mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-27 10:02:01 +00:00
Merge branch 'master' of github.com:ClickHouse/ClickHouse into date_diff
This commit is contained in:
commit
eb37b0f5b9
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -284,3 +284,6 @@
|
|||||||
[submodule "contrib/llvm-project"]
|
[submodule "contrib/llvm-project"]
|
||||||
path = contrib/llvm-project
|
path = contrib/llvm-project
|
||||||
url = https://github.com/ClickHouse/llvm-project.git
|
url = https://github.com/ClickHouse/llvm-project.git
|
||||||
|
[submodule "contrib/corrosion"]
|
||||||
|
path = contrib/corrosion
|
||||||
|
url = https://github.com/corrosion-rs/corrosion.git
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
project(ClickHouse LANGUAGES C CXX ASM)
|
project(ClickHouse LANGUAGES C CXX ASM)
|
||||||
|
|
||||||
@ -557,9 +557,9 @@ macro (clickhouse_add_executable target)
|
|||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# With cross-compiling, all targets are built for the target platform which usually different from the host
|
# With cross-compiling, all targets are built for the target platform which usually different from the host
|
||||||
# platform. This is problematic if a build artifact X (e.g. a file or an executable) is generated by running
|
# platform. This is problematic if a build artifact X (e.g. a file or an executable) is generated by running
|
||||||
# another executable Y previously produced in the build. This is solved by compiling and running Y for/on
|
# another executable Y previously produced in the build. This is solved by compiling and running Y for/on
|
||||||
# the host platform. Add target to the list:
|
# the host platform. Add target to the list:
|
||||||
# add_native_target(<target> ...)
|
# add_native_target(<target> ...)
|
||||||
set_property (GLOBAL PROPERTY NATIVE_BUILD_TARGETS)
|
set_property (GLOBAL PROPERTY NATIVE_BUILD_TARGETS)
|
||||||
@ -574,6 +574,10 @@ include_directories(${ConfigIncludePath})
|
|||||||
include (cmake/warnings.cmake)
|
include (cmake/warnings.cmake)
|
||||||
include (cmake/print_flags.cmake)
|
include (cmake/print_flags.cmake)
|
||||||
|
|
||||||
|
if (ENABLE_RUST)
|
||||||
|
add_subdirectory (rust)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory (base)
|
add_subdirectory (base)
|
||||||
add_subdirectory (src)
|
add_subdirectory (src)
|
||||||
add_subdirectory (programs)
|
add_subdirectory (programs)
|
||||||
@ -584,7 +588,7 @@ include (cmake/sanitize_target_link_libraries.cmake)
|
|||||||
|
|
||||||
# Build native targets if necessary
|
# Build native targets if necessary
|
||||||
get_property(NATIVE_BUILD_TARGETS GLOBAL PROPERTY NATIVE_BUILD_TARGETS)
|
get_property(NATIVE_BUILD_TARGETS GLOBAL PROPERTY NATIVE_BUILD_TARGETS)
|
||||||
if (NATIVE_BUILD_TARGETS
|
if (NATIVE_BUILD_TARGETS
|
||||||
AND NOT(
|
AND NOT(
|
||||||
CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME
|
CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME
|
||||||
AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR
|
AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR
|
||||||
|
@ -5,6 +5,7 @@ ClickHouse® is an open-source column-oriented database management system that a
|
|||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
* [Official website](https://clickhouse.com/) has a quick high-level overview of ClickHouse on the main page.
|
* [Official website](https://clickhouse.com/) has a quick high-level overview of ClickHouse on the main page.
|
||||||
|
* [ClickHouse Cloud](https://clickhouse.com/cloud) ClickHouse as a service, built by the creators and maintainers.
|
||||||
* [Tutorial](https://clickhouse.com/docs/en/getting_started/tutorial/) shows how to set up and query a small ClickHouse cluster.
|
* [Tutorial](https://clickhouse.com/docs/en/getting_started/tutorial/) shows how to set up and query a small ClickHouse cluster.
|
||||||
* [Documentation](https://clickhouse.com/docs/en/) provides more in-depth information.
|
* [Documentation](https://clickhouse.com/docs/en/) provides more in-depth information.
|
||||||
* [YouTube channel](https://www.youtube.com/c/ClickHouseDB) has a lot of content about ClickHouse in video format.
|
* [YouTube channel](https://www.youtube.com/c/ClickHouseDB) has a lot of content about ClickHouse in video format.
|
||||||
|
@ -176,6 +176,249 @@ void __explicit_bzero_chk(void * buf, size_t len, size_t unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
ssize_t copy_file_range(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, unsigned flags)
|
||||||
|
{
|
||||||
|
return syscall(SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long splice(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, unsigned flags)
|
||||||
|
{
|
||||||
|
return syscall(SYS_splice, fd_in, off_in, fd_out, off_out, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define _BSD_SOURCE
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if !defined(__aarch64__)
|
||||||
|
struct statx {
|
||||||
|
uint32_t stx_mask;
|
||||||
|
uint32_t stx_blksize;
|
||||||
|
uint64_t stx_attributes;
|
||||||
|
uint32_t stx_nlink;
|
||||||
|
uint32_t stx_uid;
|
||||||
|
uint32_t stx_gid;
|
||||||
|
uint16_t stx_mode;
|
||||||
|
uint16_t pad1;
|
||||||
|
uint64_t stx_ino;
|
||||||
|
uint64_t stx_size;
|
||||||
|
uint64_t stx_blocks;
|
||||||
|
uint64_t stx_attributes_mask;
|
||||||
|
struct {
|
||||||
|
int64_t tv_sec;
|
||||||
|
uint32_t tv_nsec;
|
||||||
|
int32_t pad;
|
||||||
|
} stx_atime, stx_btime, stx_ctime, stx_mtime;
|
||||||
|
uint32_t stx_rdev_major;
|
||||||
|
uint32_t stx_rdev_minor;
|
||||||
|
uint32_t stx_dev_major;
|
||||||
|
uint32_t stx_dev_minor;
|
||||||
|
uint64_t spare[14];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int statx(int fd, const char *restrict path, int flag,
|
||||||
|
unsigned int mask, struct statx *restrict statxbuf)
|
||||||
|
{
|
||||||
|
return syscall(SYS_statx, fd, path, flag, mask, statxbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
ssize_t getrandom(void *buf, size_t buflen, unsigned flags)
|
||||||
|
{
|
||||||
|
/// There was cancellable syscall (syscall_cp), but I don't care too.
|
||||||
|
return syscall(SYS_getrandom, buf, buflen, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define ALIGN (sizeof(size_t))
|
||||||
|
#define ONES ((size_t)-1/UCHAR_MAX)
|
||||||
|
#define HIGHS (ONES * (UCHAR_MAX/2+1))
|
||||||
|
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
|
||||||
|
|
||||||
|
char *__strchrnul(const char *s, int c)
|
||||||
|
{
|
||||||
|
c = (unsigned char)c;
|
||||||
|
if (!c) return (char *)s + strlen(s);
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
typedef size_t __attribute__((__may_alias__)) word;
|
||||||
|
const word *w;
|
||||||
|
for (; (uintptr_t)s % ALIGN; s++)
|
||||||
|
if (!*s || *(unsigned char *)s == c) return (char *)s;
|
||||||
|
size_t k = ONES * c;
|
||||||
|
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
|
||||||
|
s = (void *)w;
|
||||||
|
#endif
|
||||||
|
for (; *s && *(unsigned char *)s != c; s++);
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __execvpe(const char *file, char *const argv[], char *const envp[])
|
||||||
|
{
|
||||||
|
const char *p, *z, *path = getenv("PATH");
|
||||||
|
size_t l, k;
|
||||||
|
int seen_eacces = 0;
|
||||||
|
|
||||||
|
errno = ENOENT;
|
||||||
|
if (!*file) return -1;
|
||||||
|
|
||||||
|
if (strchr(file, '/'))
|
||||||
|
return execve(file, argv, envp);
|
||||||
|
|
||||||
|
if (!path) path = "/usr/local/bin:/bin:/usr/bin";
|
||||||
|
k = strnlen(file, NAME_MAX+1);
|
||||||
|
if (k > NAME_MAX) {
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
l = strnlen(path, PATH_MAX-1)+1;
|
||||||
|
|
||||||
|
for(p=path; ; p=z) {
|
||||||
|
char b[l+k+1];
|
||||||
|
z = __strchrnul(p, ':');
|
||||||
|
if (z-p >= l) {
|
||||||
|
if (!*z++) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy(b, p, z-p);
|
||||||
|
b[z-p] = '/';
|
||||||
|
memcpy(b+(z-p)+(z>p), file, k+1);
|
||||||
|
execve(b, argv, envp);
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
seen_eacces = 1;
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!*z++) break;
|
||||||
|
}
|
||||||
|
if (seen_eacces) errno = EACCES;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "spawn.h"
|
||||||
|
|
||||||
|
int posix_spawnp(pid_t *restrict res, const char *restrict file,
|
||||||
|
const posix_spawn_file_actions_t *fa,
|
||||||
|
const posix_spawnattr_t *restrict attr,
|
||||||
|
char *const argv[restrict], char *const envp[restrict])
|
||||||
|
{
|
||||||
|
posix_spawnattr_t spawnp_attr = { 0 };
|
||||||
|
if (attr) spawnp_attr = *attr;
|
||||||
|
spawnp_attr.__fn = (void *)__execvpe;
|
||||||
|
return posix_spawn(res, file, fa, &spawnp_attr, argv, envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FDOP_CLOSE 1
|
||||||
|
#define FDOP_DUP2 2
|
||||||
|
#define FDOP_OPEN 3
|
||||||
|
#define FDOP_CHDIR 4
|
||||||
|
#define FDOP_FCHDIR 5
|
||||||
|
|
||||||
|
#define ENOMEM 12
|
||||||
|
#define EBADF 9
|
||||||
|
|
||||||
|
struct fdop {
|
||||||
|
struct fdop *next, *prev;
|
||||||
|
int cmd, fd, srcfd, oflag;
|
||||||
|
mode_t mode;
|
||||||
|
char path[];
|
||||||
|
};
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *fa) {
|
||||||
|
fa->__actions = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *restrict fa, const char *restrict path) {
|
||||||
|
struct fdop *op = malloc(sizeof *op + strlen(path) + 1);
|
||||||
|
if (!op) return ENOMEM;
|
||||||
|
op->cmd = FDOP_CHDIR;
|
||||||
|
op->fd = -1;
|
||||||
|
strcpy(op->path, path);
|
||||||
|
if ((op->next = fa->__actions)) op->next->prev = op;
|
||||||
|
op->prev = 0;
|
||||||
|
fa->__actions = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, int fd) {
|
||||||
|
if (fd < 0) return EBADF;
|
||||||
|
struct fdop *op = malloc(sizeof *op);
|
||||||
|
if (!op) return ENOMEM;
|
||||||
|
op->cmd = FDOP_CLOSE;
|
||||||
|
op->fd = fd;
|
||||||
|
if ((op->next = fa->__actions)) op->next->prev = op;
|
||||||
|
op->prev = 0;
|
||||||
|
fa->__actions = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, int srcfd, int fd) {
|
||||||
|
if (srcfd < 0 || fd < 0) return EBADF;
|
||||||
|
struct fdop *op = malloc(sizeof *op);
|
||||||
|
if (!op) return ENOMEM;
|
||||||
|
op->cmd = FDOP_DUP2;
|
||||||
|
op->srcfd = srcfd;
|
||||||
|
op->fd = fd;
|
||||||
|
if ((op->next = fa->__actions)) op->next->prev = op;
|
||||||
|
op->prev = 0;
|
||||||
|
fa->__actions = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *fa, int fd) {
|
||||||
|
if (fd < 0) return EBADF;
|
||||||
|
struct fdop *op = malloc(sizeof *op);
|
||||||
|
if (!op) return ENOMEM;
|
||||||
|
op->cmd = FDOP_FCHDIR;
|
||||||
|
op->fd = fd;
|
||||||
|
if ((op->next = fa->__actions)) op->next->prev = op;
|
||||||
|
op->prev = 0;
|
||||||
|
fa->__actions = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict fa, int fd, const char *restrict path, int flags, mode_t mode) {
|
||||||
|
if (fd < 0) return EBADF;
|
||||||
|
struct fdop *op = malloc(sizeof *op + strlen(path) + 1);
|
||||||
|
if (!op) return ENOMEM;
|
||||||
|
op->cmd = FDOP_OPEN;
|
||||||
|
op->fd = fd;
|
||||||
|
op->oflag = flags;
|
||||||
|
op->mode = mode;
|
||||||
|
strcpy(op->path, path);
|
||||||
|
if ((op->next = fa->__actions)) op->next->prev = op;
|
||||||
|
op->prev = 0;
|
||||||
|
fa->__actions = op;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) {
|
||||||
|
struct fdop *op = fa->__actions, *next;
|
||||||
|
while (op) {
|
||||||
|
next = op->next;
|
||||||
|
free(op);
|
||||||
|
op = next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (__cplusplus)
|
#if defined (__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
32
base/glibc-compatibility/spawn.h
Normal file
32
base/glibc-compatibility/spawn.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef _SPAWN_H
|
||||||
|
#define _SPAWN_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <features.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int __flags;
|
||||||
|
pid_t __pgrp;
|
||||||
|
sigset_t __def, __mask;
|
||||||
|
int __prio, __pol;
|
||||||
|
void *__fn;
|
||||||
|
char __pad[64-sizeof(void *)];
|
||||||
|
} posix_spawnattr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int __pad0[2];
|
||||||
|
void *__actions;
|
||||||
|
int __pad[16];
|
||||||
|
} posix_spawn_file_actions_t;
|
||||||
|
|
||||||
|
int posix_spawn(pid_t *__restrict, const char *__restrict, const posix_spawn_file_actions_t *,
|
||||||
|
const posix_spawnattr_t *__restrict, char *const *__restrict, char *const *__restrict);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
2
contrib/AMQP-CPP
vendored
2
contrib/AMQP-CPP
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 1a6c51f4ac51ac56610fa95081bd2f349911375a
|
Subproject commit 818c2d8ad96a08a5d20fece7d1e1e8855a2b0860
|
2
contrib/CMakeLists.txt
vendored
2
contrib/CMakeLists.txt
vendored
@ -92,6 +92,8 @@ add_contrib (openldap-cmake openldap)
|
|||||||
add_contrib (grpc-cmake grpc)
|
add_contrib (grpc-cmake grpc)
|
||||||
add_contrib (msgpack-c-cmake msgpack-c)
|
add_contrib (msgpack-c-cmake msgpack-c)
|
||||||
|
|
||||||
|
add_contrib (corrosion-cmake corrosion)
|
||||||
|
|
||||||
if (ENABLE_FUZZING)
|
if (ENABLE_FUZZING)
|
||||||
add_contrib (libprotobuf-mutator-cmake libprotobuf-mutator)
|
add_contrib (libprotobuf-mutator-cmake libprotobuf-mutator)
|
||||||
endif()
|
endif()
|
||||||
|
@ -4,6 +4,11 @@ if (NOT ENABLE_AMQPCPP)
|
|||||||
message(STATUS "Not using AMQP-CPP")
|
message(STATUS "Not using AMQP-CPP")
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
if (OS_FREEBSD)
|
||||||
|
message(STATUS "Not using AMQP-CPP because libuv is disabled")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# can be removed once libuv build on MacOS with GCC is possible
|
# can be removed once libuv build on MacOS with GCC is possible
|
||||||
if (NOT TARGET ch_contrib::uv)
|
if (NOT TARGET ch_contrib::uv)
|
||||||
|
1
contrib/corrosion
vendored
Submodule
1
contrib/corrosion
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d9dfdefaa3d9ec4ba1245c7070727359c65c7869
|
46
contrib/corrosion-cmake/CMakeLists.txt
Normal file
46
contrib/corrosion-cmake/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
if (NOT ENABLE_LIBRARIES)
|
||||||
|
set(DEFAULT_ENABLE_RUST FALSE)
|
||||||
|
elseif((CMAKE_TOOLCHAIN_FILE MATCHES "darwin") AND (CMAKE_TOOLCHAIN_FILE MATCHES "aarch64"))
|
||||||
|
message(STATUS "Rust is not available on aarch64-apple-darwin")
|
||||||
|
set(DEFAULT_ENABLE_RUST FALSE)
|
||||||
|
else()
|
||||||
|
list (APPEND CMAKE_MODULE_PATH "${ClickHouse_SOURCE_DIR}/contrib/corrosion/cmake")
|
||||||
|
find_package(Rust)
|
||||||
|
set(DEFAULT_ENABLE_RUST ${Rust_FOUND})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(ENABLE_RUST "Enable rust" ${DEFAULT_ENABLE_RUST})
|
||||||
|
|
||||||
|
message(STATUS ${ENABLE_RUST})
|
||||||
|
|
||||||
|
if(NOT ENABLE_RUST)
|
||||||
|
message(STATUS "Not using rust")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Checking Rust toolchain for current target")
|
||||||
|
|
||||||
|
if(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-x86_64")
|
||||||
|
set(Rust_CARGO_TARGET "x86_64-unknown-linux-gnu")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_TOOLCHAIN_FILE MATCHES "linux/toolchain-aarch64")
|
||||||
|
set(Rust_CARGO_TARGET "aarch64-unknown-linux-gnu")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if((CMAKE_TOOLCHAIN_FILE MATCHES "darwin") AND (CMAKE_TOOLCHAIN_FILE MATCHES "x86_64"))
|
||||||
|
set(Rust_CARGO_TARGET "x86_64-apple-darwin")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if((CMAKE_TOOLCHAIN_FILE MATCHES "freebsd") AND (CMAKE_TOOLCHAIN_FILE MATCHES "x86_64"))
|
||||||
|
set(Rust_CARGO_TARGET "x86_64-unknown-freebsd")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_TOOLCHAIN_FILE MATCHES "ppc64le")
|
||||||
|
set(Rust_CARGO_TARGET "powerpc64le-unknown-linux-gnu")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Switched Rust target to ${Rust_CARGO_TARGET}")
|
||||||
|
|
||||||
|
# Define function corrosion_import_crate()
|
||||||
|
include ("${ClickHouse_SOURCE_DIR}/contrib/corrosion/cmake/Corrosion.cmake")
|
2
contrib/llvm-project
vendored
2
contrib/llvm-project
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 6ca2b5b3927226f6bcf6c656f502ff5d012ad9b6
|
Subproject commit 328e4602120ddd6b2c1fb91bf2d50bd7bc249711
|
@ -14,7 +14,7 @@ endif()
|
|||||||
# TODO: Enable shared library build
|
# TODO: Enable shared library build
|
||||||
# TODO: Enable compilation on AArch64
|
# TODO: Enable compilation on AArch64
|
||||||
|
|
||||||
set (LLVM_VERSION "13.0.0bundled")
|
set (LLVM_VERSION "14.0.0bundled")
|
||||||
set (LLVM_INCLUDE_DIRS
|
set (LLVM_INCLUDE_DIRS
|
||||||
"${ClickHouse_SOURCE_DIR}/contrib/llvm-project/llvm/include"
|
"${ClickHouse_SOURCE_DIR}/contrib/llvm-project/llvm/include"
|
||||||
"${ClickHouse_BINARY_DIR}/contrib/llvm-project/llvm/include"
|
"${ClickHouse_BINARY_DIR}/contrib/llvm-project/llvm/include"
|
||||||
|
@ -3,6 +3,33 @@
|
|||||||
ARG FROM_TAG=latest
|
ARG FROM_TAG=latest
|
||||||
FROM clickhouse/test-util:$FROM_TAG
|
FROM clickhouse/test-util:$FROM_TAG
|
||||||
|
|
||||||
|
# Rust toolchain and libraries
|
||||||
|
ENV RUSTUP_HOME=/rust/rustup
|
||||||
|
ENV CARGO_HOME=/rust/cargo
|
||||||
|
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
|
||||||
|
RUN chmod 777 -R /rust
|
||||||
|
ENV PATH="/rust/cargo/env:${PATH}"
|
||||||
|
ENV PATH="/rust/cargo/bin:${PATH}"
|
||||||
|
RUN rustup target add aarch64-unknown-linux-gnu && \
|
||||||
|
rustup target add x86_64-apple-darwin && \
|
||||||
|
rustup target add x86_64-unknown-freebsd && \
|
||||||
|
rustup target add aarch64-apple-darwin && \
|
||||||
|
rustup target add powerpc64le-unknown-linux-gnu
|
||||||
|
RUN apt-get install \
|
||||||
|
gcc-aarch64-linux-gnu \
|
||||||
|
build-essential \
|
||||||
|
libc6 \
|
||||||
|
libc6-dev \
|
||||||
|
libc6-dev-arm64-cross \
|
||||||
|
--yes
|
||||||
|
|
||||||
|
# Install CMake 3.20+ for Rust compilation
|
||||||
|
# Used https://askubuntu.com/a/1157132 as reference
|
||||||
|
RUN apt purge cmake --yes
|
||||||
|
RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
|
||||||
|
RUN apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
|
||||||
|
RUN apt update && apt install cmake --yes
|
||||||
|
|
||||||
ENV CC=clang-${LLVM_VERSION}
|
ENV CC=clang-${LLVM_VERSION}
|
||||||
ENV CXX=clang++-${LLVM_VERSION}
|
ENV CXX=clang++-${LLVM_VERSION}
|
||||||
|
|
||||||
|
@ -19,6 +19,12 @@ RUN apt-get update \
|
|||||||
pv \
|
pv \
|
||||||
--yes --no-install-recommends
|
--yes --no-install-recommends
|
||||||
|
|
||||||
|
# Install CMake 3.20+ for Rust compilation
|
||||||
|
RUN apt purge cmake --yes
|
||||||
|
RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
|
||||||
|
RUN apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
|
||||||
|
RUN apt update && apt install cmake --yes
|
||||||
|
|
||||||
RUN pip3 install numpy scipy pandas Jinja2
|
RUN pip3 install numpy scipy pandas Jinja2
|
||||||
|
|
||||||
ARG odbc_driver_url="https://github.com/ClickHouse/clickhouse-odbc/releases/download/v1.1.4.20200302/clickhouse-odbc-1.1.4-Linux.tar.gz"
|
ARG odbc_driver_url="https://github.com/ClickHouse/clickhouse-odbc/releases/download/v1.1.4.20200302/clickhouse-odbc-1.1.4-Linux.tar.gz"
|
||||||
|
@ -157,7 +157,6 @@ function run_cmake
|
|||||||
"-DUSE_UNWIND=1"
|
"-DUSE_UNWIND=1"
|
||||||
"-DENABLE_NURAFT=1"
|
"-DENABLE_NURAFT=1"
|
||||||
"-DENABLE_JEMALLOC=1"
|
"-DENABLE_JEMALLOC=1"
|
||||||
"-DENABLE_REPLXX=1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
export CCACHE_DIR="$FASTTEST_WORKSPACE/ccache"
|
export CCACHE_DIR="$FASTTEST_WORKSPACE/ccache"
|
||||||
|
6
docker/test/fuzzer/allow-nullable-key.xml
Normal file
6
docker/test/fuzzer/allow-nullable-key.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<clickhouse>
|
||||||
|
<!-- Allow nullable key to avoid errors while fuzzing definitions of tables -->
|
||||||
|
<merge_tree>
|
||||||
|
<allow_nullable_key>1</allow_nullable_key>
|
||||||
|
</merge_tree>
|
||||||
|
</clickhouse>
|
@ -94,6 +94,7 @@ function configure
|
|||||||
# TODO figure out which ones are needed
|
# TODO figure out which ones are needed
|
||||||
cp -av --dereference "$repo_dir"/tests/config/config.d/listen.xml db/config.d
|
cp -av --dereference "$repo_dir"/tests/config/config.d/listen.xml db/config.d
|
||||||
cp -av --dereference "$script_dir"/query-fuzzer-tweaks-users.xml db/users.d
|
cp -av --dereference "$script_dir"/query-fuzzer-tweaks-users.xml db/users.d
|
||||||
|
cp -av --dereference "$script_dir"/allow-nullable-key.xml db/config.d
|
||||||
|
|
||||||
cat > db/config.d/core.xml <<EOL
|
cat > db/config.d/core.xml <<EOL
|
||||||
<clickhouse>
|
<clickhouse>
|
||||||
@ -240,6 +241,7 @@ quit
|
|||||||
--receive_data_timeout_ms=10000 \
|
--receive_data_timeout_ms=10000 \
|
||||||
--stacktrace \
|
--stacktrace \
|
||||||
--query-fuzzer-runs=1000 \
|
--query-fuzzer-runs=1000 \
|
||||||
|
--create-query-fuzzer-runs=50 \
|
||||||
--queries-file $(ls -1 ch/tests/queries/0_stateless/*.sql | sort -R) \
|
--queries-file $(ls -1 ch/tests/queries/0_stateless/*.sql | sort -R) \
|
||||||
$NEW_TESTS_OPT \
|
$NEW_TESTS_OPT \
|
||||||
> >(tail -n 100000 > fuzzer.log) \
|
> >(tail -n 100000 > fuzzer.log) \
|
||||||
|
@ -35,6 +35,8 @@ RUN apt-get update \
|
|||||||
tzdata \
|
tzdata \
|
||||||
vim \
|
vim \
|
||||||
wget \
|
wget \
|
||||||
|
rustc \
|
||||||
|
cargo \
|
||||||
&& pip3 --no-cache-dir install 'clickhouse-driver==0.2.1' scipy \
|
&& pip3 --no-cache-dir install 'clickhouse-driver==0.2.1' scipy \
|
||||||
&& apt-get purge --yes python3-dev g++ \
|
&& apt-get purge --yes python3-dev g++ \
|
||||||
&& apt-get autoremove --yes \
|
&& apt-get autoremove --yes \
|
||||||
|
@ -35,12 +35,13 @@ RUN apt-get update -y \
|
|||||||
tree \
|
tree \
|
||||||
unixodbc \
|
unixodbc \
|
||||||
wget \
|
wget \
|
||||||
|
rustc \
|
||||||
|
cargo \
|
||||||
zstd \
|
zstd \
|
||||||
file \
|
file \
|
||||||
pv \
|
pv \
|
||||||
&& apt-get clean
|
&& apt-get clean
|
||||||
|
|
||||||
|
|
||||||
RUN pip3 install numpy scipy pandas Jinja2
|
RUN pip3 install numpy scipy pandas Jinja2
|
||||||
|
|
||||||
RUN mkdir -p /tmp/clickhouse-odbc-tmp \
|
RUN mkdir -p /tmp/clickhouse-odbc-tmp \
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
position: 10
|
position: 1
|
||||||
label: 'Example Datasets'
|
label: 'Example Datasets'
|
||||||
collapsible: true
|
collapsible: true
|
||||||
collapsed: true
|
collapsed: true
|
||||||
link:
|
link:
|
||||||
type: generated-index
|
type: doc
|
||||||
title: Example Datasets
|
id: en/getting-started/example-datasets/
|
||||||
slug: /en/getting-started/example-datasets
|
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
---
|
---
|
||||||
slug: /en/getting-started/example-datasets/cell-towers
|
slug: /en/getting-started/example-datasets/cell-towers
|
||||||
sidebar_label: Cell Towers
|
sidebar_label: Cell Towers
|
||||||
|
sidebar_position: 3
|
||||||
title: "Cell Towers"
|
title: "Cell Towers"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
import Tabs from '@theme/Tabs';
|
||||||
|
import TabItem from '@theme/TabItem';
|
||||||
|
import CodeBlock from '@theme/CodeBlock';
|
||||||
|
import ActionsMenu from '@site/docs/en/_snippets/_service_actions_menu.md';
|
||||||
|
import SQLConsoleDetail from '@site/docs/en/_snippets/_launch_sql_console.md';
|
||||||
|
|
||||||
This dataset is from [OpenCellid](https://www.opencellid.org/) - The world's largest Open Database of Cell Towers.
|
This dataset is from [OpenCellid](https://www.opencellid.org/) - The world's largest Open Database of Cell Towers.
|
||||||
|
|
||||||
As of 2021, it contains more than 40 million records about cell towers (GSM, LTE, UMTS, etc.) around the world with their geographical coordinates and metadata (country code, network, etc).
|
As of 2021, it contains more than 40 million records about cell towers (GSM, LTE, UMTS, etc.) around the world with their geographical coordinates and metadata (country code, network, etc).
|
||||||
@ -13,6 +20,26 @@ OpenCelliD Project is licensed under a Creative Commons Attribution-ShareAlike 4
|
|||||||
|
|
||||||
## Get the Dataset {#get-the-dataset}
|
## Get the Dataset {#get-the-dataset}
|
||||||
|
|
||||||
|
<Tabs groupId="deployMethod">
|
||||||
|
<TabItem value="serverless" label="ClickHouse Cloud" default>
|
||||||
|
|
||||||
|
ClickHouse Cloud provides an easy-button for uploading this dataset from S3. Log in to your ClickHouse Cloud organization, or create a free trial at [ClickHouse.cloud](https://clickhouse.cloud).
|
||||||
|
<ActionsMenu menu="Load Data" />
|
||||||
|
|
||||||
|
Choose the **Cell Towers** dataset from the **Sample data** tab, and **Load data**:
|
||||||
|
|
||||||
|
![Load cell towers dataset](@site/docs/en/_snippets/images/cloud-load-data-sample.png)
|
||||||
|
|
||||||
|
Examine the schema of the cell_towers table:
|
||||||
|
```sql
|
||||||
|
DESCRIBE TABLE cell_towers
|
||||||
|
```
|
||||||
|
|
||||||
|
<SQLConsoleDetail />
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="selfmanaged" label="Self-managed">
|
||||||
|
|
||||||
1. Download the snapshot of the dataset from February 2021: [cell_towers.csv.xz](https://datasets.clickhouse.com/cell_towers.csv.xz) (729 MB).
|
1. Download the snapshot of the dataset from February 2021: [cell_towers.csv.xz](https://datasets.clickhouse.com/cell_towers.csv.xz) (729 MB).
|
||||||
|
|
||||||
2. Validate the integrity (optional step):
|
2. Validate the integrity (optional step):
|
||||||
@ -56,7 +83,10 @@ ENGINE = MergeTree ORDER BY (radio, mcc, net, created);
|
|||||||
clickhouse-client --query "INSERT INTO cell_towers FORMAT CSVWithNames" < cell_towers.csv
|
clickhouse-client --query "INSERT INTO cell_towers FORMAT CSVWithNames" < cell_towers.csv
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples {#examples}
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Example queries {#examples}
|
||||||
|
|
||||||
1. A number of cell towers by type:
|
1. A number of cell towers by type:
|
||||||
|
|
||||||
@ -101,18 +131,31 @@ So, the top countries are: the USA, Germany, and Russia.
|
|||||||
|
|
||||||
You may want to create an [External Dictionary](../../sql-reference/dictionaries/external-dictionaries/external-dicts.md) in ClickHouse to decode these values.
|
You may want to create an [External Dictionary](../../sql-reference/dictionaries/external-dictionaries/external-dicts.md) in ClickHouse to decode these values.
|
||||||
|
|
||||||
|
## Use case: Incorporate geo data {#use-case}
|
||||||
## Use case {#use-case}
|
|
||||||
|
|
||||||
Using `pointInPolygon` function.
|
Using `pointInPolygon` function.
|
||||||
|
|
||||||
1. Create a table where we will store polygons:
|
1. Create a table where we will store polygons:
|
||||||
|
|
||||||
|
<Tabs groupId="deployMethod">
|
||||||
|
<TabItem value="serverless" label="ClickHouse Cloud" default>
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE moscow (polygon Array(Tuple(Float64, Float64)))
|
||||||
|
ORDER BY polygon;
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="selfmanaged" label="Self-managed">
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TEMPORARY TABLE
|
CREATE TEMPORARY TABLE
|
||||||
moscow (polygon Array(Tuple(Float64, Float64)));
|
moscow (polygon Array(Tuple(Float64, Float64)));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
2. This is a rough shape of Moscow (without "new Moscow"):
|
2. This is a rough shape of Moscow (without "new Moscow"):
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
File diff suppressed because one or more lines are too long
@ -13,16 +13,6 @@ Description of the fields: https://www.gov.uk/guidance/about-the-price-paid-data
|
|||||||
|
|
||||||
Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.
|
Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.
|
||||||
|
|
||||||
## Download the Dataset {#download-dataset}
|
|
||||||
|
|
||||||
Run the command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv
|
|
||||||
```
|
|
||||||
|
|
||||||
Download will take about 2 minutes with good internet connection.
|
|
||||||
|
|
||||||
## Create the Table {#create-table}
|
## Create the Table {#create-table}
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@ -41,31 +31,49 @@ CREATE TABLE uk_price_paid
|
|||||||
locality LowCardinality(String),
|
locality LowCardinality(String),
|
||||||
town LowCardinality(String),
|
town LowCardinality(String),
|
||||||
district LowCardinality(String),
|
district LowCardinality(String),
|
||||||
county LowCardinality(String),
|
county LowCardinality(String)
|
||||||
category UInt8
|
)
|
||||||
) ENGINE = MergeTree ORDER BY (postcode1, postcode2, addr1, addr2);
|
ENGINE = MergeTree
|
||||||
|
ORDER BY (postcode1, postcode2, addr1, addr2);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Preprocess and Import Data {#preprocess-import-data}
|
## Preprocess and Insert the Data {#preprocess-import-data}
|
||||||
|
|
||||||
We will use `clickhouse-local` tool for data preprocessing and `clickhouse-client` to upload it.
|
We will use the `url` function to stream the data into ClickHouse. We need to preprocess some of the incoming data first, which includes:
|
||||||
|
- splitting the `postcode` to two different columns - `postcode1` and `postcode2`, which is better for storage and queries
|
||||||
|
- converting the `time` field to date as it only contains 00:00 time
|
||||||
|
- ignoring the [UUid](../../sql-reference/data-types/uuid.md) field because we don't need it for analysis
|
||||||
|
- transforming `type` and `duration` to more readable `Enum` fields using the [transform](../../sql-reference/functions/other-functions.md#transform) function
|
||||||
|
- transforming the `is_new` field from a single-character string (`Y`/`N`) to a [UInt8](../../sql-reference/data-types/int-uint.md#uint8-uint16-uint32-uint64-uint256-int8-int16-int32-int64-int128-int256) field with 0 or 1
|
||||||
|
- drop the last two columns since they all have the same value (which is 0)
|
||||||
|
|
||||||
In this example, we define the structure of source data from the CSV file and specify a query to preprocess the data with `clickhouse-local`.
|
The `url` function streams the data from the web server into your ClickHouse table. The following command inserts 5 million rows into the `uk_price_paid` table:
|
||||||
|
|
||||||
The preprocessing is:
|
```sql
|
||||||
- splitting the postcode to two different columns `postcode1` and `postcode2` that is better for storage and queries;
|
INSERT INTO uk_price_paid
|
||||||
- coverting the `time` field to date as it only contains 00:00 time;
|
WITH
|
||||||
- ignoring the [UUid](../../sql-reference/data-types/uuid.md) field because we don't need it for analysis;
|
splitByChar(' ', postcode) AS p
|
||||||
- transforming `type` and `duration` to more readable Enum fields with function [transform](../../sql-reference/functions/other-functions.md#transform);
|
SELECT
|
||||||
- transforming `is_new` and `category` fields from single-character string (`Y`/`N` and `A`/`B`) to [UInt8](../../sql-reference/data-types/int-uint.md#uint8-uint16-uint32-uint64-uint256-int8-int16-int32-int64-int128-int256) field with 0 and 1.
|
toUInt32(price_string) AS price,
|
||||||
|
parseDateTimeBestEffortUS(time) AS date,
|
||||||
Preprocessed data is piped directly to `clickhouse-client` to be inserted into ClickHouse table in streaming fashion.
|
p[1] AS postcode1,
|
||||||
|
p[2] AS postcode2,
|
||||||
```bash
|
transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
|
||||||
clickhouse-local --input-format CSV --structure '
|
b = 'Y' AS is_new,
|
||||||
uuid String,
|
transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
|
||||||
price UInt32,
|
addr1,
|
||||||
time DateTime,
|
addr2,
|
||||||
|
street,
|
||||||
|
locality,
|
||||||
|
town,
|
||||||
|
district,
|
||||||
|
county
|
||||||
|
FROM url(
|
||||||
|
'http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
|
||||||
|
'CSV',
|
||||||
|
'uuid_string String,
|
||||||
|
price_string String,
|
||||||
|
time String,
|
||||||
postcode String,
|
postcode String,
|
||||||
a String,
|
a String,
|
||||||
b String,
|
b String,
|
||||||
@ -78,154 +86,136 @@ clickhouse-local --input-format CSV --structure '
|
|||||||
district String,
|
district String,
|
||||||
county String,
|
county String,
|
||||||
d String,
|
d String,
|
||||||
e String
|
e String'
|
||||||
' --query "
|
) SETTINGS max_http_get_redirects=10;
|
||||||
WITH splitByChar(' ', postcode) AS p
|
|
||||||
SELECT
|
|
||||||
price,
|
|
||||||
toDate(time) AS date,
|
|
||||||
p[1] AS postcode1,
|
|
||||||
p[2] AS postcode2,
|
|
||||||
transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
|
|
||||||
b = 'Y' AS is_new,
|
|
||||||
transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
|
|
||||||
addr1,
|
|
||||||
addr2,
|
|
||||||
street,
|
|
||||||
locality,
|
|
||||||
town,
|
|
||||||
district,
|
|
||||||
county,
|
|
||||||
d = 'B' AS category
|
|
||||||
FROM table" --date_time_input_format best_effort < pp-complete.csv | clickhouse-client --query "INSERT INTO uk_price_paid FORMAT TSV"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
It will take about 40 seconds.
|
Wait for the data to insert - it will take a minute or two depending on the network speed.
|
||||||
|
|
||||||
## Validate the Data {#validate-data}
|
## Validate the Data {#validate-data}
|
||||||
|
|
||||||
Query:
|
Let's verify it worked by seeing how many rows were inserted:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT count() FROM uk_price_paid;
|
SELECT count()
|
||||||
|
FROM uk_price_paid
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
At the time this query was executed, the dataset had 27,450,499 rows. Let's see what the storage size is of the table in ClickHouse:
|
||||||
|
|
||||||
```text
|
|
||||||
┌──count()─┐
|
|
||||||
│ 26321785 │
|
|
||||||
└──────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
The size of dataset in ClickHouse is just 278 MiB, check it.
|
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT formatReadableSize(total_bytes) FROM system.tables WHERE name = 'uk_price_paid';
|
SELECT formatReadableSize(total_bytes)
|
||||||
|
FROM system.tables
|
||||||
|
WHERE name = 'uk_price_paid'
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
Notice the size of the table is just 221.43 MiB!
|
||||||
|
|
||||||
```text
|
|
||||||
┌─formatReadableSize(total_bytes)─┐
|
|
||||||
│ 278.80 MiB │
|
|
||||||
└─────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run Some Queries {#run-queries}
|
## Run Some Queries {#run-queries}
|
||||||
|
|
||||||
|
Let's run some queries to analyze the data:
|
||||||
|
|
||||||
### Query 1. Average Price Per Year {#average-price}
|
### Query 1. Average Price Per Year {#average-price}
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT toYear(date) AS year, round(avg(price)) AS price, bar(price, 0, 1000000, 80) FROM uk_price_paid GROUP BY year ORDER BY year;
|
SELECT
|
||||||
|
toYear(date) AS year,
|
||||||
|
round(avg(price)) AS price,
|
||||||
|
bar(price, 0, 1000000, 80
|
||||||
|
)
|
||||||
|
FROM uk_price_paid
|
||||||
|
GROUP BY year
|
||||||
|
ORDER BY year
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
The result looks like:
|
||||||
|
|
||||||
```text
|
```response
|
||||||
┌─year─┬──price─┬─bar(round(avg(price)), 0, 1000000, 80)─┐
|
┌─year─┬──price─┬─bar(round(avg(price)), 0, 1000000, 80)─┐
|
||||||
│ 1995 │ 67932 │ █████▍ │
|
│ 1995 │ 67934 │ █████▍ │
|
||||||
│ 1996 │ 71505 │ █████▋ │
|
│ 1996 │ 71508 │ █████▋ │
|
||||||
│ 1997 │ 78532 │ ██████▎ │
|
│ 1997 │ 78536 │ ██████▎ │
|
||||||
│ 1998 │ 85436 │ ██████▋ │
|
│ 1998 │ 85441 │ ██████▋ │
|
||||||
│ 1999 │ 96037 │ ███████▋ │
|
│ 1999 │ 96038 │ ███████▋ │
|
||||||
│ 2000 │ 107479 │ ████████▌ │
|
│ 2000 │ 107487 │ ████████▌ │
|
||||||
│ 2001 │ 118885 │ █████████▌ │
|
│ 2001 │ 118888 │ █████████▌ │
|
||||||
│ 2002 │ 137941 │ ███████████ │
|
│ 2002 │ 137948 │ ███████████ │
|
||||||
│ 2003 │ 155889 │ ████████████▍ │
|
│ 2003 │ 155893 │ ████████████▍ │
|
||||||
│ 2004 │ 178885 │ ██████████████▎ │
|
│ 2004 │ 178888 │ ██████████████▎ │
|
||||||
│ 2005 │ 189351 │ ███████████████▏ │
|
│ 2005 │ 189359 │ ███████████████▏ │
|
||||||
│ 2006 │ 203528 │ ████████████████▎ │
|
│ 2006 │ 203532 │ ████████████████▎ │
|
||||||
│ 2007 │ 219378 │ █████████████████▌ │
|
│ 2007 │ 219375 │ █████████████████▌ │
|
||||||
│ 2008 │ 217056 │ █████████████████▎ │
|
│ 2008 │ 217056 │ █████████████████▎ │
|
||||||
│ 2009 │ 213419 │ █████████████████ │
|
│ 2009 │ 213419 │ █████████████████ │
|
||||||
│ 2010 │ 236109 │ ██████████████████▊ │
|
│ 2010 │ 236110 │ ██████████████████▊ │
|
||||||
│ 2011 │ 232805 │ ██████████████████▌ │
|
│ 2011 │ 232805 │ ██████████████████▌ │
|
||||||
│ 2012 │ 238367 │ ███████████████████ │
|
│ 2012 │ 238381 │ ███████████████████ │
|
||||||
│ 2013 │ 256931 │ ████████████████████▌ │
|
│ 2013 │ 256927 │ ████████████████████▌ │
|
||||||
│ 2014 │ 279915 │ ██████████████████████▍ │
|
│ 2014 │ 280008 │ ██████████████████████▍ │
|
||||||
│ 2015 │ 297266 │ ███████████████████████▋ │
|
│ 2015 │ 297263 │ ███████████████████████▋ │
|
||||||
│ 2016 │ 313201 │ █████████████████████████ │
|
│ 2016 │ 313518 │ █████████████████████████ │
|
||||||
│ 2017 │ 346097 │ ███████████████████████████▋ │
|
│ 2017 │ 346371 │ ███████████████████████████▋ │
|
||||||
│ 2018 │ 350116 │ ████████████████████████████ │
|
│ 2018 │ 350556 │ ████████████████████████████ │
|
||||||
│ 2019 │ 351013 │ ████████████████████████████ │
|
│ 2019 │ 352184 │ ████████████████████████████▏ │
|
||||||
│ 2020 │ 369420 │ █████████████████████████████▌ │
|
│ 2020 │ 375808 │ ██████████████████████████████ │
|
||||||
│ 2021 │ 386903 │ ██████████████████████████████▊ │
|
│ 2021 │ 381105 │ ██████████████████████████████▍ │
|
||||||
|
│ 2022 │ 362572 │ █████████████████████████████ │
|
||||||
└──────┴────────┴────────────────────────────────────────┘
|
└──────┴────────┴────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### Query 2. Average Price per Year in London {#average-price-london}
|
### Query 2. Average Price per Year in London {#average-price-london}
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT toYear(date) AS year, round(avg(price)) AS price, bar(price, 0, 2000000, 100) FROM uk_price_paid WHERE town = 'LONDON' GROUP BY year ORDER BY year;
|
SELECT
|
||||||
|
toYear(date) AS year,
|
||||||
|
round(avg(price)) AS price,
|
||||||
|
bar(price, 0, 2000000, 100
|
||||||
|
)
|
||||||
|
FROM uk_price_paid
|
||||||
|
WHERE town = 'LONDON'
|
||||||
|
GROUP BY year
|
||||||
|
ORDER BY year
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
The result looks like:
|
||||||
|
|
||||||
```text
|
```response
|
||||||
┌─year─┬───price─┬─bar(round(avg(price)), 0, 2000000, 100)───────────────┐
|
┌─year─┬───price─┬─bar(round(avg(price)), 0, 2000000, 100)───────────────┐
|
||||||
│ 1995 │ 109116 │ █████▍ │
|
│ 1995 │ 109110 │ █████▍ │
|
||||||
│ 1996 │ 118667 │ █████▊ │
|
│ 1996 │ 118659 │ █████▊ │
|
||||||
│ 1997 │ 136518 │ ██████▋ │
|
│ 1997 │ 136526 │ ██████▋ │
|
||||||
│ 1998 │ 152983 │ ███████▋ │
|
│ 1998 │ 153002 │ ███████▋ │
|
||||||
│ 1999 │ 180637 │ █████████ │
|
│ 1999 │ 180633 │ █████████ │
|
||||||
│ 2000 │ 215838 │ ██████████▋ │
|
│ 2000 │ 215849 │ ██████████▋ │
|
||||||
│ 2001 │ 232994 │ ███████████▋ │
|
│ 2001 │ 232987 │ ███████████▋ │
|
||||||
│ 2002 │ 263670 │ █████████████▏ │
|
│ 2002 │ 263668 │ █████████████▏ │
|
||||||
│ 2003 │ 278394 │ █████████████▊ │
|
│ 2003 │ 278424 │ █████████████▊ │
|
||||||
│ 2004 │ 304666 │ ███████████████▏ │
|
│ 2004 │ 304664 │ ███████████████▏ │
|
||||||
│ 2005 │ 322875 │ ████████████████▏ │
|
│ 2005 │ 322887 │ ████████████████▏ │
|
||||||
│ 2006 │ 356191 │ █████████████████▋ │
|
│ 2006 │ 356195 │ █████████████████▋ │
|
||||||
│ 2007 │ 404054 │ ████████████████████▏ │
|
│ 2007 │ 404062 │ ████████████████████▏ │
|
||||||
│ 2008 │ 420741 │ █████████████████████ │
|
│ 2008 │ 420741 │ █████████████████████ │
|
||||||
│ 2009 │ 427753 │ █████████████████████▍ │
|
│ 2009 │ 427754 │ █████████████████████▍ │
|
||||||
│ 2010 │ 480306 │ ████████████████████████ │
|
│ 2010 │ 480322 │ ████████████████████████ │
|
||||||
│ 2011 │ 496274 │ ████████████████████████▋ │
|
│ 2011 │ 496278 │ ████████████████████████▋ │
|
||||||
│ 2012 │ 519442 │ █████████████████████████▊ │
|
│ 2012 │ 519482 │ █████████████████████████▊ │
|
||||||
│ 2013 │ 616212 │ ██████████████████████████████▋ │
|
│ 2013 │ 616195 │ ██████████████████████████████▋ │
|
||||||
│ 2014 │ 724154 │ ████████████████████████████████████▏ │
|
│ 2014 │ 724121 │ ████████████████████████████████████▏ │
|
||||||
│ 2015 │ 792129 │ ███████████████████████████████████████▌ │
|
│ 2015 │ 792101 │ ███████████████████████████████████████▌ │
|
||||||
│ 2016 │ 843655 │ ██████████████████████████████████████████▏ │
|
│ 2016 │ 843589 │ ██████████████████████████████████████████▏ │
|
||||||
│ 2017 │ 982642 │ █████████████████████████████████████████████████▏ │
|
│ 2017 │ 983523 │ █████████████████████████████████████████████████▏ │
|
||||||
│ 2018 │ 1016835 │ ██████████████████████████████████████████████████▋ │
|
│ 2018 │ 1016753 │ ██████████████████████████████████████████████████▋ │
|
||||||
│ 2019 │ 1042849 │ ████████████████████████████████████████████████████▏ │
|
│ 2019 │ 1041673 │ ████████████████████████████████████████████████████ │
|
||||||
│ 2020 │ 1011889 │ ██████████████████████████████████████████████████▌ │
|
│ 2020 │ 1060027 │ █████████████████████████████████████████████████████ │
|
||||||
│ 2021 │ 960343 │ ████████████████████████████████████████████████ │
|
│ 2021 │ 958249 │ ███████████████████████████████████████████████▊ │
|
||||||
|
│ 2022 │ 902596 │ █████████████████████████████████████████████▏ │
|
||||||
└──────┴─────────┴───────────────────────────────────────────────────────┘
|
└──────┴─────────┴───────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Something happened in 2013. I don't have a clue. Maybe you have a clue what happened in 2020?
|
Something happened to home prices in 2020! But that is probably not a surprise...
|
||||||
|
|
||||||
### Query 3. The Most Expensive Neighborhoods {#most-expensive-neighborhoods}
|
### Query 3. The Most Expensive Neighborhoods {#most-expensive-neighborhoods}
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
town,
|
town,
|
||||||
@ -240,124 +230,123 @@ GROUP BY
|
|||||||
district
|
district
|
||||||
HAVING c >= 100
|
HAVING c >= 100
|
||||||
ORDER BY price DESC
|
ORDER BY price DESC
|
||||||
LIMIT 100;
|
LIMIT 100
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
The result looks like:
|
||||||
|
|
||||||
```text
|
```response
|
||||||
|
┌─town─────────────────┬─district───────────────┬─────c─┬───price─┬─bar(round(avg(price)), 0, 5000000, 100)─────────────────────────┐
|
||||||
┌─town─────────────────┬─district───────────────┬────c─┬───price─┬─bar(round(avg(price)), 0, 5000000, 100)────────────────────────────┐
|
│ LONDON │ CITY OF LONDON │ 578 │ 3149590 │ ██████████████████████████████████████████████████████████████▊ │
|
||||||
│ LONDON │ CITY OF WESTMINSTER │ 3606 │ 3280239 │ █████████████████████████████████████████████████████████████████▌ │
|
│ LONDON │ CITY OF WESTMINSTER │ 7083 │ 2903794 │ ██████████████████████████████████████████████████████████ │
|
||||||
│ LONDON │ CITY OF LONDON │ 274 │ 3160502 │ ███████████████████████████████████████████████████████████████▏ │
|
│ LONDON │ KENSINGTON AND CHELSEA │ 4986 │ 2333782 │ ██████████████████████████████████████████████▋ │
|
||||||
│ LONDON │ KENSINGTON AND CHELSEA │ 2550 │ 2308478 │ ██████████████████████████████████████████████▏ │
|
│ LEATHERHEAD │ ELMBRIDGE │ 203 │ 2071595 │ █████████████████████████████████████████▍ │
|
||||||
│ LEATHERHEAD │ ELMBRIDGE │ 114 │ 1897407 │ █████████████████████████████████████▊ │
|
│ VIRGINIA WATER │ RUNNYMEDE │ 308 │ 1939465 │ ██████████████████████████████████████▋ │
|
||||||
│ LONDON │ CAMDEN │ 3033 │ 1805404 │ ████████████████████████████████████ │
|
│ LONDON │ CAMDEN │ 5750 │ 1673687 │ █████████████████████████████████▍ │
|
||||||
│ VIRGINIA WATER │ RUNNYMEDE │ 156 │ 1753247 │ ███████████████████████████████████ │
|
│ WINDLESHAM │ SURREY HEATH │ 182 │ 1428358 │ ████████████████████████████▌ │
|
||||||
│ WINDLESHAM │ SURREY HEATH │ 108 │ 1677613 │ █████████████████████████████████▌ │
|
│ NORTHWOOD │ THREE RIVERS │ 112 │ 1404170 │ ████████████████████████████ │
|
||||||
│ THORNTON HEATH │ CROYDON │ 546 │ 1671721 │ █████████████████████████████████▍ │
|
│ BARNET │ ENFIELD │ 259 │ 1338299 │ ██████████████████████████▋ │
|
||||||
│ BARNET │ ENFIELD │ 124 │ 1505840 │ ██████████████████████████████ │
|
│ LONDON │ ISLINGTON │ 5504 │ 1275520 │ █████████████████████████▌ │
|
||||||
│ COBHAM │ ELMBRIDGE │ 387 │ 1237250 │ ████████████████████████▋ │
|
│ LONDON │ RICHMOND UPON THAMES │ 1345 │ 1261935 │ █████████████████████████▏ │
|
||||||
│ LONDON │ ISLINGTON │ 2668 │ 1236980 │ ████████████████████████▋ │
|
│ COBHAM │ ELMBRIDGE │ 727 │ 1251403 │ █████████████████████████ │
|
||||||
│ OXFORD │ SOUTH OXFORDSHIRE │ 321 │ 1220907 │ ████████████████████████▍ │
|
│ BEACONSFIELD │ BUCKINGHAMSHIRE │ 680 │ 1199970 │ ███████████████████████▊ │
|
||||||
│ LONDON │ RICHMOND UPON THAMES │ 704 │ 1215551 │ ████████████████████████▎ │
|
│ LONDON │ TOWER HAMLETS │ 10012 │ 1157827 │ ███████████████████████▏ │
|
||||||
│ LONDON │ HOUNSLOW │ 671 │ 1207493 │ ████████████████████████▏ │
|
│ LONDON │ HOUNSLOW │ 1278 │ 1144389 │ ██████████████████████▊ │
|
||||||
│ ASCOT │ WINDSOR AND MAIDENHEAD │ 407 │ 1183299 │ ███████████████████████▋ │
|
│ BURFORD │ WEST OXFORDSHIRE │ 182 │ 1139393 │ ██████████████████████▋ │
|
||||||
│ BEACONSFIELD │ BUCKINGHAMSHIRE │ 330 │ 1175615 │ ███████████████████████▌ │
|
│ RICHMOND │ RICHMOND UPON THAMES │ 1649 │ 1130076 │ ██████████████████████▌ │
|
||||||
│ RICHMOND │ RICHMOND UPON THAMES │ 874 │ 1110444 │ ██████████████████████▏ │
|
│ KINGSTON UPON THAMES │ RICHMOND UPON THAMES │ 147 │ 1126111 │ ██████████████████████▌ │
|
||||||
│ LONDON │ HAMMERSMITH AND FULHAM │ 3086 │ 1053983 │ █████████████████████ │
|
│ ASCOT │ WINDSOR AND MAIDENHEAD │ 773 │ 1106109 │ ██████████████████████ │
|
||||||
│ SURBITON │ ELMBRIDGE │ 100 │ 1011800 │ ████████████████████▏ │
|
│ LONDON │ HAMMERSMITH AND FULHAM │ 6162 │ 1056198 │ █████████████████████ │
|
||||||
│ RADLETT │ HERTSMERE │ 283 │ 1011712 │ ████████████████████▏ │
|
│ RADLETT │ HERTSMERE │ 513 │ 1045758 │ ████████████████████▊ │
|
||||||
│ SALCOMBE │ SOUTH HAMS │ 127 │ 1011624 │ ████████████████████▏ │
|
│ LEATHERHEAD │ GUILDFORD │ 354 │ 1045175 │ ████████████████████▊ │
|
||||||
│ WEYBRIDGE │ ELMBRIDGE │ 655 │ 1007265 │ ████████████████████▏ │
|
│ WEYBRIDGE │ ELMBRIDGE │ 1275 │ 1036702 │ ████████████████████▋ │
|
||||||
│ ESHER │ ELMBRIDGE │ 485 │ 986581 │ ███████████████████▋ │
|
│ FARNHAM │ EAST HAMPSHIRE │ 107 │ 1033682 │ ████████████████████▋ │
|
||||||
│ LEATHERHEAD │ GUILDFORD │ 202 │ 977320 │ ███████████████████▌ │
|
│ ESHER │ ELMBRIDGE │ 915 │ 1032753 │ ████████████████████▋ │
|
||||||
│ BURFORD │ WEST OXFORDSHIRE │ 111 │ 966893 │ ███████████████████▎ │
|
│ FARNHAM │ HART │ 102 │ 1002692 │ ████████████████████ │
|
||||||
│ BROCKENHURST │ NEW FOREST │ 129 │ 956675 │ ███████████████████▏ │
|
│ GERRARDS CROSS │ BUCKINGHAMSHIRE │ 845 │ 983639 │ ███████████████████▋ │
|
||||||
│ HINDHEAD │ WAVERLEY │ 137 │ 953753 │ ███████████████████ │
|
│ CHALFONT ST GILES │ BUCKINGHAMSHIRE │ 286 │ 973993 │ ███████████████████▍ │
|
||||||
│ GERRARDS CROSS │ BUCKINGHAMSHIRE │ 419 │ 951121 │ ███████████████████ │
|
│ SALCOMBE │ SOUTH HAMS │ 215 │ 965724 │ ███████████████████▎ │
|
||||||
│ EAST MOLESEY │ ELMBRIDGE │ 192 │ 936769 │ ██████████████████▋ │
|
│ SURBITON │ ELMBRIDGE │ 181 │ 960346 │ ███████████████████▏ │
|
||||||
│ CHALFONT ST GILES │ BUCKINGHAMSHIRE │ 146 │ 925515 │ ██████████████████▌ │
|
│ BROCKENHURST │ NEW FOREST │ 226 │ 951278 │ ███████████████████ │
|
||||||
│ LONDON │ TOWER HAMLETS │ 4388 │ 918304 │ ██████████████████▎ │
|
│ SUTTON COLDFIELD │ LICHFIELD │ 110 │ 930757 │ ██████████████████▌ │
|
||||||
│ OLNEY │ MILTON KEYNES │ 235 │ 910646 │ ██████████████████▏ │
|
│ EAST MOLESEY │ ELMBRIDGE │ 372 │ 927026 │ ██████████████████▌ │
|
||||||
│ HENLEY-ON-THAMES │ SOUTH OXFORDSHIRE │ 540 │ 902418 │ ██████████████████ │
|
│ LLANGOLLEN │ WREXHAM │ 127 │ 925681 │ ██████████████████▌ │
|
||||||
│ LONDON │ SOUTHWARK │ 3885 │ 892997 │ █████████████████▋ │
|
│ OXFORD │ SOUTH OXFORDSHIRE │ 638 │ 923830 │ ██████████████████▍ │
|
||||||
│ KINGSTON UPON THAMES │ KINGSTON UPON THAMES │ 960 │ 885969 │ █████████████████▋ │
|
│ LONDON │ MERTON │ 4383 │ 923194 │ ██████████████████▍ │
|
||||||
│ LONDON │ EALING │ 2658 │ 871755 │ █████████████████▍ │
|
│ GUILDFORD │ WAVERLEY │ 261 │ 905733 │ ██████████████████ │
|
||||||
│ CRANBROOK │ TUNBRIDGE WELLS │ 431 │ 862348 │ █████████████████▏ │
|
│ TEDDINGTON │ RICHMOND UPON THAMES │ 1147 │ 894856 │ █████████████████▊ │
|
||||||
│ LONDON │ MERTON │ 2099 │ 859118 │ █████████████████▏ │
|
│ HARPENDEN │ ST ALBANS │ 1271 │ 893079 │ █████████████████▋ │
|
||||||
│ BELVEDERE │ BEXLEY │ 346 │ 842423 │ ████████████████▋ │
|
│ HENLEY-ON-THAMES │ SOUTH OXFORDSHIRE │ 1042 │ 887557 │ █████████████████▋ │
|
||||||
│ GUILDFORD │ WAVERLEY │ 143 │ 841277 │ ████████████████▋ │
|
│ POTTERS BAR │ WELWYN HATFIELD │ 314 │ 863037 │ █████████████████▎ │
|
||||||
│ HARPENDEN │ ST ALBANS │ 657 │ 841216 │ ████████████████▋ │
|
│ LONDON │ WANDSWORTH │ 13210 │ 857318 │ █████████████████▏ │
|
||||||
│ LONDON │ HACKNEY │ 3307 │ 837090 │ ████████████████▋ │
|
│ BILLINGSHURST │ CHICHESTER │ 255 │ 856508 │ █████████████████▏ │
|
||||||
│ LONDON │ WANDSWORTH │ 6566 │ 832663 │ ████████████████▋ │
|
│ LONDON │ SOUTHWARK │ 7742 │ 843145 │ ████████████████▋ │
|
||||||
│ MAIDENHEAD │ BUCKINGHAMSHIRE │ 123 │ 824299 │ ████████████████▍ │
|
│ LONDON │ HACKNEY │ 6656 │ 839716 │ ████████████████▋ │
|
||||||
│ KINGS LANGLEY │ DACORUM │ 145 │ 821331 │ ████████████████▍ │
|
│ LUTTERWORTH │ HARBOROUGH │ 1096 │ 836546 │ ████████████████▋ │
|
||||||
│ BERKHAMSTED │ DACORUM │ 543 │ 818415 │ ████████████████▎ │
|
│ KINGSTON UPON THAMES │ KINGSTON UPON THAMES │ 1846 │ 828990 │ ████████████████▌ │
|
||||||
│ GREAT MISSENDEN │ BUCKINGHAMSHIRE │ 226 │ 802807 │ ████████████████ │
|
│ LONDON │ EALING │ 5583 │ 820135 │ ████████████████▍ │
|
||||||
│ BILLINGSHURST │ CHICHESTER │ 144 │ 797829 │ ███████████████▊ │
|
│ INGATESTONE │ CHELMSFORD │ 120 │ 815379 │ ████████████████▎ │
|
||||||
│ WOKING │ GUILDFORD │ 176 │ 793494 │ ███████████████▋ │
|
│ MARLOW │ BUCKINGHAMSHIRE │ 718 │ 809943 │ ████████████████▏ │
|
||||||
│ STOCKBRIDGE │ TEST VALLEY │ 178 │ 793269 │ ███████████████▋ │
|
│ EAST GRINSTEAD │ TANDRIDGE │ 105 │ 809461 │ ████████████████▏ │
|
||||||
│ EPSOM │ REIGATE AND BANSTEAD │ 172 │ 791862 │ ███████████████▋ │
|
│ CHIGWELL │ EPPING FOREST │ 484 │ 809338 │ ████████████████▏ │
|
||||||
│ TONBRIDGE │ TUNBRIDGE WELLS │ 360 │ 787876 │ ███████████████▋ │
|
│ EGHAM │ RUNNYMEDE │ 989 │ 807858 │ ████████████████▏ │
|
||||||
│ TEDDINGTON │ RICHMOND UPON THAMES │ 595 │ 786492 │ ███████████████▋ │
|
│ HASLEMERE │ CHICHESTER │ 223 │ 804173 │ ████████████████ │
|
||||||
│ TWICKENHAM │ RICHMOND UPON THAMES │ 1155 │ 786193 │ ███████████████▋ │
|
│ PETWORTH │ CHICHESTER │ 288 │ 803206 │ ████████████████ │
|
||||||
│ LYNDHURST │ NEW FOREST │ 102 │ 785593 │ ███████████████▋ │
|
│ TWICKENHAM │ RICHMOND UPON THAMES │ 2194 │ 802616 │ ████████████████ │
|
||||||
│ LONDON │ LAMBETH │ 5228 │ 774574 │ ███████████████▍ │
|
│ WEMBLEY │ BRENT │ 1698 │ 801733 │ ████████████████ │
|
||||||
│ LONDON │ BARNET │ 3955 │ 773259 │ ███████████████▍ │
|
│ HINDHEAD │ WAVERLEY │ 233 │ 801482 │ ████████████████ │
|
||||||
│ OXFORD │ VALE OF WHITE HORSE │ 353 │ 772088 │ ███████████████▍ │
|
│ LONDON │ BARNET │ 8083 │ 792066 │ ███████████████▋ │
|
||||||
│ TONBRIDGE │ MAIDSTONE │ 305 │ 770740 │ ███████████████▍ │
|
│ WOKING │ GUILDFORD │ 343 │ 789360 │ ███████████████▋ │
|
||||||
│ LUTTERWORTH │ HARBOROUGH │ 538 │ 768634 │ ███████████████▎ │
|
│ STOCKBRIDGE │ TEST VALLEY │ 318 │ 777909 │ ███████████████▌ │
|
||||||
│ WOODSTOCK │ WEST OXFORDSHIRE │ 140 │ 766037 │ ███████████████▎ │
|
│ BERKHAMSTED │ DACORUM │ 1049 │ 776138 │ ███████████████▌ │
|
||||||
│ MIDHURST │ CHICHESTER │ 257 │ 764815 │ ███████████████▎ │
|
│ MAIDENHEAD │ BUCKINGHAMSHIRE │ 236 │ 775572 │ ███████████████▌ │
|
||||||
│ MARLOW │ BUCKINGHAMSHIRE │ 327 │ 761876 │ ███████████████▏ │
|
│ SOLIHULL │ STRATFORD-ON-AVON │ 142 │ 770727 │ ███████████████▍ │
|
||||||
│ LONDON │ NEWHAM │ 3237 │ 761784 │ ███████████████▏ │
|
│ GREAT MISSENDEN │ BUCKINGHAMSHIRE │ 431 │ 764493 │ ███████████████▎ │
|
||||||
│ ALDERLEY EDGE │ CHESHIRE EAST │ 178 │ 757318 │ ███████████████▏ │
|
│ TADWORTH │ REIGATE AND BANSTEAD │ 920 │ 757511 │ ███████████████▏ │
|
||||||
│ LUTON │ CENTRAL BEDFORDSHIRE │ 212 │ 754283 │ ███████████████ │
|
│ LONDON │ BRENT │ 4124 │ 757194 │ ███████████████▏ │
|
||||||
│ PETWORTH │ CHICHESTER │ 154 │ 754220 │ ███████████████ │
|
│ THAMES DITTON │ ELMBRIDGE │ 470 │ 750828 │ ███████████████ │
|
||||||
│ ALRESFORD │ WINCHESTER │ 219 │ 752718 │ ███████████████ │
|
│ LONDON │ LAMBETH │ 10431 │ 750532 │ ███████████████ │
|
||||||
│ POTTERS BAR │ WELWYN HATFIELD │ 174 │ 748465 │ ██████████████▊ │
|
│ RICKMANSWORTH │ THREE RIVERS │ 1500 │ 747029 │ ██████████████▊ │
|
||||||
│ HASLEMERE │ CHICHESTER │ 128 │ 746907 │ ██████████████▊ │
|
│ KINGS LANGLEY │ DACORUM │ 281 │ 746536 │ ██████████████▊ │
|
||||||
│ TADWORTH │ REIGATE AND BANSTEAD │ 502 │ 743252 │ ██████████████▋ │
|
│ HARLOW │ EPPING FOREST │ 172 │ 739423 │ ██████████████▋ │
|
||||||
│ THAMES DITTON │ ELMBRIDGE │ 244 │ 741913 │ ██████████████▋ │
|
│ TONBRIDGE │ SEVENOAKS │ 103 │ 738740 │ ██████████████▋ │
|
||||||
│ REIGATE │ REIGATE AND BANSTEAD │ 581 │ 738198 │ ██████████████▋ │
|
│ BELVEDERE │ BEXLEY │ 686 │ 736385 │ ██████████████▋ │
|
||||||
│ BOURNE END │ BUCKINGHAMSHIRE │ 138 │ 735190 │ ██████████████▋ │
|
│ CRANBROOK │ TUNBRIDGE WELLS │ 769 │ 734328 │ ██████████████▋ │
|
||||||
│ SEVENOAKS │ SEVENOAKS │ 1156 │ 730018 │ ██████████████▌ │
|
│ SOLIHULL │ WARWICK │ 116 │ 733286 │ ██████████████▋ │
|
||||||
│ OXTED │ TANDRIDGE │ 336 │ 729123 │ ██████████████▌ │
|
│ ALDERLEY EDGE │ CHESHIRE EAST │ 357 │ 732882 │ ██████████████▋ │
|
||||||
│ INGATESTONE │ BRENTWOOD │ 166 │ 728103 │ ██████████████▌ │
|
│ WELWYN │ WELWYN HATFIELD │ 404 │ 730281 │ ██████████████▌ │
|
||||||
│ LONDON │ BRENT │ 2079 │ 720605 │ ██████████████▍ │
|
│ CHISLEHURST │ BROMLEY │ 870 │ 730279 │ ██████████████▌ │
|
||||||
│ LONDON │ HARINGEY │ 3216 │ 717780 │ ██████████████▎ │
|
│ LONDON │ HARINGEY │ 6488 │ 726715 │ ██████████████▌ │
|
||||||
│ PURLEY │ CROYDON │ 575 │ 716108 │ ██████████████▎ │
|
│ AMERSHAM │ BUCKINGHAMSHIRE │ 965 │ 725426 │ ██████████████▌ │
|
||||||
│ WELWYN │ WELWYN HATFIELD │ 222 │ 710603 │ ██████████████▏ │
|
│ SEVENOAKS │ SEVENOAKS │ 2183 │ 725102 │ ██████████████▌ │
|
||||||
│ RICKMANSWORTH │ THREE RIVERS │ 798 │ 704571 │ ██████████████ │
|
│ BOURNE END │ BUCKINGHAMSHIRE │ 269 │ 724595 │ ██████████████▍ │
|
||||||
│ BANSTEAD │ REIGATE AND BANSTEAD │ 401 │ 701293 │ ██████████████ │
|
│ NORTHWOOD │ HILLINGDON │ 568 │ 722436 │ ██████████████▍ │
|
||||||
│ CHIGWELL │ EPPING FOREST │ 261 │ 701203 │ ██████████████ │
|
│ PURFLEET │ THURROCK │ 143 │ 722205 │ ██████████████▍ │
|
||||||
│ PINNER │ HARROW │ 528 │ 698885 │ █████████████▊ │
|
│ SLOUGH │ BUCKINGHAMSHIRE │ 832 │ 721529 │ ██████████████▍ │
|
||||||
│ HASLEMERE │ WAVERLEY │ 280 │ 696659 │ █████████████▊ │
|
│ INGATESTONE │ BRENTWOOD │ 301 │ 718292 │ ██████████████▎ │
|
||||||
│ SLOUGH │ BUCKINGHAMSHIRE │ 396 │ 694917 │ █████████████▊ │
|
│ EPSOM │ REIGATE AND BANSTEAD │ 315 │ 709264 │ ██████████████▏ │
|
||||||
│ WALTON-ON-THAMES │ ELMBRIDGE │ 946 │ 692395 │ █████████████▋ │
|
│ ASHTEAD │ MOLE VALLEY │ 524 │ 708646 │ ██████████████▏ │
|
||||||
│ READING │ SOUTH OXFORDSHIRE │ 318 │ 691988 │ █████████████▋ │
|
│ BETCHWORTH │ MOLE VALLEY │ 155 │ 708525 │ ██████████████▏ │
|
||||||
│ NORTHWOOD │ HILLINGDON │ 271 │ 690643 │ █████████████▋ │
|
│ OXTED │ TANDRIDGE │ 645 │ 706946 │ ██████████████▏ │
|
||||||
│ FELTHAM │ HOUNSLOW │ 763 │ 688595 │ █████████████▋ │
|
│ READING │ SOUTH OXFORDSHIRE │ 593 │ 705466 │ ██████████████ │
|
||||||
│ ASHTEAD │ MOLE VALLEY │ 303 │ 687923 │ █████████████▋ │
|
│ FELTHAM │ HOUNSLOW │ 1536 │ 703815 │ ██████████████ │
|
||||||
│ BARNET │ BARNET │ 975 │ 686980 │ █████████████▋ │
|
│ TUNBRIDGE WELLS │ WEALDEN │ 207 │ 703296 │ ██████████████ │
|
||||||
│ WOKING │ SURREY HEATH │ 283 │ 686669 │ █████████████▋ │
|
│ LEWES │ WEALDEN │ 116 │ 701349 │ ██████████████ │
|
||||||
│ MALMESBURY │ WILTSHIRE │ 323 │ 683324 │ █████████████▋ │
|
│ OXFORD │ OXFORD │ 3656 │ 700813 │ ██████████████ │
|
||||||
│ AMERSHAM │ BUCKINGHAMSHIRE │ 496 │ 680962 │ █████████████▌ │
|
│ MAYFIELD │ WEALDEN │ 177 │ 698158 │ █████████████▊ │
|
||||||
│ CHISLEHURST │ BROMLEY │ 430 │ 680209 │ █████████████▌ │
|
│ PINNER │ HARROW │ 997 │ 697876 │ █████████████▊ │
|
||||||
│ HYTHE │ FOLKESTONE AND HYTHE │ 490 │ 676908 │ █████████████▌ │
|
│ LECHLADE │ COTSWOLD │ 155 │ 696262 │ █████████████▊ │
|
||||||
│ MAYFIELD │ WEALDEN │ 101 │ 676210 │ █████████████▌ │
|
│ WALTON-ON-THAMES │ ELMBRIDGE │ 1850 │ 690102 │ █████████████▋ │
|
||||||
│ ASCOT │ BRACKNELL FOREST │ 168 │ 676004 │ █████████████▌ │
|
└──────────────────────┴────────────────────────┴───────┴─────────┴─────────────────────────────────────────────────────────────────┘
|
||||||
└──────────────────────┴────────────────────────┴──────┴─────────┴────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Let's Speed Up Queries Using Projections {#speedup-with-projections}
|
## Let's Speed Up Queries Using Projections {#speedup-with-projections}
|
||||||
|
|
||||||
[Projections](../../sql-reference/statements/alter/projection.md) allow to improve queries speed by storing pre-aggregated data.
|
[Projections](../../sql-reference/statements/alter/projection.md) allow you to improve query speeds by storing pre-aggregated data in whatever format you want. In this example, we create a projection that keeps track of the average price, total price, and count of properties grouped by the year, district and town. At execution time, ClickHouse will use your projection if it thinks the projection can improve the performance fo the query (you don't have to do anything special to use the projection - ClickHouse decides for you when the projection will be useful).
|
||||||
|
|
||||||
### Build a Projection {#build-projection}
|
### Build a Projection {#build-projection}
|
||||||
|
|
||||||
Create an aggregate projection by dimensions `toYear(date)`, `district`, `town`:
|
Let's create an aggregate projection by the dimensions `toYear(date)`, `district`, and `town`:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
ALTER TABLE uk_price_paid
|
ALTER TABLE uk_price_paid
|
||||||
@ -374,25 +363,23 @@ ALTER TABLE uk_price_paid
|
|||||||
toYear(date),
|
toYear(date),
|
||||||
district,
|
district,
|
||||||
town
|
town
|
||||||
);
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Populate the projection for existing data (without it projection will be created for only newly inserted data):
|
Populate the projection for existing data. (Without materializing it, the projection will be created for only newly inserted data):
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
ALTER TABLE uk_price_paid
|
ALTER TABLE uk_price_paid
|
||||||
MATERIALIZE PROJECTION projection_by_year_district_town
|
MATERIALIZE PROJECTION projection_by_year_district_town
|
||||||
SETTINGS mutations_sync = 1;
|
SETTINGS mutations_sync = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Test Performance {#test-performance}
|
## Test Performance {#test-performance}
|
||||||
|
|
||||||
Let's run the same 3 queries.
|
Let's run the same 3 queries again:
|
||||||
|
|
||||||
### Query 1. Average Price Per Year {#average-price-projections}
|
### Query 1. Average Price Per Year {#average-price-projections}
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
toYear(date) AS year,
|
toYear(date) AS year,
|
||||||
@ -400,47 +387,18 @@ SELECT
|
|||||||
bar(price, 0, 1000000, 80)
|
bar(price, 0, 1000000, 80)
|
||||||
FROM uk_price_paid
|
FROM uk_price_paid
|
||||||
GROUP BY year
|
GROUP BY year
|
||||||
ORDER BY year ASC;
|
ORDER BY year ASC
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
The result is the same, but the performance is better!
|
||||||
|
```response
|
||||||
```text
|
No projection: 28 rows in set. Elapsed: 1.775 sec. Processed 27.45 million rows, 164.70 MB (15.47 million rows/s., 92.79 MB/s.)
|
||||||
┌─year─┬──price─┬─bar(round(avg(price)), 0, 1000000, 80)─┐
|
With projection: 28 rows in set. Elapsed: 0.665 sec. Processed 87.51 thousand rows, 3.21 MB (131.51 thousand rows/s., 4.82 MB/s.)
|
||||||
│ 1995 │ 67932 │ █████▍ │
|
|
||||||
│ 1996 │ 71505 │ █████▋ │
|
|
||||||
│ 1997 │ 78532 │ ██████▎ │
|
|
||||||
│ 1998 │ 85436 │ ██████▋ │
|
|
||||||
│ 1999 │ 96037 │ ███████▋ │
|
|
||||||
│ 2000 │ 107479 │ ████████▌ │
|
|
||||||
│ 2001 │ 118885 │ █████████▌ │
|
|
||||||
│ 2002 │ 137941 │ ███████████ │
|
|
||||||
│ 2003 │ 155889 │ ████████████▍ │
|
|
||||||
│ 2004 │ 178885 │ ██████████████▎ │
|
|
||||||
│ 2005 │ 189351 │ ███████████████▏ │
|
|
||||||
│ 2006 │ 203528 │ ████████████████▎ │
|
|
||||||
│ 2007 │ 219378 │ █████████████████▌ │
|
|
||||||
│ 2008 │ 217056 │ █████████████████▎ │
|
|
||||||
│ 2009 │ 213419 │ █████████████████ │
|
|
||||||
│ 2010 │ 236109 │ ██████████████████▊ │
|
|
||||||
│ 2011 │ 232805 │ ██████████████████▌ │
|
|
||||||
│ 2012 │ 238367 │ ███████████████████ │
|
|
||||||
│ 2013 │ 256931 │ ████████████████████▌ │
|
|
||||||
│ 2014 │ 279915 │ ██████████████████████▍ │
|
|
||||||
│ 2015 │ 297266 │ ███████████████████████▋ │
|
|
||||||
│ 2016 │ 313201 │ █████████████████████████ │
|
|
||||||
│ 2017 │ 346097 │ ███████████████████████████▋ │
|
|
||||||
│ 2018 │ 350116 │ ████████████████████████████ │
|
|
||||||
│ 2019 │ 351013 │ ████████████████████████████ │
|
|
||||||
│ 2020 │ 369420 │ █████████████████████████████▌ │
|
|
||||||
│ 2021 │ 386903 │ ██████████████████████████████▊ │
|
|
||||||
└──────┴────────┴────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Query 2. Average Price Per Year in London {#average-price-london-projections}
|
### Query 2. Average Price Per Year in London {#average-price-london-projections}
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
toYear(date) AS year,
|
toYear(date) AS year,
|
||||||
@ -449,48 +407,19 @@ SELECT
|
|||||||
FROM uk_price_paid
|
FROM uk_price_paid
|
||||||
WHERE town = 'LONDON'
|
WHERE town = 'LONDON'
|
||||||
GROUP BY year
|
GROUP BY year
|
||||||
ORDER BY year ASC;
|
ORDER BY year ASC
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
Same result, but notice the improvement in query performance:
|
||||||
|
|
||||||
```text
|
```response
|
||||||
┌─year─┬───price─┬─bar(round(avg(price)), 0, 2000000, 100)───────────────┐
|
No projection: 28 rows in set. Elapsed: 0.720 sec. Processed 27.45 million rows, 46.61 MB (38.13 million rows/s., 64.74 MB/s.)
|
||||||
│ 1995 │ 109116 │ █████▍ │
|
With projection: 28 rows in set. Elapsed: 0.015 sec. Processed 87.51 thousand rows, 3.51 MB (5.74 million rows/s., 230.24 MB/s.)
|
||||||
│ 1996 │ 118667 │ █████▊ │
|
|
||||||
│ 1997 │ 136518 │ ██████▋ │
|
|
||||||
│ 1998 │ 152983 │ ███████▋ │
|
|
||||||
│ 1999 │ 180637 │ █████████ │
|
|
||||||
│ 2000 │ 215838 │ ██████████▋ │
|
|
||||||
│ 2001 │ 232994 │ ███████████▋ │
|
|
||||||
│ 2002 │ 263670 │ █████████████▏ │
|
|
||||||
│ 2003 │ 278394 │ █████████████▊ │
|
|
||||||
│ 2004 │ 304666 │ ███████████████▏ │
|
|
||||||
│ 2005 │ 322875 │ ████████████████▏ │
|
|
||||||
│ 2006 │ 356191 │ █████████████████▋ │
|
|
||||||
│ 2007 │ 404054 │ ████████████████████▏ │
|
|
||||||
│ 2008 │ 420741 │ █████████████████████ │
|
|
||||||
│ 2009 │ 427753 │ █████████████████████▍ │
|
|
||||||
│ 2010 │ 480306 │ ████████████████████████ │
|
|
||||||
│ 2011 │ 496274 │ ████████████████████████▋ │
|
|
||||||
│ 2012 │ 519442 │ █████████████████████████▊ │
|
|
||||||
│ 2013 │ 616212 │ ██████████████████████████████▋ │
|
|
||||||
│ 2014 │ 724154 │ ████████████████████████████████████▏ │
|
|
||||||
│ 2015 │ 792129 │ ███████████████████████████████████████▌ │
|
|
||||||
│ 2016 │ 843655 │ ██████████████████████████████████████████▏ │
|
|
||||||
│ 2017 │ 982642 │ █████████████████████████████████████████████████▏ │
|
|
||||||
│ 2018 │ 1016835 │ ██████████████████████████████████████████████████▋ │
|
|
||||||
│ 2019 │ 1042849 │ ████████████████████████████████████████████████████▏ │
|
|
||||||
│ 2020 │ 1011889 │ ██████████████████████████████████████████████████▌ │
|
|
||||||
│ 2021 │ 960343 │ ████████████████████████████████████████████████ │
|
|
||||||
└──────┴─────────┴───────────────────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Query 3. The Most Expensive Neighborhoods {#most-expensive-neighborhoods-projections}
|
### Query 3. The Most Expensive Neighborhoods {#most-expensive-neighborhoods-projections}
|
||||||
|
|
||||||
The condition (date >= '2020-01-01') needs to be modified to match projection dimension (toYear(date) >= 2020).
|
The condition (date >= '2020-01-01') needs to be modified so that it matches the projection dimension (`toYear(date) >= 2020)`:
|
||||||
|
|
||||||
Query:
|
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
@ -506,138 +435,16 @@ GROUP BY
|
|||||||
district
|
district
|
||||||
HAVING c >= 100
|
HAVING c >= 100
|
||||||
ORDER BY price DESC
|
ORDER BY price DESC
|
||||||
LIMIT 100;
|
LIMIT 100
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
Again, the result is the same but notice the improvement in query performance:
|
||||||
|
|
||||||
```text
|
```response
|
||||||
┌─town─────────────────┬─district───────────────┬────c─┬───price─┬─bar(round(avg(price)), 0, 5000000, 100)────────────────────────────┐
|
No projection: 100 rows in set. Elapsed: 0.928 sec. Processed 27.45 million rows, 103.80 MB (29.56 million rows/s., 111.80 MB/s.)
|
||||||
│ LONDON │ CITY OF WESTMINSTER │ 3606 │ 3280239 │ █████████████████████████████████████████████████████████████████▌ │
|
With projection: 100 rows in set. Elapsed: 0.336 sec. Processed 17.32 thousand rows, 1.23 MB (51.61 thousand rows/s., 3.65 MB/s.)
|
||||||
│ LONDON │ CITY OF LONDON │ 274 │ 3160502 │ ███████████████████████████████████████████████████████████████▏ │
|
|
||||||
│ LONDON │ KENSINGTON AND CHELSEA │ 2550 │ 2308478 │ ██████████████████████████████████████████████▏ │
|
|
||||||
│ LEATHERHEAD │ ELMBRIDGE │ 114 │ 1897407 │ █████████████████████████████████████▊ │
|
|
||||||
│ LONDON │ CAMDEN │ 3033 │ 1805404 │ ████████████████████████████████████ │
|
|
||||||
│ VIRGINIA WATER │ RUNNYMEDE │ 156 │ 1753247 │ ███████████████████████████████████ │
|
|
||||||
│ WINDLESHAM │ SURREY HEATH │ 108 │ 1677613 │ █████████████████████████████████▌ │
|
|
||||||
│ THORNTON HEATH │ CROYDON │ 546 │ 1671721 │ █████████████████████████████████▍ │
|
|
||||||
│ BARNET │ ENFIELD │ 124 │ 1505840 │ ██████████████████████████████ │
|
|
||||||
│ COBHAM │ ELMBRIDGE │ 387 │ 1237250 │ ████████████████████████▋ │
|
|
||||||
│ LONDON │ ISLINGTON │ 2668 │ 1236980 │ ████████████████████████▋ │
|
|
||||||
│ OXFORD │ SOUTH OXFORDSHIRE │ 321 │ 1220907 │ ████████████████████████▍ │
|
|
||||||
│ LONDON │ RICHMOND UPON THAMES │ 704 │ 1215551 │ ████████████████████████▎ │
|
|
||||||
│ LONDON │ HOUNSLOW │ 671 │ 1207493 │ ████████████████████████▏ │
|
|
||||||
│ ASCOT │ WINDSOR AND MAIDENHEAD │ 407 │ 1183299 │ ███████████████████████▋ │
|
|
||||||
│ BEACONSFIELD │ BUCKINGHAMSHIRE │ 330 │ 1175615 │ ███████████████████████▌ │
|
|
||||||
│ RICHMOND │ RICHMOND UPON THAMES │ 874 │ 1110444 │ ██████████████████████▏ │
|
|
||||||
│ LONDON │ HAMMERSMITH AND FULHAM │ 3086 │ 1053983 │ █████████████████████ │
|
|
||||||
│ SURBITON │ ELMBRIDGE │ 100 │ 1011800 │ ████████████████████▏ │
|
|
||||||
│ RADLETT │ HERTSMERE │ 283 │ 1011712 │ ████████████████████▏ │
|
|
||||||
│ SALCOMBE │ SOUTH HAMS │ 127 │ 1011624 │ ████████████████████▏ │
|
|
||||||
│ WEYBRIDGE │ ELMBRIDGE │ 655 │ 1007265 │ ████████████████████▏ │
|
|
||||||
│ ESHER │ ELMBRIDGE │ 485 │ 986581 │ ███████████████████▋ │
|
|
||||||
│ LEATHERHEAD │ GUILDFORD │ 202 │ 977320 │ ███████████████████▌ │
|
|
||||||
│ BURFORD │ WEST OXFORDSHIRE │ 111 │ 966893 │ ███████████████████▎ │
|
|
||||||
│ BROCKENHURST │ NEW FOREST │ 129 │ 956675 │ ███████████████████▏ │
|
|
||||||
│ HINDHEAD │ WAVERLEY │ 137 │ 953753 │ ███████████████████ │
|
|
||||||
│ GERRARDS CROSS │ BUCKINGHAMSHIRE │ 419 │ 951121 │ ███████████████████ │
|
|
||||||
│ EAST MOLESEY │ ELMBRIDGE │ 192 │ 936769 │ ██████████████████▋ │
|
|
||||||
│ CHALFONT ST GILES │ BUCKINGHAMSHIRE │ 146 │ 925515 │ ██████████████████▌ │
|
|
||||||
│ LONDON │ TOWER HAMLETS │ 4388 │ 918304 │ ██████████████████▎ │
|
|
||||||
│ OLNEY │ MILTON KEYNES │ 235 │ 910646 │ ██████████████████▏ │
|
|
||||||
│ HENLEY-ON-THAMES │ SOUTH OXFORDSHIRE │ 540 │ 902418 │ ██████████████████ │
|
|
||||||
│ LONDON │ SOUTHWARK │ 3885 │ 892997 │ █████████████████▋ │
|
|
||||||
│ KINGSTON UPON THAMES │ KINGSTON UPON THAMES │ 960 │ 885969 │ █████████████████▋ │
|
|
||||||
│ LONDON │ EALING │ 2658 │ 871755 │ █████████████████▍ │
|
|
||||||
│ CRANBROOK │ TUNBRIDGE WELLS │ 431 │ 862348 │ █████████████████▏ │
|
|
||||||
│ LONDON │ MERTON │ 2099 │ 859118 │ █████████████████▏ │
|
|
||||||
│ BELVEDERE │ BEXLEY │ 346 │ 842423 │ ████████████████▋ │
|
|
||||||
│ GUILDFORD │ WAVERLEY │ 143 │ 841277 │ ████████████████▋ │
|
|
||||||
│ HARPENDEN │ ST ALBANS │ 657 │ 841216 │ ████████████████▋ │
|
|
||||||
│ LONDON │ HACKNEY │ 3307 │ 837090 │ ████████████████▋ │
|
|
||||||
│ LONDON │ WANDSWORTH │ 6566 │ 832663 │ ████████████████▋ │
|
|
||||||
│ MAIDENHEAD │ BUCKINGHAMSHIRE │ 123 │ 824299 │ ████████████████▍ │
|
|
||||||
│ KINGS LANGLEY │ DACORUM │ 145 │ 821331 │ ████████████████▍ │
|
|
||||||
│ BERKHAMSTED │ DACORUM │ 543 │ 818415 │ ████████████████▎ │
|
|
||||||
│ GREAT MISSENDEN │ BUCKINGHAMSHIRE │ 226 │ 802807 │ ████████████████ │
|
|
||||||
│ BILLINGSHURST │ CHICHESTER │ 144 │ 797829 │ ███████████████▊ │
|
|
||||||
│ WOKING │ GUILDFORD │ 176 │ 793494 │ ███████████████▋ │
|
|
||||||
│ STOCKBRIDGE │ TEST VALLEY │ 178 │ 793269 │ ███████████████▋ │
|
|
||||||
│ EPSOM │ REIGATE AND BANSTEAD │ 172 │ 791862 │ ███████████████▋ │
|
|
||||||
│ TONBRIDGE │ TUNBRIDGE WELLS │ 360 │ 787876 │ ███████████████▋ │
|
|
||||||
│ TEDDINGTON │ RICHMOND UPON THAMES │ 595 │ 786492 │ ███████████████▋ │
|
|
||||||
│ TWICKENHAM │ RICHMOND UPON THAMES │ 1155 │ 786193 │ ███████████████▋ │
|
|
||||||
│ LYNDHURST │ NEW FOREST │ 102 │ 785593 │ ███████████████▋ │
|
|
||||||
│ LONDON │ LAMBETH │ 5228 │ 774574 │ ███████████████▍ │
|
|
||||||
│ LONDON │ BARNET │ 3955 │ 773259 │ ███████████████▍ │
|
|
||||||
│ OXFORD │ VALE OF WHITE HORSE │ 353 │ 772088 │ ███████████████▍ │
|
|
||||||
│ TONBRIDGE │ MAIDSTONE │ 305 │ 770740 │ ███████████████▍ │
|
|
||||||
│ LUTTERWORTH │ HARBOROUGH │ 538 │ 768634 │ ███████████████▎ │
|
|
||||||
│ WOODSTOCK │ WEST OXFORDSHIRE │ 140 │ 766037 │ ███████████████▎ │
|
|
||||||
│ MIDHURST │ CHICHESTER │ 257 │ 764815 │ ███████████████▎ │
|
|
||||||
│ MARLOW │ BUCKINGHAMSHIRE │ 327 │ 761876 │ ███████████████▏ │
|
|
||||||
│ LONDON │ NEWHAM │ 3237 │ 761784 │ ███████████████▏ │
|
|
||||||
│ ALDERLEY EDGE │ CHESHIRE EAST │ 178 │ 757318 │ ███████████████▏ │
|
|
||||||
│ LUTON │ CENTRAL BEDFORDSHIRE │ 212 │ 754283 │ ███████████████ │
|
|
||||||
│ PETWORTH │ CHICHESTER │ 154 │ 754220 │ ███████████████ │
|
|
||||||
│ ALRESFORD │ WINCHESTER │ 219 │ 752718 │ ███████████████ │
|
|
||||||
│ POTTERS BAR │ WELWYN HATFIELD │ 174 │ 748465 │ ██████████████▊ │
|
|
||||||
│ HASLEMERE │ CHICHESTER │ 128 │ 746907 │ ██████████████▊ │
|
|
||||||
│ TADWORTH │ REIGATE AND BANSTEAD │ 502 │ 743252 │ ██████████████▋ │
|
|
||||||
│ THAMES DITTON │ ELMBRIDGE │ 244 │ 741913 │ ██████████████▋ │
|
|
||||||
│ REIGATE │ REIGATE AND BANSTEAD │ 581 │ 738198 │ ██████████████▋ │
|
|
||||||
│ BOURNE END │ BUCKINGHAMSHIRE │ 138 │ 735190 │ ██████████████▋ │
|
|
||||||
│ SEVENOAKS │ SEVENOAKS │ 1156 │ 730018 │ ██████████████▌ │
|
|
||||||
│ OXTED │ TANDRIDGE │ 336 │ 729123 │ ██████████████▌ │
|
|
||||||
│ INGATESTONE │ BRENTWOOD │ 166 │ 728103 │ ██████████████▌ │
|
|
||||||
│ LONDON │ BRENT │ 2079 │ 720605 │ ██████████████▍ │
|
|
||||||
│ LONDON │ HARINGEY │ 3216 │ 717780 │ ██████████████▎ │
|
|
||||||
│ PURLEY │ CROYDON │ 575 │ 716108 │ ██████████████▎ │
|
|
||||||
│ WELWYN │ WELWYN HATFIELD │ 222 │ 710603 │ ██████████████▏ │
|
|
||||||
│ RICKMANSWORTH │ THREE RIVERS │ 798 │ 704571 │ ██████████████ │
|
|
||||||
│ BANSTEAD │ REIGATE AND BANSTEAD │ 401 │ 701293 │ ██████████████ │
|
|
||||||
│ CHIGWELL │ EPPING FOREST │ 261 │ 701203 │ ██████████████ │
|
|
||||||
│ PINNER │ HARROW │ 528 │ 698885 │ █████████████▊ │
|
|
||||||
│ HASLEMERE │ WAVERLEY │ 280 │ 696659 │ █████████████▊ │
|
|
||||||
│ SLOUGH │ BUCKINGHAMSHIRE │ 396 │ 694917 │ █████████████▊ │
|
|
||||||
│ WALTON-ON-THAMES │ ELMBRIDGE │ 946 │ 692395 │ █████████████▋ │
|
|
||||||
│ READING │ SOUTH OXFORDSHIRE │ 318 │ 691988 │ █████████████▋ │
|
|
||||||
│ NORTHWOOD │ HILLINGDON │ 271 │ 690643 │ █████████████▋ │
|
|
||||||
│ FELTHAM │ HOUNSLOW │ 763 │ 688595 │ █████████████▋ │
|
|
||||||
│ ASHTEAD │ MOLE VALLEY │ 303 │ 687923 │ █████████████▋ │
|
|
||||||
│ BARNET │ BARNET │ 975 │ 686980 │ █████████████▋ │
|
|
||||||
│ WOKING │ SURREY HEATH │ 283 │ 686669 │ █████████████▋ │
|
|
||||||
│ MALMESBURY │ WILTSHIRE │ 323 │ 683324 │ █████████████▋ │
|
|
||||||
│ AMERSHAM │ BUCKINGHAMSHIRE │ 496 │ 680962 │ █████████████▌ │
|
|
||||||
│ CHISLEHURST │ BROMLEY │ 430 │ 680209 │ █████████████▌ │
|
|
||||||
│ HYTHE │ FOLKESTONE AND HYTHE │ 490 │ 676908 │ █████████████▌ │
|
|
||||||
│ MAYFIELD │ WEALDEN │ 101 │ 676210 │ █████████████▌ │
|
|
||||||
│ ASCOT │ BRACKNELL FOREST │ 168 │ 676004 │ █████████████▌ │
|
|
||||||
└──────────────────────┴────────────────────────┴──────┴─────────┴────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Summary {#summary}
|
### Test it in the Playground {#playground}
|
||||||
|
|
||||||
All 3 queries work much faster and read fewer rows.
|
|
||||||
|
|
||||||
```text
|
|
||||||
Query 1
|
|
||||||
|
|
||||||
no projection: 27 rows in set. Elapsed: 0.158 sec. Processed 26.32 million rows, 157.93 MB (166.57 million rows/s., 999.39 MB/s.)
|
|
||||||
projection: 27 rows in set. Elapsed: 0.007 sec. Processed 105.96 thousand rows, 3.33 MB (14.58 million rows/s., 458.13 MB/s.)
|
|
||||||
|
|
||||||
|
|
||||||
Query 2
|
|
||||||
|
|
||||||
no projection: 27 rows in set. Elapsed: 0.163 sec. Processed 26.32 million rows, 80.01 MB (161.75 million rows/s., 491.64 MB/s.)
|
|
||||||
projection: 27 rows in set. Elapsed: 0.008 sec. Processed 105.96 thousand rows, 3.67 MB (13.29 million rows/s., 459.89 MB/s.)
|
|
||||||
|
|
||||||
Query 3
|
|
||||||
|
|
||||||
no projection: 100 rows in set. Elapsed: 0.069 sec. Processed 26.32 million rows, 62.47 MB (382.13 million rows/s., 906.93 MB/s.)
|
|
||||||
projection: 100 rows in set. Elapsed: 0.029 sec. Processed 8.08 thousand rows, 511.08 KB (276.06 thousand rows/s., 17.47 MB/s.)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test It in Playground {#playground}
|
|
||||||
|
|
||||||
The dataset is also available in the [Online Playground](https://play.clickhouse.com/play?user=play#U0VMRUNUIHRvd24sIGRpc3RyaWN0LCBjb3VudCgpIEFTIGMsIHJvdW5kKGF2ZyhwcmljZSkpIEFTIHByaWNlLCBiYXIocHJpY2UsIDAsIDUwMDAwMDAsIDEwMCkgRlJPTSB1a19wcmljZV9wYWlkIFdIRVJFIGRhdGUgPj0gJzIwMjAtMDEtMDEnIEdST1VQIEJZIHRvd24sIGRpc3RyaWN0IEhBVklORyBjID49IDEwMCBPUkRFUiBCWSBwcmljZSBERVNDIExJTUlUIDEwMA==).
|
The dataset is also available in the [Online Playground](https://play.clickhouse.com/play?user=play#U0VMRUNUIHRvd24sIGRpc3RyaWN0LCBjb3VudCgpIEFTIGMsIHJvdW5kKGF2ZyhwcmljZSkpIEFTIHByaWNlLCBiYXIocHJpY2UsIDAsIDUwMDAwMDAsIDEwMCkgRlJPTSB1a19wcmljZV9wYWlkIFdIRVJFIGRhdGUgPj0gJzIwMjAtMDEtMDEnIEdST1VQIEJZIHRvd24sIGRpc3RyaWN0IEhBVklORyBjID49IDEwMCBPUkRFUiBCWSBwcmljZSBERVNDIExJTUlUIDEwMA==).
|
||||||
|
26
docs/en/getting-started/index.md
Normal file
26
docs/en/getting-started/index.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
slug: /en/getting-started/example-datasets/
|
||||||
|
sidebar_position: 0
|
||||||
|
sidebar_label: Overview
|
||||||
|
keywords: [clickhouse, install, tutorial, sample, datasets]
|
||||||
|
pagination_next: 'en/tutorial'
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tutorials and Example Datasets
|
||||||
|
|
||||||
|
We have a lot of resources for helping you get started and learn how ClickHouse works:
|
||||||
|
|
||||||
|
- If you need to get ClickHouse up and running, check out our [Quick Start](../quick-start.mdx)
|
||||||
|
- The [ClickHouse Tutorial](../tutorial.md) analyzes a dataset of New York City taxi rides
|
||||||
|
|
||||||
|
In addition, the sample datasets provide a great experience on working with ClickHouse,
|
||||||
|
learning important techniques and tricks, and seeing how to take advantage of the many powerful
|
||||||
|
functions in ClickHouse. The sample datasets include:
|
||||||
|
|
||||||
|
- The [UK Property Price Paid dataset](../getting-started/example-datasets/uk-price-paid.md) is a good starting point with some interesting SQL queries
|
||||||
|
- The [New York Taxi Data](../getting-started/example-datasets/nyc-taxi.md) has an example of how to insert data from S3 into ClickHouse
|
||||||
|
- The [Cell Towers dataset](../getting-started/example-datasets/cell-towers.md) imports a CSV into ClickHouse
|
||||||
|
- The [NYPD Complaint Data](../getting-started/example-datasets/nypd_complaint_data.md) demonstrates how to use data inference to simplify creating tables
|
||||||
|
- The ["What's on the Menu?" dataset](../getting-started/example-datasets/menus.md) has an example of denormalizing data
|
||||||
|
|
||||||
|
View the **Tutorials and Datasets** menu for a complete list of sample datasets.
|
@ -3,6 +3,7 @@ slug: /en/interfaces/cli
|
|||||||
sidebar_position: 17
|
sidebar_position: 17
|
||||||
sidebar_label: Command-Line Client
|
sidebar_label: Command-Line Client
|
||||||
---
|
---
|
||||||
|
import ConnectionDetails from '@site/docs/en/_snippets/_gather_your_details_native.md';
|
||||||
|
|
||||||
# Command-line Client
|
# Command-line Client
|
||||||
|
|
||||||
@ -24,26 +25,76 @@ Connected to ClickHouse server version 20.13.1 revision 54442.
|
|||||||
Different client and server versions are compatible with one another, but some features may not be available in older clients. We recommend using the same version of the client as the server app. When you try to use a client of the older version, then the server, `clickhouse-client` displays the message:
|
Different client and server versions are compatible with one another, but some features may not be available in older clients. We recommend using the same version of the client as the server app. When you try to use a client of the older version, then the server, `clickhouse-client` displays the message:
|
||||||
|
|
||||||
```response
|
```response
|
||||||
ClickHouse client version is older than ClickHouse server. It may lack support for new features.
|
ClickHouse client version is older than ClickHouse server.
|
||||||
|
It may lack support for new features.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage {#cli_usage}
|
## Usage {#cli_usage}
|
||||||
|
|
||||||
The client can be used in interactive and non-interactive (batch) mode. To use batch mode, specify the ‘query’ parameter, or send data to ‘stdin’ (it verifies that ‘stdin’ is not a terminal), or both. Similar to the HTTP interface, when using the ‘query’ parameter and sending data to ‘stdin’, the request is a concatenation of the ‘query’ parameter, a line feed, and the data in ‘stdin’. This is convenient for large INSERT queries.
|
The client can be used in interactive and non-interactive (batch) mode.
|
||||||
|
|
||||||
Example of using the client to insert data:
|
### Gather your connection details
|
||||||
|
<ConnectionDetails />
|
||||||
|
|
||||||
|
### Interactive
|
||||||
|
|
||||||
|
To connect to your ClickHouse Cloud service, or any ClickHouse server using TLS and passwords, interactively use `--secure`, port 9440, and provide your username and password:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clickhouse-client --host <HOSTNAME> \
|
||||||
|
--secure \
|
||||||
|
--port 9440 \
|
||||||
|
--user <USERNAME> \
|
||||||
|
--password <PASSWORD>
|
||||||
|
```
|
||||||
|
|
||||||
|
To connect to a self-managed ClickHouse server you will need the details for that server. Whether or not TLS is used, port numbers, and passwords are all configurable. Use the above example for ClickHouse Cloud as a starting point.
|
||||||
|
|
||||||
|
|
||||||
|
### Batch
|
||||||
|
|
||||||
|
To use batch mode, specify the ‘query’ parameter, or send data to ‘stdin’ (it verifies that ‘stdin’ is not a terminal), or both. Similar to the HTTP interface, when using the ‘query’ parameter and sending data to ‘stdin’, the request is a concatenation of the ‘query’ parameter, a line feed, and the data in ‘stdin’. This is convenient for large INSERT queries.
|
||||||
|
|
||||||
|
Examples of using the client to insert data:
|
||||||
|
|
||||||
|
#### Inserting a CSV file into a remote ClickHouse service
|
||||||
|
|
||||||
|
This example is appropriate for ClickHouse Cloud, or any ClickHouse server using TLS and a password. In this example a sample dataset CSV file, `cell_towers.csv` is inserted into an existing table `cell_towers` in the `default` database:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clickhouse-client --host HOSTNAME.clickhouse.cloud \
|
||||||
|
--secure \
|
||||||
|
--port 9440 \
|
||||||
|
--user default \
|
||||||
|
--password PASSWORD \
|
||||||
|
--query "INSERT INTO cell_towers FORMAT CSVWithNames" \
|
||||||
|
< cell_towers.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
:::note
|
||||||
|
To concentrate on the query syntax, the rest of the examples leave off the connection details (`--host`, `--port`, etc.). Add them in when you try the commands.
|
||||||
|
:::
|
||||||
|
|
||||||
|
#### Three different ways of inserting data
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ echo -ne "1, 'some text', '2016-08-14 00:00:00'\n2, 'some more text', '2016-08-14 00:00:01'" | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
echo -ne "1, 'some text', '2016-08-14 00:00:00'\n2, 'some more text', '2016-08-14 00:00:01'" | \
|
||||||
|
clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
||||||
|
```
|
||||||
|
|
||||||
$ cat <<_EOF | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
```bash
|
||||||
|
cat <<_EOF | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
||||||
3, 'some text', '2016-08-14 00:00:00'
|
3, 'some text', '2016-08-14 00:00:00'
|
||||||
4, 'some more text', '2016-08-14 00:00:01'
|
4, 'some more text', '2016-08-14 00:00:01'
|
||||||
_EOF
|
_EOF
|
||||||
|
|
||||||
$ cat file.csv | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat file.csv | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
In batch mode, the default data format is TabSeparated. You can set the format in the FORMAT clause of the query.
|
In batch mode, the default data format is TabSeparated. You can set the format in the FORMAT clause of the query.
|
||||||
|
|
||||||
By default, you can only process a single query in batch mode. To make multiple queries from a “script,” use the `--multiquery` parameter. This works for all queries except INSERT. Query results are output consecutively without additional separators. Similarly, to process a large number of queries, you can run ‘clickhouse-client’ for each query. Note that it may take tens of milliseconds to launch the ‘clickhouse-client’ program.
|
By default, you can only process a single query in batch mode. To make multiple queries from a “script,” use the `--multiquery` parameter. This works for all queries except INSERT. Query results are output consecutively without additional separators. Similarly, to process a large number of queries, you can run ‘clickhouse-client’ for each query. Note that it may take tens of milliseconds to launch the ‘clickhouse-client’ program.
|
||||||
|
@ -84,8 +84,8 @@ In the following example a table is created and loaded with data from a CSV file
|
|||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
./clickhouse-grpc-client.py -q "CREATE TABLE grpc_example_table (id UInt32, text String) ENGINE = MergeTree() ORDER BY id;"
|
./clickhouse-grpc-client.py -q "CREATE TABLE grpc_example_table (id UInt32, text String) ENGINE = MergeTree() ORDER BY id;"
|
||||||
echo "0,Input data for" > a.txt ; echo "1,gRPC protocol example" >> a.txt
|
echo -e "0,Input data for\n1,gRPC protocol example" > a.csv
|
||||||
cat a.txt | ./clickhouse-grpc-client.py -q "INSERT INTO grpc_example_table FORMAT CSV"
|
cat a.csv | ./clickhouse-grpc-client.py -q "INSERT INTO grpc_example_table FORMAT CSV"
|
||||||
|
|
||||||
./clickhouse-grpc-client.py --format PrettyCompact -q "SELECT * FROM grpc_example_table;"
|
./clickhouse-grpc-client.py --format PrettyCompact -q "SELECT * FROM grpc_example_table;"
|
||||||
```
|
```
|
||||||
|
@ -6,16 +6,32 @@ sidebar_label: MySQL Interface
|
|||||||
|
|
||||||
# MySQL Interface
|
# MySQL Interface
|
||||||
|
|
||||||
ClickHouse supports MySQL wire protocol. It can be enabled by [mysql_port](../operations/server-configuration-parameters/settings.md#server_configuration_parameters-mysql_port) setting in configuration file:
|
ClickHouse supports MySQL wire protocol. To enable the MySQL wire protocol, add the [mysql_port](../operations/server-configuration-parameters/settings.md#server_configuration_parameters-mysql_port) setting to your server's configuration file. For example, you could define the port in a new XML file in your `config.d` folder:
|
||||||
|
|
||||||
``` xml
|
``` xml
|
||||||
<mysql_port>9004</mysql_port>
|
<clickhouse>
|
||||||
|
<mysql_port>9004</mysql_port>
|
||||||
|
</clickhouse>
|
||||||
```
|
```
|
||||||
|
|
||||||
Example of connecting using command-line tool `mysql`:
|
Startup your ClickHouse server and look for a log message similar to the following that mentions Listening for MySQL compatibility protocol:
|
||||||
|
|
||||||
|
```
|
||||||
|
{} <Information> Application: Listening for MySQL compatibility protocol: 127.0.0.1:9004
|
||||||
|
```
|
||||||
|
|
||||||
|
## Connect mysql to ClickHouse
|
||||||
|
|
||||||
|
The following command demonstrates how to connect the MySQL client `mysql` to ClickHouse:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysql --protocol tcp -h [hostname] -u [username] -P [port_number] [database_name]
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ mysql --protocol tcp -u default -P 9004
|
$ mysql --protocol tcp -h 127.0.0.1 -u default -P 9004 default
|
||||||
```
|
```
|
||||||
|
|
||||||
Output if a connection succeeded:
|
Output if a connection succeeded:
|
||||||
|
@ -5,6 +5,9 @@ sidebar_label: ClickHouse Keeper
|
|||||||
---
|
---
|
||||||
|
|
||||||
# ClickHouse Keeper
|
# ClickHouse Keeper
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_automated.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
ClickHouse Keeper provides the coordination system for data [replication](../engines/table-engines/mergetree-family/replication.md) and [distributed DDL](../sql-reference/distributed-ddl.md) queries execution. ClickHouse Keeper is compatible with ZooKeeper.
|
ClickHouse Keeper provides the coordination system for data [replication](../engines/table-engines/mergetree-family/replication.md) and [distributed DDL](../sql-reference/distributed-ddl.md) queries execution. ClickHouse Keeper is compatible with ZooKeeper.
|
||||||
|
|
||||||
|
@ -3,7 +3,11 @@ slug: /en/operations/external-authenticators/
|
|||||||
sidebar_position: 48
|
sidebar_position: 48
|
||||||
sidebar_label: External User Authenticators and Directories
|
sidebar_label: External User Authenticators and Directories
|
||||||
title: "External User Authenticators and Directories"
|
title: "External User Authenticators and Directories"
|
||||||
|
pagination_next: 'en/operations/external-authenticators/kerberos'
|
||||||
---
|
---
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
ClickHouse supports authenticating and managing users using external services.
|
ClickHouse supports authenticating and managing users using external services.
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
slug: /en/operations/external-authenticators/kerberos
|
slug: /en/operations/external-authenticators/kerberos
|
||||||
---
|
---
|
||||||
# Kerberos
|
# Kerberos
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
Existing and properly configured ClickHouse users can be authenticated via Kerberos authentication protocol.
|
Existing and properly configured ClickHouse users can be authenticated via Kerberos authentication protocol.
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
slug: /en/operations/external-authenticators/ldap
|
slug: /en/operations/external-authenticators/ldap
|
||||||
title: "LDAP"
|
title: "LDAP"
|
||||||
---
|
---
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
LDAP server can be used to authenticate ClickHouse users. There are two different approaches for doing this:
|
LDAP server can be used to authenticate ClickHouse users. There are two different approaches for doing this:
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
slug: /en/operations/external-authenticators/ssl-x509
|
slug: /en/operations/external-authenticators/ssl-x509
|
||||||
title: "SSL X.509 certificate authentication"
|
title: "SSL X.509 certificate authentication"
|
||||||
---
|
---
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
[SSL 'strict' option](../server-configuration-parameters/settings.md#server_configuration_parameters-openssl) enables mandatory certificate validation for the incoming connections. In this case, only connections with trusted certificates can be established. Connections with untrusted certificates will be rejected. Thus, certificate validation allows to uniquely authenticate an incoming connection. `Common Name` field of the certificate is used to identify connected user. This allows to associate multiple certificates with the same user. Additionally, reissuing and revoking of the certificates does not affect the ClickHouse configuration.
|
[SSL 'strict' option](../server-configuration-parameters/settings.md#server_configuration_parameters-openssl) enables mandatory certificate validation for the incoming connections. In this case, only connections with trusted certificates can be established. Connections with untrusted certificates will be rejected. Thus, certificate validation allows to uniquely authenticate an incoming connection. `Common Name` field of the certificate is used to identify connected user. This allows to associate multiple certificates with the same user. Additionally, reissuing and revoking of the certificates does not affect the ClickHouse configuration.
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ sidebar_label: Monitoring
|
|||||||
---
|
---
|
||||||
|
|
||||||
# Monitoring
|
# Monitoring
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_automated.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
You can monitor:
|
You can monitor:
|
||||||
|
|
||||||
|
@ -3,9 +3,12 @@ slug: /en/operations/optimizing-performance/sampling-query-profiler
|
|||||||
sidebar_position: 54
|
sidebar_position: 54
|
||||||
sidebar_label: Query Profiling
|
sidebar_label: Query Profiling
|
||||||
---
|
---
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
# Sampling Query Profiler
|
# Sampling Query Profiler
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
ClickHouse runs sampling profiler that allows analyzing query execution. Using profiler you can find source code routines that used the most frequently during query execution. You can trace CPU time and wall-clock time spent including idle time.
|
ClickHouse runs sampling profiler that allows analyzing query execution. Using profiler you can find source code routines that used the most frequently during query execution. You can trace CPU time and wall-clock time spent including idle time.
|
||||||
|
|
||||||
To use profiler:
|
To use profiler:
|
||||||
|
@ -5,6 +5,10 @@ sidebar_label: Testing Hardware
|
|||||||
title: "How to Test Your Hardware with ClickHouse"
|
title: "How to Test Your Hardware with ClickHouse"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
You can run a basic ClickHouse performance test on any server without installation of ClickHouse packages.
|
You can run a basic ClickHouse performance test on any server without installation of ClickHouse packages.
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
slug: /en/operations/server-configuration-parameters/
|
slug: /en/operations/server-configuration-parameters/
|
||||||
sidebar_position: 54
|
sidebar_position: 54
|
||||||
sidebar_label: Server Configuration Parameters
|
sidebar_label: Server Configuration Parameters
|
||||||
|
pagination_next: en/operations/server-configuration-parameters/settings
|
||||||
---
|
---
|
||||||
|
|
||||||
# Server Configuration Parameters
|
# Server Configuration Parameters
|
||||||
|
@ -666,6 +666,7 @@ Keys:
|
|||||||
- `http_proxy` - Configure HTTP proxy for sending crash reports.
|
- `http_proxy` - Configure HTTP proxy for sending crash reports.
|
||||||
- `debug` - Sets the Sentry client into debug mode.
|
- `debug` - Sets the Sentry client into debug mode.
|
||||||
- `tmp_path` - Filesystem path for temporary crash report state.
|
- `tmp_path` - Filesystem path for temporary crash report state.
|
||||||
|
- `environment` - An arbitrary name of an environment in which the ClickHouse server is running. It will be mentioned in each crash report. The default value is `test` or `prod` depending on the version of ClickHouse.
|
||||||
|
|
||||||
**Recommended way to use**
|
**Recommended way to use**
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
sidebar_label: Settings
|
sidebar_label: Settings
|
||||||
sidebar_position: 51
|
sidebar_position: 51
|
||||||
slug: /en/operations/settings/
|
slug: /en/operations/settings/
|
||||||
|
pagination_next: en/operations/settings/settings
|
||||||
---
|
---
|
||||||
|
|
||||||
# Settings Overview
|
# Settings Overview
|
||||||
|
@ -668,7 +668,7 @@ log_query_views=1
|
|||||||
|
|
||||||
## log_formatted_queries {#settings-log-formatted-queries}
|
## log_formatted_queries {#settings-log-formatted-queries}
|
||||||
|
|
||||||
Allows to log formatted queries to the [system.query_log](../../operations/system-tables/query_log.md) system table.
|
Allows to log formatted queries to the [system.query_log](../../operations/system-tables/query_log.md) system table (populates `formatted_query` column in the [system.query_log](../../operations/system-tables/query_log.md)).
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ sidebar_label: Secured Communication with Zookeeper
|
|||||||
---
|
---
|
||||||
|
|
||||||
# Optional secured communication between ClickHouse and Zookeeper
|
# Optional secured communication between ClickHouse and Zookeeper
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_automated.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
You should specify `ssl.keyStore.location`, `ssl.keyStore.password` and `ssl.trustStore.location`, `ssl.trustStore.password` for communication with ClickHouse client over SSL. These options are available from Zookeeper version 3.5.2.
|
You should specify `ssl.keyStore.location`, `ssl.keyStore.password` and `ssl.trustStore.location`, `ssl.trustStore.password` for communication with ClickHouse client over SSL. These options are available from Zookeeper version 3.5.2.
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ sidebar_position: 58
|
|||||||
sidebar_label: Usage Recommendations
|
sidebar_label: Usage Recommendations
|
||||||
title: "Usage Recommendations"
|
title: "Usage Recommendations"
|
||||||
---
|
---
|
||||||
|
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_automated.md';
|
||||||
|
|
||||||
|
<SelfManaged />
|
||||||
|
|
||||||
## CPU Scaling Governor
|
## CPU Scaling Governor
|
||||||
|
|
||||||
|
@ -294,6 +294,53 @@ Result:
|
|||||||
|
|
||||||
Notice how only a portion of the data was properly decrypted, and the rest is gibberish since either `mode`, `key`, or `iv` were different upon encryption.
|
Notice how only a portion of the data was properly decrypted, and the rest is gibberish since either `mode`, `key`, or `iv` were different upon encryption.
|
||||||
|
|
||||||
|
## tryDecrypt
|
||||||
|
|
||||||
|
Similar to `decrypt`, but returns NULL if decryption fails because of using the wrong key.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
Let's create a table where `user_id` is the unique user id, `encrypted` is an encrypted string field, `iv` is an initial vector for decrypt/encrypt. Assume that users know their id and the key to decrypt the encrypted field:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE decrypt_null (
|
||||||
|
dt DateTime,
|
||||||
|
user_id UInt32,
|
||||||
|
encrypted String,
|
||||||
|
iv String
|
||||||
|
) ENGINE = Memory;
|
||||||
|
```
|
||||||
|
|
||||||
|
Insert some data:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO decrypt_null VALUES
|
||||||
|
('2022-08-02 00:00:00', 1, encrypt('aes-256-gcm', 'value1', 'keykeykeykeykeykeykeykeykeykey01', 'iv1'), 'iv1'),
|
||||||
|
('2022-09-02 00:00:00', 2, encrypt('aes-256-gcm', 'value2', 'keykeykeykeykeykeykeykeykeykey02', 'iv2'), 'iv2'),
|
||||||
|
('2022-09-02 00:00:01', 3, encrypt('aes-256-gcm', 'value3', 'keykeykeykeykeykeykeykeykeykey03', 'iv3'), 'iv3');
|
||||||
|
```
|
||||||
|
|
||||||
|
Query:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
dt,
|
||||||
|
user_id,
|
||||||
|
tryDecrypt('aes-256-gcm', encrypted, 'keykeykeykeykeykeykeykeykeykey02', iv) AS value
|
||||||
|
FROM decrypt_null
|
||||||
|
ORDER BY user_id ASC
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────dt─┬─user_id─┬─value──┐
|
||||||
|
│ 2022-08-02 00:00:00 │ 1 │ ᴺᵁᴸᴸ │
|
||||||
|
│ 2022-09-02 00:00:00 │ 2 │ value2 │
|
||||||
|
│ 2022-09-02 00:00:01 │ 3 │ ᴺᵁᴸᴸ │
|
||||||
|
└─────────────────────┴─────────┴────────┘
|
||||||
|
```
|
||||||
|
|
||||||
## aes_decrypt_mysql
|
## aes_decrypt_mysql
|
||||||
|
|
||||||
Compatible with mysql encryption and decrypts data encrypted with [AES_ENCRYPT](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-encrypt) function.
|
Compatible with mysql encryption and decrypts data encrypted with [AES_ENCRYPT](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_aes-encrypt) function.
|
||||||
|
@ -10,7 +10,7 @@ Creates new [roles](../../../operations/access-rights.md#role-management). Role
|
|||||||
Syntax:
|
Syntax:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE ROLE [IF NOT EXISTS | OR REPLACE] name1 [, name2 ...]
|
CREATE ROLE [IF NOT EXISTS | OR REPLACE] name1 [ON CLUSTER cluster_name1] [, name2 [ON CLUSTER cluster_name2] ...]
|
||||||
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]
|
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ Creates a new view. Views can be [normal](#normal-view), [materialized](#materia
|
|||||||
Syntax:
|
Syntax:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER] AS SELECT ...
|
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] AS SELECT ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Normal views do not store any data. They just perform a read from another table on each access. In other words, a normal view is nothing more than a saved query. When reading from a view, this saved query is used as a subquery in the [FROM](../../../sql-reference/statements/select/from.md) clause.
|
Normal views do not store any data. They just perform a read from another table on each access. In other words, a normal view is nothing more than a saved query. When reading from a view, this saved query is used as a subquery in the [FROM](../../../sql-reference/statements/select/from.md) clause.
|
||||||
|
@ -430,9 +430,9 @@ FROM
|
|||||||
### Cumulative sum.
|
### Cumulative sum.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE events
|
CREATE TABLE warehouse
|
||||||
(
|
(
|
||||||
`metric` String,
|
`item` String,
|
||||||
`ts` DateTime,
|
`ts` DateTime,
|
||||||
`value` Float
|
`value` Float
|
||||||
)
|
)
|
||||||
|
@ -624,6 +624,7 @@ ClickHouse поддерживает динамическое изменение
|
|||||||
- `http_proxy` - Настройка HTTP proxy для отсылки отчетов о сбоях.
|
- `http_proxy` - Настройка HTTP proxy для отсылки отчетов о сбоях.
|
||||||
- `debug` - Настроить клиентскую библиотеку Sentry в debug режим.
|
- `debug` - Настроить клиентскую библиотеку Sentry в debug режим.
|
||||||
- `tmp_path` - Путь в файловой системе для временного хранения состояния отчетов о сбоях перед отправкой на сервер Sentry.
|
- `tmp_path` - Путь в файловой системе для временного хранения состояния отчетов о сбоях перед отправкой на сервер Sentry.
|
||||||
|
- `environment` - Произвольное название среды, в которой запущен сервер ClickHouse, которое будет упомянуто в каждом отчете от сбое. По умолчанию имеет значение `test` или `prod` в зависимости от версии ClickHouse.
|
||||||
|
|
||||||
**Рекомендованные настройки**
|
**Рекомендованные настройки**
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ sidebar_label: "Роль"
|
|||||||
Синтаксис:
|
Синтаксис:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE ROLE [IF NOT EXISTS | OR REPLACE] name1 [, name2 ...]
|
CREATE ROLE [IF NOT EXISTS | OR REPLACE] name1 [ON CLUSTER cluster_name1] [, name2 [ON CLUSTER cluster_name2] ...]
|
||||||
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]
|
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -47,4 +47,4 @@ SET ROLE accountant;
|
|||||||
SELECT * FROM db.*;
|
SELECT * FROM db.*;
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--hide-->
|
<!--hide-->
|
||||||
|
@ -11,7 +11,7 @@ sidebar_label: "Представление"
|
|||||||
## Обычные представления {#normal}
|
## Обычные представления {#normal}
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER] AS SELECT ...
|
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] AS SELECT ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Обычные представления не хранят никаких данных, они выполняют чтение данных из другой таблицы при каждом доступе. Другими словами, обычное представление — это не что иное, как сохраненный запрос. При чтении данных из представления этот сохраненный запрос используется как подзапрос в секции [FROM](../../../sql-reference/statements/select/from.md).
|
Обычные представления не хранят никаких данных, они выполняют чтение данных из другой таблицы при каждом доступе. Другими словами, обычное представление — это не что иное, как сохраненный запрос. При чтении данных из представления этот сохраненный запрос используется как подзапрос в секции [FROM](../../../sql-reference/statements/select/from.md).
|
||||||
|
@ -13,7 +13,7 @@ sidebar_label: VIEW
|
|||||||
语法:
|
语法:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER] AS SELECT ...
|
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] AS SELECT ...
|
||||||
```
|
```
|
||||||
|
|
||||||
普通视图不存储任何数据。 他们只是在每次访问时从另一个表执行读取。换句话说,普通视图只不过是一个保存的查询。 从视图中读取时,此保存的查询用作[FROM](../../../sql-reference/statements/select/from.md)子句中的子查询.
|
普通视图不存储任何数据。 他们只是在每次访问时从另一个表执行读取。换句话说,普通视图只不过是一个保存的查询。 从视图中读取时,此保存的查询用作[FROM](../../../sql-reference/statements/select/from.md)子句中的子查询.
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "Core/Protocol.h"
|
#include "Core/Protocol.h"
|
||||||
|
#include "Parsers/formatAST.h"
|
||||||
|
|
||||||
#include <base/find_symbols.h>
|
#include <base/find_symbols.h>
|
||||||
|
|
||||||
@ -514,6 +515,66 @@ static bool queryHasWithClause(const IAST & ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<bool> Client::processFuzzingStep(const String & query_to_execute, const ASTPtr & parsed_query)
|
||||||
|
{
|
||||||
|
processParsedSingleQuery(query_to_execute, query_to_execute, parsed_query);
|
||||||
|
|
||||||
|
const auto * exception = server_exception ? server_exception.get() : client_exception.get();
|
||||||
|
// Sometimes you may get TOO_DEEP_RECURSION from the server,
|
||||||
|
// and TOO_DEEP_RECURSION should not fail the fuzzer check.
|
||||||
|
if (have_error && exception->code() == ErrorCodes::TOO_DEEP_RECURSION)
|
||||||
|
{
|
||||||
|
have_error = false;
|
||||||
|
server_exception.reset();
|
||||||
|
client_exception.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_error)
|
||||||
|
{
|
||||||
|
fmt::print(stderr, "Error on processing query '{}': {}\n", parsed_query->formatForErrorMessage(), exception->message());
|
||||||
|
|
||||||
|
// Try to reconnect after errors, for two reasons:
|
||||||
|
// 1. We might not have realized that the server died, e.g. if
|
||||||
|
// it sent us a <Fatal> trace and closed connection properly.
|
||||||
|
// 2. The connection might have gotten into a wrong state and
|
||||||
|
// the next query will get false positive about
|
||||||
|
// "Unknown packet from server".
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection->forceConnected(connection_parameters.timeouts);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Just report it, we'll terminate below.
|
||||||
|
fmt::print(stderr,
|
||||||
|
"Error while reconnecting to the server: {}\n",
|
||||||
|
getCurrentExceptionMessage(true));
|
||||||
|
|
||||||
|
// The reconnection might fail, but we'll still be connected
|
||||||
|
// in the sense of `connection->isConnected() = true`,
|
||||||
|
// in case when the requested database doesn't exist.
|
||||||
|
// Disconnect manually now, so that the following code doesn't
|
||||||
|
// have any doubts, and the connection state is predictable.
|
||||||
|
connection->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connection->isConnected())
|
||||||
|
{
|
||||||
|
// Probably the server is dead because we found an assertion
|
||||||
|
// failure. Fail fast.
|
||||||
|
fmt::print(stderr, "Lost connection to the server.\n");
|
||||||
|
|
||||||
|
// Print the changed settings because they might be needed to
|
||||||
|
// reproduce the error.
|
||||||
|
printChangedSettings();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns false when server is not available.
|
/// Returns false when server is not available.
|
||||||
bool Client::processWithFuzzing(const String & full_query)
|
bool Client::processWithFuzzing(const String & full_query)
|
||||||
@ -558,18 +619,33 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
// - SET -- The time to fuzz the settings has not yet come
|
// - SET -- The time to fuzz the settings has not yet come
|
||||||
// (see comments in Client/QueryFuzzer.cpp)
|
// (see comments in Client/QueryFuzzer.cpp)
|
||||||
size_t this_query_runs = query_fuzzer_runs;
|
size_t this_query_runs = query_fuzzer_runs;
|
||||||
if (orig_ast->as<ASTInsertQuery>() ||
|
ASTs queries_for_fuzzed_tables;
|
||||||
orig_ast->as<ASTCreateQuery>() ||
|
|
||||||
orig_ast->as<ASTDropQuery>() ||
|
if (orig_ast->as<ASTSetQuery>())
|
||||||
orig_ast->as<ASTSetQuery>())
|
|
||||||
{
|
{
|
||||||
this_query_runs = 1;
|
this_query_runs = 1;
|
||||||
}
|
}
|
||||||
|
else if (const auto * create = orig_ast->as<ASTCreateQuery>())
|
||||||
|
{
|
||||||
|
if (QueryFuzzer::isSuitableForFuzzing(*create))
|
||||||
|
this_query_runs = create_query_fuzzer_runs;
|
||||||
|
else
|
||||||
|
this_query_runs = 1;
|
||||||
|
}
|
||||||
|
else if (const auto * insert = orig_ast->as<ASTInsertQuery>())
|
||||||
|
{
|
||||||
|
this_query_runs = 1;
|
||||||
|
queries_for_fuzzed_tables = fuzzer.getInsertQueriesForFuzzedTables(full_query);
|
||||||
|
}
|
||||||
|
else if (const auto * drop = orig_ast->as<ASTDropQuery>())
|
||||||
|
{
|
||||||
|
this_query_runs = 1;
|
||||||
|
queries_for_fuzzed_tables = fuzzer.getDropQueriesForFuzzedTables(*drop);
|
||||||
|
}
|
||||||
|
|
||||||
String query_to_execute;
|
String query_to_execute;
|
||||||
ASTPtr parsed_query;
|
|
||||||
|
|
||||||
ASTPtr fuzz_base = orig_ast;
|
ASTPtr fuzz_base = orig_ast;
|
||||||
|
|
||||||
for (size_t fuzz_step = 0; fuzz_step < this_query_runs; ++fuzz_step)
|
for (size_t fuzz_step = 0; fuzz_step < this_query_runs; ++fuzz_step)
|
||||||
{
|
{
|
||||||
fmt::print(stderr, "Fuzzing step {} out of {}\n", fuzz_step, this_query_runs);
|
fmt::print(stderr, "Fuzzing step {} out of {}\n", fuzz_step, this_query_runs);
|
||||||
@ -630,9 +706,9 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed_query = ast_to_process;
|
query_to_execute = ast_to_process->formatForErrorMessage();
|
||||||
query_to_execute = parsed_query->formatForErrorMessage();
|
if (auto res = processFuzzingStep(query_to_execute, ast_to_process))
|
||||||
processParsedSingleQuery(full_query, query_to_execute, parsed_query);
|
return *res;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -645,60 +721,6 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
have_error = true;
|
have_error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto * exception = server_exception ? server_exception.get() : client_exception.get();
|
|
||||||
// Sometimes you may get TOO_DEEP_RECURSION from the server,
|
|
||||||
// and TOO_DEEP_RECURSION should not fail the fuzzer check.
|
|
||||||
if (have_error && exception->code() == ErrorCodes::TOO_DEEP_RECURSION)
|
|
||||||
{
|
|
||||||
have_error = false;
|
|
||||||
server_exception.reset();
|
|
||||||
client_exception.reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_error)
|
|
||||||
{
|
|
||||||
fmt::print(stderr, "Error on processing query '{}': {}\n", ast_to_process->formatForErrorMessage(), exception->message());
|
|
||||||
|
|
||||||
// Try to reconnect after errors, for two reasons:
|
|
||||||
// 1. We might not have realized that the server died, e.g. if
|
|
||||||
// it sent us a <Fatal> trace and closed connection properly.
|
|
||||||
// 2. The connection might have gotten into a wrong state and
|
|
||||||
// the next query will get false positive about
|
|
||||||
// "Unknown packet from server".
|
|
||||||
try
|
|
||||||
{
|
|
||||||
connection->forceConnected(connection_parameters.timeouts);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
// Just report it, we'll terminate below.
|
|
||||||
fmt::print(stderr,
|
|
||||||
"Error while reconnecting to the server: {}\n",
|
|
||||||
getCurrentExceptionMessage(true));
|
|
||||||
|
|
||||||
// The reconnection might fail, but we'll still be connected
|
|
||||||
// in the sense of `connection->isConnected() = true`,
|
|
||||||
// in case when the requested database doesn't exist.
|
|
||||||
// Disconnect manually now, so that the following code doesn't
|
|
||||||
// have any doubts, and the connection state is predictable.
|
|
||||||
connection->disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connection->isConnected())
|
|
||||||
{
|
|
||||||
// Probably the server is dead because we found an assertion
|
|
||||||
// failure. Fail fast.
|
|
||||||
fmt::print(stderr, "Lost connection to the server.\n");
|
|
||||||
|
|
||||||
// Print the changed settings because they might be needed to
|
|
||||||
// reproduce the error.
|
|
||||||
printChangedSettings();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that after the query is formatted, we can parse it back,
|
// Check that after the query is formatted, we can parse it back,
|
||||||
// format again and get the same result. Unfortunately, we can't
|
// format again and get the same result. Unfortunately, we can't
|
||||||
// compare the ASTs, which would be more sensitive to errors. This
|
// compare the ASTs, which would be more sensitive to errors. This
|
||||||
@ -729,13 +751,12 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
// query, but second and third.
|
// query, but second and third.
|
||||||
// If you have to add any more workarounds to this check, just remove
|
// If you have to add any more workarounds to this check, just remove
|
||||||
// it altogether, it's not so useful.
|
// it altogether, it's not so useful.
|
||||||
if (parsed_query && !have_error && !queryHasWithClause(*parsed_query))
|
if (ast_to_process && !have_error && !queryHasWithClause(*ast_to_process))
|
||||||
{
|
{
|
||||||
ASTPtr ast_2;
|
ASTPtr ast_2;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto * tmp_pos = query_to_execute.c_str();
|
const auto * tmp_pos = query_to_execute.c_str();
|
||||||
|
|
||||||
ast_2 = parseQuery(tmp_pos, tmp_pos + query_to_execute.size(), false /* allow_multi_statements */);
|
ast_2 = parseQuery(tmp_pos, tmp_pos + query_to_execute.size(), false /* allow_multi_statements */);
|
||||||
}
|
}
|
||||||
catch (Exception & e)
|
catch (Exception & e)
|
||||||
@ -762,7 +783,7 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
"Got the following (different) text after formatting the fuzzed query and parsing it back:\n'{}'\n, expected:\n'{}'\n",
|
"Got the following (different) text after formatting the fuzzed query and parsing it back:\n'{}'\n, expected:\n'{}'\n",
|
||||||
text_3, text_2);
|
text_3, text_2);
|
||||||
fmt::print(stderr, "In more detail:\n");
|
fmt::print(stderr, "In more detail:\n");
|
||||||
fmt::print(stderr, "AST-1 (generated by fuzzer):\n'{}'\n", parsed_query->dumpTree());
|
fmt::print(stderr, "AST-1 (generated by fuzzer):\n'{}'\n", ast_to_process->dumpTree());
|
||||||
fmt::print(stderr, "Text-1 (AST-1 formatted):\n'{}'\n", query_to_execute);
|
fmt::print(stderr, "Text-1 (AST-1 formatted):\n'{}'\n", query_to_execute);
|
||||||
fmt::print(stderr, "AST-2 (Text-1 parsed):\n'{}'\n", ast_2->dumpTree());
|
fmt::print(stderr, "AST-2 (Text-1 parsed):\n'{}'\n", ast_2->dumpTree());
|
||||||
fmt::print(stderr, "Text-2 (AST-2 formatted):\n'{}'\n", text_2);
|
fmt::print(stderr, "Text-2 (AST-2 formatted):\n'{}'\n", text_2);
|
||||||
@ -784,6 +805,7 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
// so that it doesn't influence the exit code.
|
// so that it doesn't influence the exit code.
|
||||||
server_exception.reset();
|
server_exception.reset();
|
||||||
client_exception.reset();
|
client_exception.reset();
|
||||||
|
fuzzer.notifyQueryFailed(ast_to_process);
|
||||||
have_error = false;
|
have_error = false;
|
||||||
}
|
}
|
||||||
else if (ast_to_process->formatForErrorMessage().size() > 500)
|
else if (ast_to_process->formatForErrorMessage().size() > 500)
|
||||||
@ -800,6 +822,35 @@ bool Client::processWithFuzzing(const String & full_query)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto & query : queries_for_fuzzed_tables)
|
||||||
|
{
|
||||||
|
std::cout << std::endl;
|
||||||
|
WriteBufferFromOStream ast_buf(std::cout, 4096);
|
||||||
|
formatAST(*query, ast_buf, false /*highlight*/);
|
||||||
|
ast_buf.next();
|
||||||
|
std::cout << std::endl << std::endl;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
query_to_execute = query->formatForErrorMessage();
|
||||||
|
if (auto res = processFuzzingStep(query_to_execute, query))
|
||||||
|
return *res;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
client_exception = std::make_unique<Exception>(getCurrentExceptionMessage(print_stack_trace), getCurrentExceptionCode());
|
||||||
|
have_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_error)
|
||||||
|
{
|
||||||
|
server_exception.reset();
|
||||||
|
client_exception.reset();
|
||||||
|
fuzzer.notifyQueryFailed(query);
|
||||||
|
have_error = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,6 +885,7 @@ void Client::addOptions(OptionsDescription & options_description)
|
|||||||
("compression", po::value<bool>(), "enable or disable compression (enabled by default for remote communication and disabled for localhost communication).")
|
("compression", po::value<bool>(), "enable or disable compression (enabled by default for remote communication and disabled for localhost communication).")
|
||||||
|
|
||||||
("query-fuzzer-runs", po::value<int>()->default_value(0), "After executing every SELECT query, do random mutations in it and run again specified number of times. This is used for testing to discover unexpected corner cases.")
|
("query-fuzzer-runs", po::value<int>()->default_value(0), "After executing every SELECT query, do random mutations in it and run again specified number of times. This is used for testing to discover unexpected corner cases.")
|
||||||
|
("create-query-fuzzer-runs", po::value<int>()->default_value(0), "")
|
||||||
("interleave-queries-file", po::value<std::vector<std::string>>()->multitoken(),
|
("interleave-queries-file", po::value<std::vector<std::string>>()->multitoken(),
|
||||||
"file path with queries to execute before every file from 'queries-file'; multiple files can be specified (--queries-file file1 file2...); this is needed to enable more aggressive fuzzing of newly added tests (see 'query-fuzzer-runs' option)")
|
"file path with queries to execute before every file from 'queries-file'; multiple files can be specified (--queries-file file1 file2...); this is needed to enable more aggressive fuzzing of newly added tests (see 'query-fuzzer-runs' option)")
|
||||||
|
|
||||||
@ -994,6 +1046,17 @@ void Client::processOptions(const OptionsDescription & options_description,
|
|||||||
ignore_error = true;
|
ignore_error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((create_query_fuzzer_runs = options["create-query-fuzzer-runs"].as<int>()))
|
||||||
|
{
|
||||||
|
// Fuzzer implies multiquery.
|
||||||
|
config().setBool("multiquery", true);
|
||||||
|
// Ignore errors in parsing queries.
|
||||||
|
config().setBool("ignore-error", true);
|
||||||
|
|
||||||
|
global_context->setSetting("allow_suspicious_low_cardinality_types", true);
|
||||||
|
ignore_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.count("opentelemetry-traceparent"))
|
if (options.count("opentelemetry-traceparent"))
|
||||||
{
|
{
|
||||||
String traceparent = options["opentelemetry-traceparent"].as<std::string>();
|
String traceparent = options["opentelemetry-traceparent"].as<std::string>();
|
||||||
|
@ -17,6 +17,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool processWithFuzzing(const String & full_query) override;
|
bool processWithFuzzing(const String & full_query) override;
|
||||||
|
std::optional<bool> processFuzzingStep(const String & query_to_execute, const ASTPtr & parsed_query);
|
||||||
|
|
||||||
void connect() override;
|
void connect() override;
|
||||||
|
|
||||||
|
@ -927,7 +927,11 @@ namespace
|
|||||||
executable.string(), config.string(), pid_file.string());
|
executable.string(), config.string(), pid_file.string());
|
||||||
|
|
||||||
if (!user.empty())
|
if (!user.empty())
|
||||||
command = fmt::format("clickhouse su '{}' {}", user, command);
|
{
|
||||||
|
/// sudo respects limits in /etc/security/limits.conf e.g. open files,
|
||||||
|
/// that's why we are using it instead of the 'clickhouse su' tool.
|
||||||
|
command = fmt::format("sudo -u '{}' {}", user, command);
|
||||||
|
}
|
||||||
|
|
||||||
fmt::print("Will run {}\n", command);
|
fmt::print("Will run {}\n", command);
|
||||||
executeScript(command, true);
|
executeScript(command, true);
|
||||||
|
4
rust/BLAKE3/CMakeLists.txt
Executable file
4
rust/BLAKE3/CMakeLists.txt
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
corrosion_import_crate(MANIFEST_PATH Cargo.toml NO_STD)
|
||||||
|
|
||||||
|
target_include_directories(_ch_rust_blake3 INTERFACE include)
|
||||||
|
add_library(ch_rust::blake3 ALIAS _ch_rust_blake3)
|
92
rust/BLAKE3/Cargo.lock
generated
Normal file
92
rust/BLAKE3/Cargo.lock
generated
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "_ch_rust_blake3"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake3",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake3"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "526c210b4520e416420759af363083471656e819a75e831b8d2c9d5a584f2413"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"arrayvec",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"constant_time_eq",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.132"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
13
rust/BLAKE3/Cargo.toml
Normal file
13
rust/BLAKE3/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "_ch_rust_blake3"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
blake3 = "1.2.0"
|
||||||
|
libc = "0.2.132"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
17
rust/BLAKE3/include/blake3.h
Normal file
17
rust/BLAKE3/include/blake3.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef BLAKE3_H
|
||||||
|
#define BLAKE3_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
char *blake3_apply_shim(const char *begin, uint32_t _size, uint8_t *out_char_data);
|
||||||
|
|
||||||
|
char *blake3_apply_shim_msan_compat(const char *begin, uint32_t size, uint8_t *out_char_data);
|
||||||
|
|
||||||
|
void blake3_free_char_pointer(char *ptr_to_free);
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif /* BLAKE3_H */
|
55
rust/BLAKE3/src/lib.rs
Normal file
55
rust/BLAKE3/src/lib.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
extern crate blake3;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn blake3_apply_shim(
|
||||||
|
begin: *const c_char,
|
||||||
|
_size: u32,
|
||||||
|
out_char_data: *mut u8,
|
||||||
|
) -> *mut c_char {
|
||||||
|
if begin.is_null() {
|
||||||
|
let err_str = CString::new("input was a null pointer").unwrap();
|
||||||
|
return err_str.into_raw();
|
||||||
|
}
|
||||||
|
let mut hasher = blake3::Hasher::new();
|
||||||
|
let input_bytes = CStr::from_ptr(begin);
|
||||||
|
let input_res = input_bytes.to_bytes();
|
||||||
|
hasher.update(input_res);
|
||||||
|
let mut reader = hasher.finalize_xof();
|
||||||
|
reader.fill(std::slice::from_raw_parts_mut(out_char_data, blake3::OUT_LEN));
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn blake3_apply_shim_msan_compat(
|
||||||
|
mut begin: *const c_char,
|
||||||
|
size: u32,
|
||||||
|
out_char_data: *mut u8,
|
||||||
|
) -> *mut c_char {
|
||||||
|
if begin.is_null() {
|
||||||
|
let err_str = CString::new("input was a null pointer").unwrap();
|
||||||
|
return err_str.into_raw();
|
||||||
|
}
|
||||||
|
libc::memset(out_char_data as *mut libc::c_void, 0, mem::size_of::<u8>());
|
||||||
|
let mut hasher = blake3::Hasher::new();
|
||||||
|
let mut vec = Vec::<u8>::new();
|
||||||
|
for _ in 0..size {
|
||||||
|
vec.push(*begin as u8);
|
||||||
|
begin = begin.add(1);
|
||||||
|
}
|
||||||
|
let input_res = vec.as_mut_slice();
|
||||||
|
hasher.update(input_res);
|
||||||
|
let mut reader = hasher.finalize_xof();
|
||||||
|
reader.fill(std::slice::from_raw_parts_mut(out_char_data, blake3::OUT_LEN));
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Freeing memory according to docs: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_raw
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn blake3_free_char_pointer(ptr_to_free: *mut c_char) {
|
||||||
|
std::mem::drop(CString::from_raw(ptr_to_free));
|
||||||
|
}
|
1
rust/CMakeLists.txt
Normal file
1
rust/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
add_subdirectory (BLAKE3)
|
@ -236,15 +236,8 @@ public:
|
|||||||
|
|
||||||
if constexpr (result_is_nullable)
|
if constexpr (result_is_nullable)
|
||||||
{
|
{
|
||||||
#ifdef __clang__
|
auto * aggregate_data_is_null_dst_value = b.CreateLoad(aggregate_data_dst_ptr->getType()->getPointerElementType(), aggregate_data_dst_ptr);
|
||||||
#pragma clang diagnostic push
|
auto * aggregate_data_is_null_src_value = b.CreateLoad(aggregate_data_src_ptr->getType()->getPointerElementType(), aggregate_data_src_ptr);
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
#endif
|
|
||||||
auto * aggregate_data_is_null_dst_value = b.CreateLoad(aggregate_data_dst_ptr);
|
|
||||||
auto * aggregate_data_is_null_src_value = b.CreateLoad(aggregate_data_src_ptr);
|
|
||||||
#ifdef __clang__
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto * is_src_null = nativeBoolCast(b, std::make_shared<DataTypeUInt8>(), aggregate_data_is_null_src_value);
|
auto * is_src_null = nativeBoolCast(b, std::make_shared<DataTypeUInt8>(), aggregate_data_is_null_src_value);
|
||||||
auto * is_null_result_value = b.CreateSelect(is_src_null, llvm::ConstantInt::get(b.getInt8Ty(), 1), aggregate_data_is_null_dst_value);
|
auto * is_null_result_value = b.CreateSelect(is_src_null, llvm::ConstantInt::get(b.getInt8Ty(), 1), aggregate_data_is_null_dst_value);
|
||||||
|
@ -32,7 +32,7 @@ struct RankCorrelationData : public StatisticalSample<Float64, Float64>
|
|||||||
std::tie(ranks_y, std::ignore) = computeRanksAndTieCorrection(this->y);
|
std::tie(ranks_y, std::ignore) = computeRanksAndTieCorrection(this->y);
|
||||||
|
|
||||||
/// Sizes can be non-equal due to skipped NaNs.
|
/// Sizes can be non-equal due to skipped NaNs.
|
||||||
const auto size = std::min(this->size_x, this->size_y);
|
const Float64 size = static_cast<Float64>(std::min(this->size_x, this->size_y));
|
||||||
|
|
||||||
/// Count d^2 sum
|
/// Count d^2 sum
|
||||||
Float64 answer = 0;
|
Float64 answer = 0;
|
||||||
|
@ -368,8 +368,6 @@ target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::re2_st)
|
|||||||
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::re2)
|
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::re2)
|
||||||
|
|
||||||
target_link_libraries(clickhouse_common_io
|
target_link_libraries(clickhouse_common_io
|
||||||
PRIVATE
|
|
||||||
${EXECINFO_LIBRARIES}
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
boost::program_options
|
boost::program_options
|
||||||
boost::system
|
boost::system
|
||||||
|
@ -251,6 +251,7 @@ protected:
|
|||||||
|
|
||||||
QueryFuzzer fuzzer;
|
QueryFuzzer fuzzer;
|
||||||
int query_fuzzer_runs = 0;
|
int query_fuzzer_runs = 0;
|
||||||
|
int create_query_fuzzer_runs = 0;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
#include "QueryFuzzer.h"
|
#include "QueryFuzzer.h"
|
||||||
|
#include <DataTypes/DataTypeArray.h>
|
||||||
|
#include <DataTypes/DataTypeFactory.h>
|
||||||
|
#include <DataTypes/DataTypeFixedString.h>
|
||||||
|
#include <DataTypes/DataTypeLowCardinality.h>
|
||||||
|
#include <DataTypes/DataTypeMap.h>
|
||||||
|
#include <DataTypes/DataTypeNullable.h>
|
||||||
|
#include <DataTypes/DataTypeTuple.h>
|
||||||
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
|
#include <DataTypes/DataTypesDecimal.h>
|
||||||
|
#include <DataTypes/IDataType.h>
|
||||||
|
#include <IO/ReadBufferFromString.h>
|
||||||
|
#include <IO/WriteHelpers.h>
|
||||||
|
#include <Parsers/ASTColumnDeclaration.h>
|
||||||
|
#include <Parsers/ASTCreateQuery.h>
|
||||||
|
#include <Parsers/IAST_fwd.h>
|
||||||
|
#include <Parsers/ParserDataType.h>
|
||||||
|
#include <Parsers/ParserInsertQuery.h>
|
||||||
|
#include <Parsers/ASTDropQuery.h>
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
@ -430,6 +448,303 @@ void QueryFuzzer::fuzzWindowFrame(ASTWindowDefinition & def)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QueryFuzzer::isSuitableForFuzzing(const ASTCreateQuery & create)
|
||||||
|
{
|
||||||
|
return create.columns_list && create.columns_list->columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryFuzzer::fuzzCreateQuery(ASTCreateQuery & create)
|
||||||
|
{
|
||||||
|
if (create.columns_list && create.columns_list->columns)
|
||||||
|
{
|
||||||
|
for (auto & ast : create.columns_list->columns->children)
|
||||||
|
{
|
||||||
|
if (auto * column = ast->as<ASTColumnDeclaration>())
|
||||||
|
{
|
||||||
|
fuzzColumnDeclaration(*column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create.storage && create.storage->engine)
|
||||||
|
{
|
||||||
|
/// Replace ReplicatedMergeTree to ordinary MergeTree
|
||||||
|
/// to avoid inconsistency of metadata in zookeeper.
|
||||||
|
auto & engine_name = create.storage->engine->name;
|
||||||
|
if (startsWith(engine_name, "Replicated"))
|
||||||
|
{
|
||||||
|
engine_name = engine_name.substr(strlen("Replicated"));
|
||||||
|
if (auto & arguments = create.storage->engine->arguments)
|
||||||
|
{
|
||||||
|
auto & children = arguments->children;
|
||||||
|
if (children.size() <= 2)
|
||||||
|
arguments.reset();
|
||||||
|
else
|
||||||
|
children.erase(children.begin(), children.begin() + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto full_name = create.getTable();
|
||||||
|
auto original_name = full_name.substr(0, full_name.find("__fuzz_"));
|
||||||
|
|
||||||
|
size_t index = index_of_fuzzed_table[original_name]++;
|
||||||
|
auto new_name = original_name + "__fuzz_" + toString(index);
|
||||||
|
|
||||||
|
create.setTable(new_name);
|
||||||
|
|
||||||
|
SipHash sip_hash;
|
||||||
|
sip_hash.update(original_name);
|
||||||
|
if (create.columns_list)
|
||||||
|
create.columns_list->updateTreeHash(sip_hash);
|
||||||
|
if (create.storage)
|
||||||
|
create.storage->updateTreeHash(sip_hash);
|
||||||
|
|
||||||
|
IAST::Hash hash;
|
||||||
|
sip_hash.get128(hash);
|
||||||
|
|
||||||
|
/// Save only tables with unique definition.
|
||||||
|
if (created_tables_hashes.insert(hash).second)
|
||||||
|
original_table_name_to_fuzzed[original_name].insert(new_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryFuzzer::fuzzColumnDeclaration(ASTColumnDeclaration & column)
|
||||||
|
{
|
||||||
|
if (column.type)
|
||||||
|
{
|
||||||
|
auto data_type = fuzzDataType(DataTypeFactory::instance().get(column.type));
|
||||||
|
|
||||||
|
ParserDataType parser;
|
||||||
|
column.type = parseQuery(parser, data_type->getName(), DBMS_DEFAULT_MAX_QUERY_SIZE, DBMS_DEFAULT_MAX_PARSER_DEPTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePtr QueryFuzzer::fuzzDataType(DataTypePtr type)
|
||||||
|
{
|
||||||
|
/// Do not replace Array/Tuple/etc. with not Array/Tuple too often.
|
||||||
|
const auto * type_array = typeid_cast<const DataTypeArray *>(type.get());
|
||||||
|
if (type_array && fuzz_rand() % 4 != 0)
|
||||||
|
return std::make_shared<DataTypeArray>(fuzzDataType(type_array->getNestedType()));
|
||||||
|
|
||||||
|
const auto * type_tuple = typeid_cast<const DataTypeTuple *>(type.get());
|
||||||
|
if (type_tuple && fuzz_rand() % 4 != 0)
|
||||||
|
{
|
||||||
|
DataTypes elements;
|
||||||
|
for (const auto & element : type_tuple->getElements())
|
||||||
|
elements.push_back(fuzzDataType(element));
|
||||||
|
|
||||||
|
return type_tuple->haveExplicitNames()
|
||||||
|
? std::make_shared<DataTypeTuple>(elements, type_tuple->getElementNames())
|
||||||
|
: std::make_shared<DataTypeTuple>(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto * type_map = typeid_cast<const DataTypeMap *>(type.get());
|
||||||
|
if (type_map && fuzz_rand() % 4 != 0)
|
||||||
|
{
|
||||||
|
auto key_type = fuzzDataType(type_map->getKeyType());
|
||||||
|
auto value_type = fuzzDataType(type_map->getValueType());
|
||||||
|
if (!DataTypeMap::checkKeyType(key_type))
|
||||||
|
key_type = type_map->getKeyType();
|
||||||
|
|
||||||
|
return std::make_shared<DataTypeMap>(key_type, value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto * type_nullable = typeid_cast<const DataTypeNullable *>(type.get());
|
||||||
|
if (type_nullable)
|
||||||
|
{
|
||||||
|
size_t tmp = fuzz_rand() % 3;
|
||||||
|
if (tmp == 0)
|
||||||
|
return fuzzDataType(type_nullable->getNestedType());
|
||||||
|
|
||||||
|
if (tmp == 1)
|
||||||
|
{
|
||||||
|
auto nested_type = fuzzDataType(type_nullable->getNestedType());
|
||||||
|
if (nested_type->canBeInsideNullable())
|
||||||
|
return std::make_shared<DataTypeNullable>(nested_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto * type_low_cardinality = typeid_cast<const DataTypeLowCardinality *>(type.get());
|
||||||
|
if (type_low_cardinality)
|
||||||
|
{
|
||||||
|
size_t tmp = fuzz_rand() % 3;
|
||||||
|
if (tmp == 0)
|
||||||
|
return fuzzDataType(type_low_cardinality->getDictionaryType());
|
||||||
|
|
||||||
|
if (tmp == 1)
|
||||||
|
{
|
||||||
|
auto nested_type = fuzzDataType(type_low_cardinality->getDictionaryType());
|
||||||
|
if (nested_type->canBeInsideLowCardinality())
|
||||||
|
return std::make_shared<DataTypeLowCardinality>(nested_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t tmp = fuzz_rand() % 8;
|
||||||
|
if (tmp == 0)
|
||||||
|
return std::make_shared<DataTypeArray>(type);
|
||||||
|
|
||||||
|
if (tmp <= 1 && type->canBeInsideNullable())
|
||||||
|
return std::make_shared<DataTypeNullable>(type);
|
||||||
|
|
||||||
|
if (tmp <= 2 && type->canBeInsideLowCardinality())
|
||||||
|
return std::make_shared<DataTypeLowCardinality>(type);
|
||||||
|
|
||||||
|
if (tmp <= 3)
|
||||||
|
return getRandomType();
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePtr QueryFuzzer::getRandomType()
|
||||||
|
{
|
||||||
|
auto type_id = static_cast<TypeIndex>(fuzz_rand() % static_cast<size_t>(TypeIndex::Tuple) + 1);
|
||||||
|
|
||||||
|
if (type_id == TypeIndex::Tuple)
|
||||||
|
{
|
||||||
|
size_t tuple_size = fuzz_rand() % 6 + 1;
|
||||||
|
DataTypes elements;
|
||||||
|
for (size_t i = 0; i < tuple_size; ++i)
|
||||||
|
elements.push_back(getRandomType());
|
||||||
|
return std::make_shared<DataTypeTuple>(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_id == TypeIndex::Array)
|
||||||
|
return std::make_shared<DataTypeArray>(getRandomType());
|
||||||
|
|
||||||
|
/// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||||
|
#define DISPATCH(DECIMAL) \
|
||||||
|
if (type_id == TypeIndex::DECIMAL) \
|
||||||
|
return std::make_shared<DataTypeDecimal<DECIMAL>>( \
|
||||||
|
DataTypeDecimal<DECIMAL>::maxPrecision(), \
|
||||||
|
(fuzz_rand() % DataTypeDecimal<DECIMAL>::maxPrecision()) + 1);
|
||||||
|
|
||||||
|
DISPATCH(Decimal32)
|
||||||
|
DISPATCH(Decimal64)
|
||||||
|
DISPATCH(Decimal128)
|
||||||
|
DISPATCH(Decimal256)
|
||||||
|
#undef DISPATCH
|
||||||
|
/// NOLINTEND(bugprone-macro-parentheses)
|
||||||
|
|
||||||
|
if (type_id == TypeIndex::FixedString)
|
||||||
|
return std::make_shared<DataTypeFixedString>(fuzz_rand() % 20);
|
||||||
|
|
||||||
|
if (type_id == TypeIndex::Enum8)
|
||||||
|
return std::make_shared<DataTypeUInt8>();
|
||||||
|
|
||||||
|
if (type_id == TypeIndex::Enum16)
|
||||||
|
return std::make_shared<DataTypeUInt16>();
|
||||||
|
|
||||||
|
return DataTypeFactory::instance().get(String(magic_enum::enum_name(type_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryFuzzer::fuzzTableName(ASTTableExpression & table)
|
||||||
|
{
|
||||||
|
if (!table.database_and_table_name || fuzz_rand() % 3 == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto * identifier = table.database_and_table_name->as<ASTTableIdentifier>();
|
||||||
|
if (!identifier)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto table_id = identifier->getTableId();
|
||||||
|
if (table_id.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto it = original_table_name_to_fuzzed.find(table_id.getTableName());
|
||||||
|
if (it != original_table_name_to_fuzzed.end() && !it->second.empty())
|
||||||
|
{
|
||||||
|
auto new_table_name = it->second.begin();
|
||||||
|
std::advance(new_table_name, fuzz_rand() % it->second.size());
|
||||||
|
StorageID new_table_id(table_id.database_name, *new_table_name);
|
||||||
|
table.database_and_table_name = std::make_shared<ASTTableIdentifier>(new_table_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ASTPtr tryParseInsertQuery(const String & full_query)
|
||||||
|
{
|
||||||
|
const char * pos = full_query.data();
|
||||||
|
const char * end = full_query.data() + full_query.size();
|
||||||
|
|
||||||
|
ParserInsertQuery parser(end, false);
|
||||||
|
String message;
|
||||||
|
|
||||||
|
return tryParseQuery(parser, pos, end, message, false, "", false, DBMS_DEFAULT_MAX_QUERY_SIZE, DBMS_DEFAULT_MAX_PARSER_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTs QueryFuzzer::getInsertQueriesForFuzzedTables(const String & full_query)
|
||||||
|
{
|
||||||
|
auto parsed_query = tryParseInsertQuery(full_query);
|
||||||
|
if (!parsed_query)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto & insert = *parsed_query->as<ASTInsertQuery>();
|
||||||
|
if (!insert.table)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto table_name = insert.getTable();
|
||||||
|
auto it = original_table_name_to_fuzzed.find(table_name);
|
||||||
|
if (it == original_table_name_to_fuzzed.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
ASTs queries;
|
||||||
|
for (const auto & fuzzed_name : it->second)
|
||||||
|
{
|
||||||
|
/// Parse query from scratch for each table instead of clone,
|
||||||
|
/// to store proper pointers to inlined data,
|
||||||
|
/// which are not copied during clone.
|
||||||
|
auto & query = queries.emplace_back(tryParseInsertQuery(full_query));
|
||||||
|
query->as<ASTInsertQuery>()->setTable(fuzzed_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTs QueryFuzzer::getDropQueriesForFuzzedTables(const ASTDropQuery & drop_query)
|
||||||
|
{
|
||||||
|
if (drop_query.kind != ASTDropQuery::Drop)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto table_name = drop_query.getTable();
|
||||||
|
auto it = index_of_fuzzed_table.find(table_name);
|
||||||
|
if (it == index_of_fuzzed_table.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
ASTs queries;
|
||||||
|
/// Drop all created tables, not only unique ones.
|
||||||
|
for (size_t i = 0; i < it->second; ++i)
|
||||||
|
{
|
||||||
|
auto fuzzed_name = table_name + "__fuzz_" + toString(i);
|
||||||
|
auto & query = queries.emplace_back(drop_query.clone());
|
||||||
|
query->as<ASTDropQuery>()->setTable(fuzzed_name);
|
||||||
|
/// Just in case add IF EXISTS to avoid exceptions.
|
||||||
|
query->as<ASTDropQuery>()->if_exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
index_of_fuzzed_table.erase(it);
|
||||||
|
original_table_name_to_fuzzed.erase(table_name);
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryFuzzer::notifyQueryFailed(ASTPtr ast)
|
||||||
|
{
|
||||||
|
auto remove_fuzzed_table = [this](const auto & table_name)
|
||||||
|
{
|
||||||
|
auto pos = table_name.find("__fuzz_");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
auto original_name = table_name.substr(0, pos);
|
||||||
|
original_table_name_to_fuzzed[original_name].erase(table_name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (const auto * create = ast->as<ASTCreateQuery>())
|
||||||
|
remove_fuzzed_table(create->getTable());
|
||||||
|
|
||||||
|
if (const auto * insert = ast->as<ASTInsertQuery>())
|
||||||
|
remove_fuzzed_table(insert->getTable());
|
||||||
|
}
|
||||||
|
|
||||||
void QueryFuzzer::fuzz(ASTs & asts)
|
void QueryFuzzer::fuzz(ASTs & asts)
|
||||||
{
|
{
|
||||||
for (auto & ast : asts)
|
for (auto & ast : asts)
|
||||||
@ -497,6 +812,7 @@ void QueryFuzzer::fuzz(ASTPtr & ast)
|
|||||||
}
|
}
|
||||||
else if (auto * table_expr = typeid_cast<ASTTableExpression *>(ast.get()))
|
else if (auto * table_expr = typeid_cast<ASTTableExpression *>(ast.get()))
|
||||||
{
|
{
|
||||||
|
fuzzTableName(*table_expr);
|
||||||
fuzz(table_expr->children);
|
fuzz(table_expr->children);
|
||||||
}
|
}
|
||||||
else if (auto * expr_list = typeid_cast<ASTExpressionList *>(ast.get()))
|
else if (auto * expr_list = typeid_cast<ASTExpressionList *>(ast.get()))
|
||||||
@ -563,6 +879,10 @@ void QueryFuzzer::fuzz(ASTPtr & ast)
|
|||||||
literal->value = fuzzField(literal->value);
|
literal->value = fuzzField(literal->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (auto * create_query = typeid_cast<ASTCreateQuery *>(ast.get()))
|
||||||
|
{
|
||||||
|
fuzzCreateQuery(*create_query);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fuzz(ast->children);
|
fuzz(ast->children);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <DataTypes/IDataType.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -16,6 +17,11 @@ namespace DB
|
|||||||
|
|
||||||
class ASTExpressionList;
|
class ASTExpressionList;
|
||||||
class ASTOrderByElement;
|
class ASTOrderByElement;
|
||||||
|
class ASTCreateQuery;
|
||||||
|
class ASTInsertQuery;
|
||||||
|
class ASTColumnDeclaration;
|
||||||
|
class ASTDropQuery;
|
||||||
|
struct ASTTableExpression;
|
||||||
struct ASTWindowDefinition;
|
struct ASTWindowDefinition;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -54,6 +60,9 @@ struct QueryFuzzer
|
|||||||
std::unordered_set<const IAST *> debug_visited_nodes;
|
std::unordered_set<const IAST *> debug_visited_nodes;
|
||||||
ASTPtr * debug_top_ast = nullptr;
|
ASTPtr * debug_top_ast = nullptr;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unordered_set<std::string>> original_table_name_to_fuzzed;
|
||||||
|
std::unordered_map<std::string, size_t> index_of_fuzzed_table;
|
||||||
|
std::set<IAST::Hash> created_tables_hashes;
|
||||||
|
|
||||||
// This is the only function you have to call -- it will modify the passed
|
// This is the only function you have to call -- it will modify the passed
|
||||||
// ASTPtr to point to new AST with some random changes.
|
// ASTPtr to point to new AST with some random changes.
|
||||||
@ -63,18 +72,28 @@ struct QueryFuzzer
|
|||||||
Field getRandomField(int type);
|
Field getRandomField(int type);
|
||||||
Field fuzzField(Field field);
|
Field fuzzField(Field field);
|
||||||
ASTPtr getRandomColumnLike();
|
ASTPtr getRandomColumnLike();
|
||||||
|
DataTypePtr fuzzDataType(DataTypePtr type);
|
||||||
|
DataTypePtr getRandomType();
|
||||||
|
ASTs getInsertQueriesForFuzzedTables(const String & full_query);
|
||||||
|
ASTs getDropQueriesForFuzzedTables(const ASTDropQuery & drop_query);
|
||||||
|
void notifyQueryFailed(ASTPtr ast);
|
||||||
void replaceWithColumnLike(ASTPtr & ast);
|
void replaceWithColumnLike(ASTPtr & ast);
|
||||||
void replaceWithTableLike(ASTPtr & ast);
|
void replaceWithTableLike(ASTPtr & ast);
|
||||||
void fuzzOrderByElement(ASTOrderByElement * elem);
|
void fuzzOrderByElement(ASTOrderByElement * elem);
|
||||||
void fuzzOrderByList(IAST * ast);
|
void fuzzOrderByList(IAST * ast);
|
||||||
void fuzzColumnLikeExpressionList(IAST * ast);
|
void fuzzColumnLikeExpressionList(IAST * ast);
|
||||||
void fuzzWindowFrame(ASTWindowDefinition & def);
|
void fuzzWindowFrame(ASTWindowDefinition & def);
|
||||||
|
void fuzzCreateQuery(ASTCreateQuery & create);
|
||||||
|
void fuzzColumnDeclaration(ASTColumnDeclaration & column);
|
||||||
|
void fuzzTableName(ASTTableExpression & table);
|
||||||
void fuzz(ASTs & asts);
|
void fuzz(ASTs & asts);
|
||||||
void fuzz(ASTPtr & ast);
|
void fuzz(ASTPtr & ast);
|
||||||
void collectFuzzInfoMain(ASTPtr ast);
|
void collectFuzzInfoMain(ASTPtr ast);
|
||||||
void addTableLike(ASTPtr ast);
|
void addTableLike(ASTPtr ast);
|
||||||
void addColumnLike(ASTPtr ast);
|
void addColumnLike(ASTPtr ast);
|
||||||
void collectFuzzInfoRecurse(ASTPtr ast);
|
void collectFuzzInfoRecurse(ASTPtr ast);
|
||||||
|
|
||||||
|
static bool isSuitableForFuzzing(const ASTCreateQuery & create);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ void ColumnAggregateFunction::insertRangeFrom(const IColumn & from, size_t start
|
|||||||
|
|
||||||
size_t end = start + length;
|
size_t end = start + length;
|
||||||
for (size_t i = start; i < end; ++i)
|
for (size_t i = start; i < end; ++i)
|
||||||
insertFrom(from, i);
|
insertFromWithOwnership(from, i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -448,7 +448,7 @@ void ColumnAggregateFunction::insertData(const char * pos, size_t /*length*/)
|
|||||||
data.push_back(*reinterpret_cast<const AggregateDataPtr *>(pos));
|
data.push_back(*reinterpret_cast<const AggregateDataPtr *>(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColumnAggregateFunction::insertFrom(const IColumn & from, size_t n)
|
void ColumnAggregateFunction::insertFromWithOwnership(const IColumn & from, size_t n)
|
||||||
{
|
{
|
||||||
/// Must create new state of aggregate function and take ownership of it,
|
/// Must create new state of aggregate function and take ownership of it,
|
||||||
/// because ownership of states of aggregate function cannot be shared for individual rows,
|
/// because ownership of states of aggregate function cannot be shared for individual rows,
|
||||||
@ -458,6 +458,11 @@ void ColumnAggregateFunction::insertFrom(const IColumn & from, size_t n)
|
|||||||
insertMergeFrom(from, n);
|
insertMergeFrom(from, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColumnAggregateFunction::insertFrom(const IColumn & from, size_t n)
|
||||||
|
{
|
||||||
|
insertRangeFrom(from, n, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void ColumnAggregateFunction::insertFrom(ConstAggregateDataPtr place)
|
void ColumnAggregateFunction::insertFrom(ConstAggregateDataPtr place)
|
||||||
{
|
{
|
||||||
ensureOwnership();
|
ensureOwnership();
|
||||||
|
@ -98,6 +98,8 @@ private:
|
|||||||
|
|
||||||
ColumnAggregateFunction(const ColumnAggregateFunction & src_);
|
ColumnAggregateFunction(const ColumnAggregateFunction & src_);
|
||||||
|
|
||||||
|
void insertFromWithOwnership(const IColumn & from, size_t n);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~ColumnAggregateFunction() override;
|
~ColumnAggregateFunction() override;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <base/types.h>
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Common/ZooKeeper/IKeeper.h>
|
#include <base/types.h>
|
||||||
#include <Poco/Event.h>
|
#include <Poco/Event.h>
|
||||||
|
#include <Common/ZooKeeper/IKeeper.h>
|
||||||
|
|
||||||
|
|
||||||
namespace zkutil
|
namespace zkutil
|
||||||
@ -34,4 +34,9 @@ Coordination::RequestPtr makeRemoveRequest(const std::string & path, int version
|
|||||||
Coordination::RequestPtr makeSetRequest(const std::string & path, const std::string & data, int version);
|
Coordination::RequestPtr makeSetRequest(const std::string & path, const std::string & data, int version);
|
||||||
Coordination::RequestPtr makeCheckRequest(const std::string & path, int version);
|
Coordination::RequestPtr makeCheckRequest(const std::string & path, int version);
|
||||||
|
|
||||||
|
Coordination::RequestPtr makeGetRequest(const std::string & path);
|
||||||
|
Coordination::RequestPtr
|
||||||
|
makeListRequest(const std::string & path, Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
||||||
|
Coordination::RequestPtr makeSimpleListRequest(const std::string & path);
|
||||||
|
Coordination::RequestPtr makeExistsRequest(const std::string & path);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <Common/ZooKeeper/Types.h>
|
||||||
|
#include <Common/ZooKeeper/ZooKeeperCommon.h>
|
||||||
#include <Common/randomSeed.h>
|
#include <Common/randomSeed.h>
|
||||||
#include <base/find_symbols.h>
|
#include <base/find_symbols.h>
|
||||||
#include <base/sort.h>
|
#include <base/sort.h>
|
||||||
@ -989,6 +991,24 @@ std::future<Coordination::ListResponse> ZooKeeper::asyncTryGetChildrenNoThrow(
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::future<Coordination::ListResponse>
|
||||||
|
ZooKeeper::asyncTryGetChildren(const std::string & path, Coordination::ListRequestType list_request_type)
|
||||||
|
{
|
||||||
|
auto promise = std::make_shared<std::promise<Coordination::ListResponse>>();
|
||||||
|
auto future = promise->get_future();
|
||||||
|
|
||||||
|
auto callback = [promise, path](const Coordination::ListResponse & response) mutable
|
||||||
|
{
|
||||||
|
if (response.error != Coordination::Error::ZOK && response.error != Coordination::Error::ZNONODE)
|
||||||
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
|
else
|
||||||
|
promise->set_value(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
impl->list(path, list_request_type, std::move(callback), {});
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
std::future<Coordination::RemoveResponse> ZooKeeper::asyncRemove(const std::string & path, int32_t version)
|
std::future<Coordination::RemoveResponse> ZooKeeper::asyncRemove(const std::string & path, int32_t version)
|
||||||
{
|
{
|
||||||
auto promise = std::make_shared<std::promise<Coordination::RemoveResponse>>();
|
auto promise = std::make_shared<std::promise<Coordination::RemoveResponse>>();
|
||||||
@ -1207,6 +1227,37 @@ Coordination::RequestPtr makeCheckRequest(const std::string & path, int version)
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Coordination::RequestPtr makeGetRequest(const std::string & path)
|
||||||
|
{
|
||||||
|
auto request = std::make_shared<Coordination::GetRequest>();
|
||||||
|
request->path = path;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordination::RequestPtr makeListRequest(const std::string & path, Coordination::ListRequestType list_request_type)
|
||||||
|
{
|
||||||
|
// Keeper server that support MultiRead also support FilteredList
|
||||||
|
auto request = std::make_shared<Coordination::ZooKeeperFilteredListRequest>();
|
||||||
|
request->path = path;
|
||||||
|
request->list_request_type = list_request_type;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordination::RequestPtr makeSimpleListRequest(const std::string & path)
|
||||||
|
{
|
||||||
|
auto request = std::make_shared<Coordination::ZooKeeperSimpleListRequest>();
|
||||||
|
request->path = path;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordination::RequestPtr makeExistsRequest(const std::string & path)
|
||||||
|
{
|
||||||
|
auto request = std::make_shared<Coordination::ZooKeeperExistsRequest>();
|
||||||
|
request->path = path;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string normalizeZooKeeperPath(std::string zookeeper_path, bool check_starts_with_slash, Poco::Logger * log)
|
std::string normalizeZooKeeperPath(std::string zookeeper_path, bool check_starts_with_slash, Poco::Logger * log)
|
||||||
{
|
{
|
||||||
if (!zookeeper_path.empty() && zookeeper_path.back() == '/')
|
if (!zookeeper_path.empty() && zookeeper_path.back() == '/')
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <Common/CurrentMetrics.h>
|
#include <Common/CurrentMetrics.h>
|
||||||
#include <Common/Stopwatch.h>
|
#include <Common/Stopwatch.h>
|
||||||
#include <Common/ZooKeeper/IKeeper.h>
|
#include <Common/ZooKeeper/IKeeper.h>
|
||||||
|
#include <Common/ZooKeeper/KeeperException.h>
|
||||||
#include <Common/ZooKeeper/ZooKeeperConstants.h>
|
#include <Common/ZooKeeper/ZooKeeperConstants.h>
|
||||||
#include <Common/ZooKeeper/ZooKeeperArgs.h>
|
#include <Common/ZooKeeper/ZooKeeperArgs.h>
|
||||||
#include <Common/thread_local_rng.h>
|
#include <Common/thread_local_rng.h>
|
||||||
@ -72,6 +73,63 @@ struct RemoveException
|
|||||||
|
|
||||||
using GetPriorityForLoadBalancing = DB::GetPriorityForLoadBalancing;
|
using GetPriorityForLoadBalancing = DB::GetPriorityForLoadBalancing;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept ZooKeeperResponse = std::derived_from<T, Coordination::Response>;
|
||||||
|
|
||||||
|
template <ZooKeeperResponse ResponseType>
|
||||||
|
struct MultiReadResponses
|
||||||
|
{
|
||||||
|
template <typename TResponses>
|
||||||
|
explicit MultiReadResponses(TResponses responses_) : responses(std::move(responses_))
|
||||||
|
{}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return std::visit([](auto && resp) { return resp.size(); }, responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseType & operator[](size_t index)
|
||||||
|
{
|
||||||
|
return std::visit(
|
||||||
|
[&]<typename TResponses>(TResponses & resp) -> ResponseType &
|
||||||
|
{
|
||||||
|
if constexpr (std::same_as<TResponses, RegularResponses>)
|
||||||
|
return dynamic_cast<ResponseType &>(*resp[index]);
|
||||||
|
else
|
||||||
|
return resp[index];
|
||||||
|
},
|
||||||
|
responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using RegularResponses = std::vector<Coordination::ResponsePtr>;
|
||||||
|
using FutureResponses = std::vector<std::future<ResponseType>>;
|
||||||
|
|
||||||
|
struct ResponsesWithFutures
|
||||||
|
{
|
||||||
|
ResponsesWithFutures(FutureResponses future_responses_) : future_responses(std::move(future_responses_))
|
||||||
|
{
|
||||||
|
cached_responses.resize(future_responses.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureResponses future_responses;
|
||||||
|
std::vector<std::optional<ResponseType>> cached_responses;
|
||||||
|
|
||||||
|
ResponseType & operator[](size_t index)
|
||||||
|
{
|
||||||
|
if (cached_responses[index].has_value())
|
||||||
|
return *cached_responses[index];
|
||||||
|
|
||||||
|
cached_responses[index] = future_responses[index].get();
|
||||||
|
return *cached_responses[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return future_responses.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::variant<RegularResponses, ResponsesWithFutures> responses;
|
||||||
|
};
|
||||||
|
|
||||||
/// ZooKeeper session. The interface is substantially different from the usual libzookeeper API.
|
/// ZooKeeper session. The interface is substantially different from the usual libzookeeper API.
|
||||||
///
|
///
|
||||||
/// Poco::Event objects are used for watches. The event is set only once on the first
|
/// Poco::Event objects are used for watches. The event is set only once on the first
|
||||||
@ -89,7 +147,6 @@ public:
|
|||||||
|
|
||||||
ZooKeeper(const ZooKeeperArgs & args_, std::shared_ptr<DB::ZooKeeperLog> zk_log_ = nullptr);
|
ZooKeeper(const ZooKeeperArgs & args_, std::shared_ptr<DB::ZooKeeperLog> zk_log_ = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/** Config of the form:
|
/** Config of the form:
|
||||||
<zookeeper>
|
<zookeeper>
|
||||||
<node>
|
<node>
|
||||||
@ -160,16 +217,63 @@ public:
|
|||||||
bool exists(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
bool exists(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
||||||
bool existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
bool existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
||||||
|
|
||||||
|
using MultiExistsResponse = MultiReadResponses<Coordination::ExistsResponse>;
|
||||||
|
template <typename TIter>
|
||||||
|
MultiExistsResponse exists(TIter start, TIter end)
|
||||||
|
{
|
||||||
|
return multiRead<Coordination::ExistsResponse, true>(
|
||||||
|
start, end, zkutil::makeExistsRequest, [&](const auto & path) { return asyncExists(path); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiExistsResponse exists(const std::vector<std::string> & paths)
|
||||||
|
{
|
||||||
|
return exists(paths.begin(), paths.end());
|
||||||
|
}
|
||||||
|
|
||||||
std::string get(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
std::string get(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
||||||
std::string getWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
std::string getWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
||||||
|
|
||||||
|
using MultiGetResponse = MultiReadResponses<Coordination::GetResponse>;
|
||||||
|
|
||||||
|
template <typename TIter>
|
||||||
|
MultiGetResponse get(TIter start, TIter end)
|
||||||
|
{
|
||||||
|
return multiRead<Coordination::GetResponse, false>(
|
||||||
|
start, end, zkutil::makeGetRequest, [&](const auto & path) { return asyncGet(path); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiGetResponse get(const std::vector<std::string> & paths)
|
||||||
|
{
|
||||||
|
return get(paths.begin(), paths.end());
|
||||||
|
}
|
||||||
|
|
||||||
/// Doesn't not throw in the following cases:
|
/// Doesn't not throw in the following cases:
|
||||||
/// * The node doesn't exist. Returns false in this case.
|
/// * The node doesn't exist. Returns false in this case.
|
||||||
bool tryGet(const std::string & path, std::string & res, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr,
|
bool tryGet(
|
||||||
Coordination::Error * code = nullptr);
|
const std::string & path,
|
||||||
|
std::string & res,
|
||||||
|
Coordination::Stat * stat = nullptr,
|
||||||
|
const EventPtr & watch = nullptr,
|
||||||
|
Coordination::Error * code = nullptr);
|
||||||
|
|
||||||
bool tryGetWatch(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback,
|
bool tryGetWatch(
|
||||||
Coordination::Error * code = nullptr);
|
const std::string & path,
|
||||||
|
std::string & res,
|
||||||
|
Coordination::Stat * stat,
|
||||||
|
Coordination::WatchCallback watch_callback,
|
||||||
|
Coordination::Error * code = nullptr);
|
||||||
|
|
||||||
|
template <typename TIter>
|
||||||
|
MultiGetResponse tryGet(TIter start, TIter end)
|
||||||
|
{
|
||||||
|
return multiRead<Coordination::GetResponse, true>(
|
||||||
|
start, end, zkutil::makeGetRequest, [&](const auto & path) { return asyncTryGet(path); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiGetResponse tryGet(const std::vector<std::string> & paths)
|
||||||
|
{
|
||||||
|
return tryGet(paths.begin(), paths.end());
|
||||||
|
}
|
||||||
|
|
||||||
void set(const std::string & path, const std::string & data,
|
void set(const std::string & path, const std::string & data,
|
||||||
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
||||||
@ -193,17 +297,57 @@ public:
|
|||||||
Coordination::WatchCallback watch_callback,
|
Coordination::WatchCallback watch_callback,
|
||||||
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
||||||
|
|
||||||
|
using MultiGetChildrenResponse = MultiReadResponses<Coordination::ListResponse>;
|
||||||
|
|
||||||
|
template <typename TIter>
|
||||||
|
MultiGetChildrenResponse
|
||||||
|
getChildren(TIter start, TIter end, Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL)
|
||||||
|
{
|
||||||
|
return multiRead<Coordination::ListResponse, false>(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
[list_request_type](const auto & path) { return zkutil::makeListRequest(path, list_request_type); },
|
||||||
|
[&](const auto & path) { return asyncGetChildren(path, {}, list_request_type); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiGetChildrenResponse
|
||||||
|
getChildren(const std::vector<std::string> & paths, Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL)
|
||||||
|
{
|
||||||
|
return getChildren(paths.begin(), paths.end(), list_request_type);
|
||||||
|
}
|
||||||
|
|
||||||
/// Doesn't not throw in the following cases:
|
/// Doesn't not throw in the following cases:
|
||||||
/// * The node doesn't exist.
|
/// * The node doesn't exist.
|
||||||
Coordination::Error tryGetChildren(const std::string & path, Strings & res,
|
Coordination::Error tryGetChildren(
|
||||||
Coordination::Stat * stat = nullptr,
|
const std::string & path,
|
||||||
const EventPtr & watch = nullptr,
|
Strings & res,
|
||||||
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
Coordination::Stat * stat = nullptr,
|
||||||
|
const EventPtr & watch = nullptr,
|
||||||
|
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
||||||
|
|
||||||
Coordination::Error tryGetChildrenWatch(const std::string & path, Strings & res,
|
Coordination::Error tryGetChildrenWatch(
|
||||||
Coordination::Stat * stat,
|
const std::string & path,
|
||||||
Coordination::WatchCallback watch_callback,
|
Strings & res,
|
||||||
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
Coordination::Stat * stat,
|
||||||
|
Coordination::WatchCallback watch_callback,
|
||||||
|
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
||||||
|
|
||||||
|
template <typename TIter>
|
||||||
|
MultiGetChildrenResponse
|
||||||
|
tryGetChildren(TIter start, TIter end, Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL)
|
||||||
|
{
|
||||||
|
return multiRead<Coordination::ListResponse, true>(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
[list_request_type](const auto & path) { return zkutil::makeListRequest(path, list_request_type); },
|
||||||
|
[&](const auto & path) { return asyncTryGetChildren(path, list_request_type); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiGetChildrenResponse
|
||||||
|
tryGetChildren(const std::vector<std::string> & paths, Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL)
|
||||||
|
{
|
||||||
|
return tryGetChildren(paths.begin(), paths.end(), list_request_type);
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs several operations in a transaction.
|
/// Performs several operations in a transaction.
|
||||||
/// Throws on every error.
|
/// Throws on every error.
|
||||||
@ -327,6 +471,12 @@ public:
|
|||||||
/// * The node doesn't exist
|
/// * The node doesn't exist
|
||||||
FutureGet asyncTryGet(const std::string & path);
|
FutureGet asyncTryGet(const std::string & path);
|
||||||
|
|
||||||
|
/// Doesn't throw in the following cases:
|
||||||
|
/// * The node doesn't exist
|
||||||
|
FutureGetChildren asyncTryGetChildren(
|
||||||
|
const std::string & path,
|
||||||
|
Coordination::ListRequestType list_request_type = Coordination::ListRequestType::ALL);
|
||||||
|
|
||||||
void finalize(const String & reason);
|
void finalize(const String & reason);
|
||||||
|
|
||||||
void setZooKeeperLog(std::shared_ptr<DB::ZooKeeperLog> zk_log_);
|
void setZooKeeperLog(std::shared_ptr<DB::ZooKeeperLog> zk_log_);
|
||||||
@ -354,6 +504,46 @@ private:
|
|||||||
Coordination::Error existsImpl(const std::string & path, Coordination::Stat * stat_, Coordination::WatchCallback watch_callback);
|
Coordination::Error existsImpl(const std::string & path, Coordination::Stat * stat_, Coordination::WatchCallback watch_callback);
|
||||||
Coordination::Error syncImpl(const std::string & path, std::string & returned_path);
|
Coordination::Error syncImpl(const std::string & path, std::string & returned_path);
|
||||||
|
|
||||||
|
using RequestFactory = std::function<Coordination::RequestPtr(const std::string &)>;
|
||||||
|
template <typename TResponse>
|
||||||
|
using AsyncFunction = std::function<std::future<TResponse>(const std::string &)>;
|
||||||
|
|
||||||
|
template <typename TResponse, bool try_multi, typename TIter>
|
||||||
|
MultiReadResponses<TResponse> multiRead(TIter start, TIter end, RequestFactory request_factory, AsyncFunction<TResponse> async_fun)
|
||||||
|
{
|
||||||
|
if (getApiVersion() >= DB::KeeperApiVersion::WITH_MULTI_READ)
|
||||||
|
{
|
||||||
|
Coordination::Requests requests;
|
||||||
|
for (auto it = start; it != end; ++it)
|
||||||
|
requests.push_back(request_factory(*it));
|
||||||
|
|
||||||
|
if constexpr (try_multi)
|
||||||
|
{
|
||||||
|
Coordination::Responses responses;
|
||||||
|
tryMulti(requests, responses);
|
||||||
|
return MultiReadResponses<TResponse>{std::move(responses)};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto responses = multi(requests);
|
||||||
|
return MultiReadResponses<TResponse>{std::move(responses)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto responses_size = std::distance(start, end);
|
||||||
|
std::vector<std::future<TResponse>> future_responses;
|
||||||
|
|
||||||
|
if (responses_size == 0)
|
||||||
|
return MultiReadResponses<TResponse>(std::move(future_responses));
|
||||||
|
|
||||||
|
future_responses.reserve(responses_size);
|
||||||
|
|
||||||
|
for (auto it = start; it != end; ++it)
|
||||||
|
future_responses.push_back(async_fun(*it));
|
||||||
|
|
||||||
|
return MultiReadResponses<TResponse>{std::move(future_responses)};
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Coordination::IKeeper> impl;
|
std::unique_ptr<Coordination::IKeeper> impl;
|
||||||
|
|
||||||
ZooKeeperArgs args;
|
ZooKeeperArgs args;
|
||||||
|
@ -337,6 +337,15 @@ void ZooKeeperListResponse::writeImpl(WriteBuffer & out) const
|
|||||||
Coordination::write(stat, out);
|
Coordination::write(stat, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZooKeeperSimpleListResponse::readImpl(ReadBuffer & in)
|
||||||
|
{
|
||||||
|
Coordination::read(names, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZooKeeperSimpleListResponse::writeImpl(WriteBuffer & out) const
|
||||||
|
{
|
||||||
|
Coordination::write(names, out);
|
||||||
|
}
|
||||||
|
|
||||||
void ZooKeeperSetACLRequest::writeImpl(WriteBuffer & out) const
|
void ZooKeeperSetACLRequest::writeImpl(WriteBuffer & out) const
|
||||||
{
|
{
|
||||||
@ -426,16 +435,29 @@ void ZooKeeperErrorResponse::writeImpl(WriteBuffer & out) const
|
|||||||
Coordination::write(error, out);
|
Coordination::write(error, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZooKeeperMultiRequest::checkOperationType(OperationType type)
|
||||||
|
{
|
||||||
|
chassert(!operation_type.has_value() || *operation_type == type);
|
||||||
|
operation_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpNum ZooKeeperMultiRequest::getOpNum() const
|
||||||
|
{
|
||||||
|
return !operation_type.has_value() || *operation_type == OperationType::Write ? OpNum::Multi : OpNum::MultiRead;
|
||||||
|
}
|
||||||
|
|
||||||
ZooKeeperMultiRequest::ZooKeeperMultiRequest(const Requests & generic_requests, const ACLs & default_acls)
|
ZooKeeperMultiRequest::ZooKeeperMultiRequest(const Requests & generic_requests, const ACLs & default_acls)
|
||||||
{
|
{
|
||||||
/// Convert nested Requests to ZooKeeperRequests.
|
/// Convert nested Requests to ZooKeeperRequests.
|
||||||
/// Note that deep copy is required to avoid modifying path in presence of chroot prefix.
|
/// Note that deep copy is required to avoid modifying path in presence of chroot prefix.
|
||||||
requests.reserve(generic_requests.size());
|
requests.reserve(generic_requests.size());
|
||||||
|
|
||||||
|
using enum OperationType;
|
||||||
for (const auto & generic_request : generic_requests)
|
for (const auto & generic_request : generic_requests)
|
||||||
{
|
{
|
||||||
if (const auto * concrete_request_create = dynamic_cast<const CreateRequest *>(generic_request.get()))
|
if (const auto * concrete_request_create = dynamic_cast<const CreateRequest *>(generic_request.get()))
|
||||||
{
|
{
|
||||||
|
checkOperationType(Write);
|
||||||
auto create = std::make_shared<ZooKeeperCreateRequest>(*concrete_request_create);
|
auto create = std::make_shared<ZooKeeperCreateRequest>(*concrete_request_create);
|
||||||
if (create->acls.empty())
|
if (create->acls.empty())
|
||||||
create->acls = default_acls;
|
create->acls = default_acls;
|
||||||
@ -443,16 +465,39 @@ ZooKeeperMultiRequest::ZooKeeperMultiRequest(const Requests & generic_requests,
|
|||||||
}
|
}
|
||||||
else if (const auto * concrete_request_remove = dynamic_cast<const RemoveRequest *>(generic_request.get()))
|
else if (const auto * concrete_request_remove = dynamic_cast<const RemoveRequest *>(generic_request.get()))
|
||||||
{
|
{
|
||||||
|
checkOperationType(Write);
|
||||||
requests.push_back(std::make_shared<ZooKeeperRemoveRequest>(*concrete_request_remove));
|
requests.push_back(std::make_shared<ZooKeeperRemoveRequest>(*concrete_request_remove));
|
||||||
}
|
}
|
||||||
else if (const auto * concrete_request_set = dynamic_cast<const SetRequest *>(generic_request.get()))
|
else if (const auto * concrete_request_set = dynamic_cast<const SetRequest *>(generic_request.get()))
|
||||||
{
|
{
|
||||||
|
checkOperationType(Write);
|
||||||
requests.push_back(std::make_shared<ZooKeeperSetRequest>(*concrete_request_set));
|
requests.push_back(std::make_shared<ZooKeeperSetRequest>(*concrete_request_set));
|
||||||
}
|
}
|
||||||
else if (const auto * concrete_request_check = dynamic_cast<const CheckRequest *>(generic_request.get()))
|
else if (const auto * concrete_request_check = dynamic_cast<const CheckRequest *>(generic_request.get()))
|
||||||
{
|
{
|
||||||
|
checkOperationType(Write);
|
||||||
requests.push_back(std::make_shared<ZooKeeperCheckRequest>(*concrete_request_check));
|
requests.push_back(std::make_shared<ZooKeeperCheckRequest>(*concrete_request_check));
|
||||||
}
|
}
|
||||||
|
else if (const auto * concrete_request_get = dynamic_cast<const GetRequest *>(generic_request.get()))
|
||||||
|
{
|
||||||
|
checkOperationType(Read);
|
||||||
|
requests.push_back(std::make_shared<ZooKeeperGetRequest>(*concrete_request_get));
|
||||||
|
}
|
||||||
|
else if (const auto * concrete_request_exists = dynamic_cast<const ExistsRequest *>(generic_request.get()))
|
||||||
|
{
|
||||||
|
checkOperationType(Read);
|
||||||
|
requests.push_back(std::make_shared<ZooKeeperExistsRequest>(*concrete_request_exists));
|
||||||
|
}
|
||||||
|
else if (const auto * concrete_request_simple_list = dynamic_cast<const ZooKeeperSimpleListRequest *>(generic_request.get()))
|
||||||
|
{
|
||||||
|
checkOperationType(Read);
|
||||||
|
requests.push_back(std::make_shared<ZooKeeperSimpleListRequest>(*concrete_request_simple_list));
|
||||||
|
}
|
||||||
|
else if (const auto * concrete_request_list = dynamic_cast<const ZooKeeperFilteredListRequest *>(generic_request.get()))
|
||||||
|
{
|
||||||
|
checkOperationType(Read);
|
||||||
|
requests.push_back(std::make_shared<ZooKeeperFilteredListRequest>(*concrete_request_list));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw Exception("Illegal command as part of multi ZooKeeper request", Error::ZBADARGUMENTS);
|
throw Exception("Illegal command as part of multi ZooKeeper request", Error::ZBADARGUMENTS);
|
||||||
}
|
}
|
||||||
@ -526,8 +571,7 @@ std::string ZooKeeperMultiRequest::toStringImpl() const
|
|||||||
|
|
||||||
bool ZooKeeperMultiRequest::isReadRequest() const
|
bool ZooKeeperMultiRequest::isReadRequest() const
|
||||||
{
|
{
|
||||||
/// Possibly we can do better
|
return getOpNum() == OpNum::MultiRead;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZooKeeperMultiResponse::readImpl(ReadBuffer & in)
|
void ZooKeeperMultiResponse::readImpl(ReadBuffer & in)
|
||||||
@ -622,8 +666,18 @@ ZooKeeperResponsePtr ZooKeeperExistsRequest::makeResponse() const { return setTi
|
|||||||
ZooKeeperResponsePtr ZooKeeperGetRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperGetResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperGetRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperGetResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperSetRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperSetResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperSetRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperSetResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperListRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperListResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperListRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperListResponse>()); }
|
||||||
|
ZooKeeperResponsePtr ZooKeeperSimpleListRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperSimpleListResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperCheckRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperCheckResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperCheckRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperCheckResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperMultiRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperMultiResponse>(requests)); }
|
ZooKeeperResponsePtr ZooKeeperMultiRequest::makeResponse() const
|
||||||
|
{
|
||||||
|
std::shared_ptr<ZooKeeperMultiResponse> response;
|
||||||
|
if (getOpNum() == OpNum::Multi)
|
||||||
|
response = std::make_shared<ZooKeeperMultiWriteResponse>(requests);
|
||||||
|
else
|
||||||
|
response = std::make_shared<ZooKeeperMultiReadResponse>(requests);
|
||||||
|
|
||||||
|
return setTime(std::move(response));
|
||||||
|
}
|
||||||
ZooKeeperResponsePtr ZooKeeperCloseRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperCloseResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperCloseRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperCloseResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperSetACLRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperSetACLResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperSetACLRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperSetACLResponse>()); }
|
||||||
ZooKeeperResponsePtr ZooKeeperGetACLRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperGetACLResponse>()); }
|
ZooKeeperResponsePtr ZooKeeperGetACLRequest::makeResponse() const { return setTime(std::make_shared<ZooKeeperGetACLResponse>()); }
|
||||||
@ -873,6 +927,12 @@ void registerZooKeeperRequest(ZooKeeperRequestFactory & factory)
|
|||||||
{
|
{
|
||||||
auto res = std::make_shared<RequestT>();
|
auto res = std::make_shared<RequestT>();
|
||||||
res->request_created_time_ns = clock_gettime_ns();
|
res->request_created_time_ns = clock_gettime_ns();
|
||||||
|
|
||||||
|
if constexpr (num == OpNum::MultiRead)
|
||||||
|
res->operation_type = ZooKeeperMultiRequest::OperationType::Read;
|
||||||
|
else if constexpr (num == OpNum::Multi)
|
||||||
|
res->operation_type = ZooKeeperMultiRequest::OperationType::Write;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -892,6 +952,7 @@ ZooKeeperRequestFactory::ZooKeeperRequestFactory()
|
|||||||
registerZooKeeperRequest<OpNum::List, ZooKeeperListRequest>(*this);
|
registerZooKeeperRequest<OpNum::List, ZooKeeperListRequest>(*this);
|
||||||
registerZooKeeperRequest<OpNum::Check, ZooKeeperCheckRequest>(*this);
|
registerZooKeeperRequest<OpNum::Check, ZooKeeperCheckRequest>(*this);
|
||||||
registerZooKeeperRequest<OpNum::Multi, ZooKeeperMultiRequest>(*this);
|
registerZooKeeperRequest<OpNum::Multi, ZooKeeperMultiRequest>(*this);
|
||||||
|
registerZooKeeperRequest<OpNum::MultiRead, ZooKeeperMultiRequest>(*this);
|
||||||
registerZooKeeperRequest<OpNum::SessionID, ZooKeeperSessionIDRequest>(*this);
|
registerZooKeeperRequest<OpNum::SessionID, ZooKeeperSessionIDRequest>(*this);
|
||||||
registerZooKeeperRequest<OpNum::GetACL, ZooKeeperGetACLRequest>(*this);
|
registerZooKeeperRequest<OpNum::GetACL, ZooKeeperGetACLRequest>(*this);
|
||||||
registerZooKeeperRequest<OpNum::SetACL, ZooKeeperSetACLRequest>(*this);
|
registerZooKeeperRequest<OpNum::SetACL, ZooKeeperSetACLRequest>(*this);
|
||||||
|
@ -257,6 +257,9 @@ struct ZooKeeperRemoveResponse final : RemoveResponse, ZooKeeperResponse
|
|||||||
|
|
||||||
struct ZooKeeperExistsRequest final : ExistsRequest, ZooKeeperRequest
|
struct ZooKeeperExistsRequest final : ExistsRequest, ZooKeeperRequest
|
||||||
{
|
{
|
||||||
|
ZooKeeperExistsRequest() = default;
|
||||||
|
explicit ZooKeeperExistsRequest(const ExistsRequest & base) : ExistsRequest(base) {}
|
||||||
|
|
||||||
OpNum getOpNum() const override { return OpNum::Exists; }
|
OpNum getOpNum() const override { return OpNum::Exists; }
|
||||||
void writeImpl(WriteBuffer & out) const override;
|
void writeImpl(WriteBuffer & out) const override;
|
||||||
void readImpl(ReadBuffer & in) override;
|
void readImpl(ReadBuffer & in) override;
|
||||||
@ -281,6 +284,9 @@ struct ZooKeeperExistsResponse final : ExistsResponse, ZooKeeperResponse
|
|||||||
|
|
||||||
struct ZooKeeperGetRequest final : GetRequest, ZooKeeperRequest
|
struct ZooKeeperGetRequest final : GetRequest, ZooKeeperRequest
|
||||||
{
|
{
|
||||||
|
ZooKeeperGetRequest() = default;
|
||||||
|
explicit ZooKeeperGetRequest(const GetRequest & base) : GetRequest(base) {}
|
||||||
|
|
||||||
OpNum getOpNum() const override { return OpNum::Get; }
|
OpNum getOpNum() const override { return OpNum::Get; }
|
||||||
void writeImpl(WriteBuffer & out) const override;
|
void writeImpl(WriteBuffer & out) const override;
|
||||||
void readImpl(ReadBuffer & in) override;
|
void readImpl(ReadBuffer & in) override;
|
||||||
@ -333,6 +339,9 @@ struct ZooKeeperSetResponse final : SetResponse, ZooKeeperResponse
|
|||||||
|
|
||||||
struct ZooKeeperListRequest : ListRequest, ZooKeeperRequest
|
struct ZooKeeperListRequest : ListRequest, ZooKeeperRequest
|
||||||
{
|
{
|
||||||
|
ZooKeeperListRequest() = default;
|
||||||
|
explicit ZooKeeperListRequest(const ListRequest & base) : ListRequest(base) {}
|
||||||
|
|
||||||
OpNum getOpNum() const override { return OpNum::List; }
|
OpNum getOpNum() const override { return OpNum::List; }
|
||||||
void writeImpl(WriteBuffer & out) const override;
|
void writeImpl(WriteBuffer & out) const override;
|
||||||
void readImpl(ReadBuffer & in) override;
|
void readImpl(ReadBuffer & in) override;
|
||||||
@ -346,6 +355,7 @@ struct ZooKeeperListRequest : ListRequest, ZooKeeperRequest
|
|||||||
struct ZooKeeperSimpleListRequest final : ZooKeeperListRequest
|
struct ZooKeeperSimpleListRequest final : ZooKeeperListRequest
|
||||||
{
|
{
|
||||||
OpNum getOpNum() const override { return OpNum::SimpleList; }
|
OpNum getOpNum() const override { return OpNum::SimpleList; }
|
||||||
|
ZooKeeperResponsePtr makeResponse() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZooKeeperFilteredListRequest final : ZooKeeperListRequest
|
struct ZooKeeperFilteredListRequest final : ZooKeeperListRequest
|
||||||
@ -373,7 +383,11 @@ struct ZooKeeperListResponse : ListResponse, ZooKeeperResponse
|
|||||||
|
|
||||||
struct ZooKeeperSimpleListResponse final : ZooKeeperListResponse
|
struct ZooKeeperSimpleListResponse final : ZooKeeperListResponse
|
||||||
{
|
{
|
||||||
|
void readImpl(ReadBuffer & in) override;
|
||||||
|
void writeImpl(WriteBuffer & out) const override;
|
||||||
OpNum getOpNum() const override { return OpNum::SimpleList; }
|
OpNum getOpNum() const override { return OpNum::SimpleList; }
|
||||||
|
|
||||||
|
size_t bytesSize() const override { return ZooKeeperListResponse::bytesSize() - sizeof(stat); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZooKeeperCheckRequest final : CheckRequest, ZooKeeperRequest
|
struct ZooKeeperCheckRequest final : CheckRequest, ZooKeeperRequest
|
||||||
@ -458,7 +472,7 @@ struct ZooKeeperGetACLResponse final : GetACLResponse, ZooKeeperResponse
|
|||||||
|
|
||||||
struct ZooKeeperMultiRequest final : MultiRequest, ZooKeeperRequest
|
struct ZooKeeperMultiRequest final : MultiRequest, ZooKeeperRequest
|
||||||
{
|
{
|
||||||
OpNum getOpNum() const override { return OpNum::Multi; }
|
OpNum getOpNum() const override;
|
||||||
ZooKeeperMultiRequest() = default;
|
ZooKeeperMultiRequest() = default;
|
||||||
|
|
||||||
ZooKeeperMultiRequest(const Requests & generic_requests, const ACLs & default_acls);
|
ZooKeeperMultiRequest(const Requests & generic_requests, const ACLs & default_acls);
|
||||||
@ -473,12 +487,20 @@ struct ZooKeeperMultiRequest final : MultiRequest, ZooKeeperRequest
|
|||||||
size_t bytesSize() const override { return MultiRequest::bytesSize() + sizeof(xid) + sizeof(has_watch); }
|
size_t bytesSize() const override { return MultiRequest::bytesSize() + sizeof(xid) + sizeof(has_watch); }
|
||||||
|
|
||||||
void createLogElements(LogElements & elems) const override;
|
void createLogElements(LogElements & elems) const override;
|
||||||
|
|
||||||
|
enum class OperationType : UInt8
|
||||||
|
{
|
||||||
|
Read,
|
||||||
|
Write
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<OperationType> operation_type;
|
||||||
|
private:
|
||||||
|
void checkOperationType(OperationType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZooKeeperMultiResponse final : MultiResponse, ZooKeeperResponse
|
struct ZooKeeperMultiResponse : MultiResponse, ZooKeeperResponse
|
||||||
{
|
{
|
||||||
OpNum getOpNum() const override { return OpNum::Multi; }
|
|
||||||
|
|
||||||
explicit ZooKeeperMultiResponse(const Requests & requests)
|
explicit ZooKeeperMultiResponse(const Requests & requests)
|
||||||
{
|
{
|
||||||
responses.reserve(requests.size());
|
responses.reserve(requests.size());
|
||||||
@ -501,6 +523,18 @@ struct ZooKeeperMultiResponse final : MultiResponse, ZooKeeperResponse
|
|||||||
void fillLogElements(LogElements & elems, size_t idx) const override;
|
void fillLogElements(LogElements & elems, size_t idx) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZooKeeperMultiWriteResponse final : public ZooKeeperMultiResponse
|
||||||
|
{
|
||||||
|
OpNum getOpNum() const override { return OpNum::Multi; }
|
||||||
|
using ZooKeeperMultiResponse::ZooKeeperMultiResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZooKeeperMultiReadResponse final : public ZooKeeperMultiResponse
|
||||||
|
{
|
||||||
|
OpNum getOpNum() const override { return OpNum::MultiRead; }
|
||||||
|
using ZooKeeperMultiResponse::ZooKeeperMultiResponse;
|
||||||
|
};
|
||||||
|
|
||||||
/// Fake internal coordination (keeper) response. Never received from client
|
/// Fake internal coordination (keeper) response. Never received from client
|
||||||
/// and never send to client.
|
/// and never send to client.
|
||||||
struct ZooKeeperSessionIDRequest final : ZooKeeperRequest
|
struct ZooKeeperSessionIDRequest final : ZooKeeperRequest
|
||||||
|
@ -20,6 +20,7 @@ static const std::unordered_set<int32_t> VALID_OPERATIONS =
|
|||||||
static_cast<int32_t>(OpNum::List),
|
static_cast<int32_t>(OpNum::List),
|
||||||
static_cast<int32_t>(OpNum::Check),
|
static_cast<int32_t>(OpNum::Check),
|
||||||
static_cast<int32_t>(OpNum::Multi),
|
static_cast<int32_t>(OpNum::Multi),
|
||||||
|
static_cast<int32_t>(OpNum::MultiRead),
|
||||||
static_cast<int32_t>(OpNum::Auth),
|
static_cast<int32_t>(OpNum::Auth),
|
||||||
static_cast<int32_t>(OpNum::SessionID),
|
static_cast<int32_t>(OpNum::SessionID),
|
||||||
static_cast<int32_t>(OpNum::SetACL),
|
static_cast<int32_t>(OpNum::SetACL),
|
||||||
@ -53,6 +54,8 @@ std::string toString(OpNum op_num)
|
|||||||
return "Check";
|
return "Check";
|
||||||
case OpNum::Multi:
|
case OpNum::Multi:
|
||||||
return "Multi";
|
return "Multi";
|
||||||
|
case OpNum::MultiRead:
|
||||||
|
return "MultiRead";
|
||||||
case OpNum::Sync:
|
case OpNum::Sync:
|
||||||
return "Sync";
|
return "Sync";
|
||||||
case OpNum::Heartbeat:
|
case OpNum::Heartbeat:
|
||||||
|
@ -31,6 +31,7 @@ enum class OpNum : int32_t
|
|||||||
List = 12,
|
List = 12,
|
||||||
Check = 13,
|
Check = 13,
|
||||||
Multi = 14,
|
Multi = 14,
|
||||||
|
MultiRead = 22,
|
||||||
Auth = 100,
|
Auth = 100,
|
||||||
|
|
||||||
// CH Keeper specific operations
|
// CH Keeper specific operations
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include <Common/ZooKeeper/ZooKeeperCommon.h>
|
|
||||||
#include <Common/ZooKeeper/ZooKeeperImpl.h>
|
#include <Common/ZooKeeper/ZooKeeperImpl.h>
|
||||||
|
|
||||||
|
#include <Common/ZooKeeper/IKeeper.h>
|
||||||
|
#include <Common/ZooKeeper/ZooKeeperCommon.h>
|
||||||
#include <Common/ZooKeeper/ZooKeeperIO.h>
|
#include <Common/ZooKeeper/ZooKeeperIO.h>
|
||||||
#include <Common/Exception.h>
|
#include <Common/Exception.h>
|
||||||
#include <Common/EventNotifier.h>
|
#include <Common/EventNotifier.h>
|
||||||
@ -14,6 +16,7 @@
|
|||||||
#include <base/getThreadId.h>
|
#include <base/getThreadId.h>
|
||||||
|
|
||||||
#include <Common/config.h>
|
#include <Common/config.h>
|
||||||
|
#include "Coordination/KeeperConstants.h"
|
||||||
|
|
||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
# include <Poco/Net/SecureStreamSocket.h>
|
# include <Poco/Net/SecureStreamSocket.h>
|
||||||
@ -1298,6 +1301,9 @@ void ZooKeeper::multi(
|
|||||||
{
|
{
|
||||||
ZooKeeperMultiRequest request(requests, default_acls);
|
ZooKeeperMultiRequest request(requests, default_acls);
|
||||||
|
|
||||||
|
if (request.getOpNum() == OpNum::MultiRead && keeper_api_version < Coordination::KeeperApiVersion::WITH_MULTI_READ)
|
||||||
|
throw Exception(Error::ZBADARGUMENTS, "MultiRead request type cannot be used because it's not supported by the server");
|
||||||
|
|
||||||
RequestInfo request_info;
|
RequestInfo request_info;
|
||||||
request_info.request = std::make_shared<ZooKeeperMultiRequest>(std::move(request));
|
request_info.request = std::make_shared<ZooKeeperMultiRequest>(std::move(request));
|
||||||
request_info.callback = [callback](const Response & response) { callback(dynamic_cast<const MultiResponse &>(response)); };
|
request_info.callback = [callback](const Response & response) { callback(dynamic_cast<const MultiResponse &>(response)); };
|
||||||
|
@ -8,10 +8,11 @@ namespace DB
|
|||||||
enum class KeeperApiVersion : uint8_t
|
enum class KeeperApiVersion : uint8_t
|
||||||
{
|
{
|
||||||
ZOOKEEPER_COMPATIBLE = 0,
|
ZOOKEEPER_COMPATIBLE = 0,
|
||||||
WITH_FILTERED_LIST
|
WITH_FILTERED_LIST,
|
||||||
|
WITH_MULTI_READ
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto current_keeper_api_version = KeeperApiVersion::WITH_FILTERED_LIST;
|
inline constexpr auto current_keeper_api_version = KeeperApiVersion::WITH_MULTI_READ;
|
||||||
|
|
||||||
const std::string keeper_system_path = "/keeper";
|
const std::string keeper_system_path = "/keeper";
|
||||||
const std::string keeper_api_version_path = keeper_system_path + "/api_version";
|
const std::string keeper_api_version_path = keeper_system_path + "/api_version";
|
||||||
|
@ -1601,6 +1601,9 @@ struct KeeperStorageGetACLRequestProcessor final : public KeeperStorageRequestPr
|
|||||||
|
|
||||||
struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestProcessor
|
struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestProcessor
|
||||||
{
|
{
|
||||||
|
using OperationType = Coordination::ZooKeeperMultiRequest::OperationType;
|
||||||
|
std::optional<OperationType> operation_type;
|
||||||
|
|
||||||
bool checkAuth(KeeperStorage & storage, int64_t session_id, bool is_local) const override
|
bool checkAuth(KeeperStorage & storage, int64_t session_id, bool is_local) const override
|
||||||
{
|
{
|
||||||
for (const auto & concrete_request : concrete_requests)
|
for (const auto & concrete_request : concrete_requests)
|
||||||
@ -1616,28 +1619,55 @@ struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestPro
|
|||||||
Coordination::ZooKeeperMultiRequest & request = dynamic_cast<Coordination::ZooKeeperMultiRequest &>(*zk_request);
|
Coordination::ZooKeeperMultiRequest & request = dynamic_cast<Coordination::ZooKeeperMultiRequest &>(*zk_request);
|
||||||
concrete_requests.reserve(request.requests.size());
|
concrete_requests.reserve(request.requests.size());
|
||||||
|
|
||||||
|
const auto check_operation_type = [&](OperationType type)
|
||||||
|
{
|
||||||
|
if (operation_type.has_value() && *operation_type != type)
|
||||||
|
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "Illegal mixing of read and write operations in multi request");
|
||||||
|
operation_type = type;
|
||||||
|
};
|
||||||
|
|
||||||
for (const auto & sub_request : request.requests)
|
for (const auto & sub_request : request.requests)
|
||||||
{
|
{
|
||||||
auto sub_zk_request = std::dynamic_pointer_cast<Coordination::ZooKeeperRequest>(sub_request);
|
auto sub_zk_request = std::dynamic_pointer_cast<Coordination::ZooKeeperRequest>(sub_request);
|
||||||
switch (sub_zk_request->getOpNum())
|
switch (sub_zk_request->getOpNum())
|
||||||
{
|
{
|
||||||
case Coordination::OpNum::Create:
|
case Coordination::OpNum::Create:
|
||||||
|
check_operation_type(OperationType::Write);
|
||||||
concrete_requests.push_back(std::make_shared<KeeperStorageCreateRequestProcessor>(sub_zk_request));
|
concrete_requests.push_back(std::make_shared<KeeperStorageCreateRequestProcessor>(sub_zk_request));
|
||||||
break;
|
break;
|
||||||
case Coordination::OpNum::Remove:
|
case Coordination::OpNum::Remove:
|
||||||
|
check_operation_type(OperationType::Write);
|
||||||
concrete_requests.push_back(std::make_shared<KeeperStorageRemoveRequestProcessor>(sub_zk_request));
|
concrete_requests.push_back(std::make_shared<KeeperStorageRemoveRequestProcessor>(sub_zk_request));
|
||||||
break;
|
break;
|
||||||
case Coordination::OpNum::Set:
|
case Coordination::OpNum::Set:
|
||||||
|
check_operation_type(OperationType::Write);
|
||||||
concrete_requests.push_back(std::make_shared<KeeperStorageSetRequestProcessor>(sub_zk_request));
|
concrete_requests.push_back(std::make_shared<KeeperStorageSetRequestProcessor>(sub_zk_request));
|
||||||
break;
|
break;
|
||||||
case Coordination::OpNum::Check:
|
case Coordination::OpNum::Check:
|
||||||
|
check_operation_type(OperationType::Write);
|
||||||
concrete_requests.push_back(std::make_shared<KeeperStorageCheckRequestProcessor>(sub_zk_request));
|
concrete_requests.push_back(std::make_shared<KeeperStorageCheckRequestProcessor>(sub_zk_request));
|
||||||
break;
|
break;
|
||||||
|
case Coordination::OpNum::Get:
|
||||||
|
check_operation_type(OperationType::Read);
|
||||||
|
concrete_requests.push_back(std::make_shared<KeeperStorageGetRequestProcessor>(sub_zk_request));
|
||||||
|
break;
|
||||||
|
case Coordination::OpNum::Exists:
|
||||||
|
check_operation_type(OperationType::Read);
|
||||||
|
concrete_requests.push_back(std::make_shared<KeeperStorageExistsRequestProcessor>(sub_zk_request));
|
||||||
|
break;
|
||||||
|
case Coordination::OpNum::List:
|
||||||
|
case Coordination::OpNum::FilteredList:
|
||||||
|
case Coordination::OpNum::SimpleList:
|
||||||
|
check_operation_type(OperationType::Read);
|
||||||
|
concrete_requests.push_back(std::make_shared<KeeperStorageListRequestProcessor>(sub_zk_request));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw DB::Exception(
|
throw DB::Exception(
|
||||||
ErrorCodes::BAD_ARGUMENTS, "Illegal command as part of multi ZooKeeper request {}", sub_zk_request->getOpNum());
|
ErrorCodes::BAD_ARGUMENTS, "Illegal command as part of multi ZooKeeper request {}", sub_zk_request->getOpNum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(request.requests.empty() || operation_type.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KeeperStorage::Delta>
|
std::vector<KeeperStorage::Delta>
|
||||||
@ -1652,7 +1682,8 @@ struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestPro
|
|||||||
|
|
||||||
if (!new_deltas.empty())
|
if (!new_deltas.empty())
|
||||||
{
|
{
|
||||||
if (auto * error = std::get_if<KeeperStorage::ErrorDelta>(&new_deltas.back().operation))
|
if (auto * error = std::get_if<KeeperStorage::ErrorDelta>(&new_deltas.back().operation);
|
||||||
|
error && *operation_type == OperationType::Write)
|
||||||
{
|
{
|
||||||
storage.uncommitted_state.rollback(zxid);
|
storage.uncommitted_state.rollback(zxid);
|
||||||
response_errors.push_back(error->error);
|
response_errors.push_back(error->error);
|
||||||
@ -1699,8 +1730,7 @@ struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestPro
|
|||||||
|
|
||||||
for (size_t i = 0; i < concrete_requests.size(); ++i)
|
for (size_t i = 0; i < concrete_requests.size(); ++i)
|
||||||
{
|
{
|
||||||
auto cur_response = concrete_requests[i]->process(storage, zxid);
|
response.responses[i] = concrete_requests[i]->process(storage, zxid);
|
||||||
response.responses[i] = cur_response;
|
|
||||||
storage.uncommitted_state.commit(zxid);
|
storage.uncommitted_state.commit(zxid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1715,26 +1745,7 @@ struct KeeperStorageMultiRequestProcessor final : public KeeperStorageRequestPro
|
|||||||
|
|
||||||
for (size_t i = 0; i < concrete_requests.size(); ++i)
|
for (size_t i = 0; i < concrete_requests.size(); ++i)
|
||||||
{
|
{
|
||||||
auto cur_response = concrete_requests[i]->processLocal(storage, zxid);
|
response.responses[i] = concrete_requests[i]->processLocal(storage, zxid);
|
||||||
|
|
||||||
response.responses[i] = cur_response;
|
|
||||||
if (cur_response->error != Coordination::Error::ZOK)
|
|
||||||
{
|
|
||||||
for (size_t j = 0; j <= i; ++j)
|
|
||||||
{
|
|
||||||
auto response_error = response.responses[j]->error;
|
|
||||||
response.responses[j] = std::make_shared<Coordination::ZooKeeperErrorResponse>();
|
|
||||||
response.responses[j]->error = response_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t j = i + 1; j < response.responses.size(); ++j)
|
|
||||||
{
|
|
||||||
response.responses[j] = std::make_shared<Coordination::ZooKeeperErrorResponse>();
|
|
||||||
response.responses[j]->error = Coordination::Error::ZRUNTIMEINCONSISTENCY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return response_ptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.error = Coordination::Error::ZOK;
|
response.error = Coordination::Error::ZOK;
|
||||||
@ -1881,6 +1892,7 @@ KeeperStorageRequestProcessorsFactory::KeeperStorageRequestProcessorsFactory()
|
|||||||
registerKeeperRequestProcessor<Coordination::OpNum::FilteredList, KeeperStorageListRequestProcessor>(*this);
|
registerKeeperRequestProcessor<Coordination::OpNum::FilteredList, KeeperStorageListRequestProcessor>(*this);
|
||||||
registerKeeperRequestProcessor<Coordination::OpNum::Check, KeeperStorageCheckRequestProcessor>(*this);
|
registerKeeperRequestProcessor<Coordination::OpNum::Check, KeeperStorageCheckRequestProcessor>(*this);
|
||||||
registerKeeperRequestProcessor<Coordination::OpNum::Multi, KeeperStorageMultiRequestProcessor>(*this);
|
registerKeeperRequestProcessor<Coordination::OpNum::Multi, KeeperStorageMultiRequestProcessor>(*this);
|
||||||
|
registerKeeperRequestProcessor<Coordination::OpNum::MultiRead, KeeperStorageMultiRequestProcessor>(*this);
|
||||||
registerKeeperRequestProcessor<Coordination::OpNum::SetACL, KeeperStorageSetACLRequestProcessor>(*this);
|
registerKeeperRequestProcessor<Coordination::OpNum::SetACL, KeeperStorageSetACLRequestProcessor>(*this);
|
||||||
registerKeeperRequestProcessor<Coordination::OpNum::GetACL, KeeperStorageGetACLRequestProcessor>(*this);
|
registerKeeperRequestProcessor<Coordination::OpNum::GetACL, KeeperStorageGetACLRequestProcessor>(*this);
|
||||||
}
|
}
|
||||||
|
@ -261,8 +261,8 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
|
|||||||
M(Bool, fallback_to_stale_replicas_for_distributed_queries, true, "Suppose max_replica_delay_for_distributed_queries is set and all replicas for the queried table are stale. If this setting is enabled, the query will be performed anyway, otherwise the error will be reported.", 0) \
|
M(Bool, fallback_to_stale_replicas_for_distributed_queries, true, "Suppose max_replica_delay_for_distributed_queries is set and all replicas for the queried table are stale. If this setting is enabled, the query will be performed anyway, otherwise the error will be reported.", 0) \
|
||||||
M(UInt64, preferred_max_column_in_block_size_bytes, 0, "Limit on max column size in block while reading. Helps to decrease cache misses count. Should be close to L2 cache size.", 0) \
|
M(UInt64, preferred_max_column_in_block_size_bytes, 0, "Limit on max column size in block while reading. Helps to decrease cache misses count. Should be close to L2 cache size.", 0) \
|
||||||
\
|
\
|
||||||
M(UInt64, parts_to_delay_insert, 150, "If the destination table contains at least that many active parts in a single partition, artificially slow down insert into table.", 0) \
|
M(UInt64, parts_to_delay_insert, 0, "If the destination table contains at least that many active parts in a single partition, artificially slow down insert into table.", 0) \
|
||||||
M(UInt64, parts_to_throw_insert, 300, "If more than this number active parts in a single partition of the destination table, throw 'Too many parts ...' exception.", 0) \
|
M(UInt64, parts_to_throw_insert, 0, "If more than this number active parts in a single partition of the destination table, throw 'Too many parts ...' exception.", 0) \
|
||||||
M(Bool, insert_distributed_sync, false, "If setting is enabled, insert query into distributed waits until data will be sent to all nodes in cluster.", 0) \
|
M(Bool, insert_distributed_sync, false, "If setting is enabled, insert query into distributed waits until data will be sent to all nodes in cluster.", 0) \
|
||||||
M(UInt64, insert_distributed_timeout, 0, "Timeout for insert query into distributed. Setting is used only with insert_distributed_sync enabled. Zero value means no timeout.", 0) \
|
M(UInt64, insert_distributed_timeout, 0, "Timeout for insert query into distributed. Setting is used only with insert_distributed_sync enabled. Zero value means no timeout.", 0) \
|
||||||
M(Int64, distributed_ddl_task_timeout, 180, "Timeout for DDL query responses from all hosts in cluster. If a ddl request has not been performed on all hosts, a response will contain a timeout error and a request will be executed in an async mode. Negative value means infinite. Zero means async mode.", 0) \
|
M(Int64, distributed_ddl_task_timeout, 180, "Timeout for DDL query responses from all hosts in cluster. If a ddl request has not been performed on all hosts, a response will contain a timeout error and a request will be executed in an async mode. Negative value means infinite. Zero means async mode.", 0) \
|
||||||
|
@ -11,8 +11,8 @@ if (OS_DARWIN AND NOT USE_STATIC_LIBRARIES)
|
|||||||
target_link_libraries (daemon PUBLIC -Wl,-undefined,dynamic_lookup)
|
target_link_libraries (daemon PUBLIC -Wl,-undefined,dynamic_lookup)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries (daemon PUBLIC loggers common PRIVATE clickhouse_common_io clickhouse_common_config ${EXECINFO_LIBRARIES})
|
target_link_libraries (daemon PUBLIC loggers common PRIVATE clickhouse_common_io clickhouse_common_config)
|
||||||
|
|
||||||
if (TARGET ch_contrib::sentry)
|
if (TARGET ch_contrib::sentry)
|
||||||
target_link_libraries (daemon PRIVATE ch_contrib::sentry)
|
target_link_libraries (daemon PRIVATE ch_contrib::sentry dbms)
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -96,14 +96,14 @@ void SentryWriter::initialize(Poco::Util::LayeredConfiguration & config)
|
|||||||
}
|
}
|
||||||
sentry_options_set_dsn(options, endpoint.c_str());
|
sentry_options_set_dsn(options, endpoint.c_str());
|
||||||
sentry_options_set_database_path(options, temp_folder_path.c_str());
|
sentry_options_set_database_path(options, temp_folder_path.c_str());
|
||||||
|
|
||||||
|
/// This value will be attached to each report
|
||||||
|
String environment_default_value = "test";
|
||||||
if (strstr(VERSION_DESCRIBE, "-stable") || strstr(VERSION_DESCRIBE, "-lts"))
|
if (strstr(VERSION_DESCRIBE, "-stable") || strstr(VERSION_DESCRIBE, "-lts"))
|
||||||
{
|
environment_default_value = "prod";
|
||||||
sentry_options_set_environment(options, "prod");
|
/// If the value is set in config - use it
|
||||||
}
|
auto value = config.getString("send_crash_reports.environment", environment_default_value);
|
||||||
else
|
sentry_options_set_environment(options, value.c_str());
|
||||||
{
|
|
||||||
sentry_options_set_environment(options, "test");
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string & http_proxy = config.getString("send_crash_reports.http_proxy", "");
|
const std::string & http_proxy = config.getString("send_crash_reports.http_proxy", "");
|
||||||
if (!http_proxy.empty())
|
if (!http_proxy.empty())
|
||||||
|
@ -205,10 +205,9 @@ inline ReturnType convertToDecimalImpl(const typename FromDataType::FieldType &
|
|||||||
if (!std::isfinite(value))
|
if (!std::isfinite(value))
|
||||||
{
|
{
|
||||||
if constexpr (throw_exception)
|
if constexpr (throw_exception)
|
||||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Cannot convert infinity or NaN to decimal",
|
throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "{} convert overflow. Cannot convert infinity or NaN to decimal", ToDataType::family_name);
|
||||||
ErrorCodes::DECIMAL_OVERFLOW);
|
|
||||||
else
|
else
|
||||||
return false;
|
return ReturnType(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto out = value * static_cast<FromFieldType>(DecimalUtils::scaleMultiplier<ToNativeType>(scale));
|
auto out = value * static_cast<FromFieldType>(DecimalUtils::scaleMultiplier<ToNativeType>(scale));
|
||||||
@ -217,8 +216,7 @@ inline ReturnType convertToDecimalImpl(const typename FromDataType::FieldType &
|
|||||||
out >= static_cast<FromFieldType>(std::numeric_limits<ToNativeType>::max()))
|
out >= static_cast<FromFieldType>(std::numeric_limits<ToNativeType>::max()))
|
||||||
{
|
{
|
||||||
if constexpr (throw_exception)
|
if constexpr (throw_exception)
|
||||||
throw Exception(std::string(ToDataType::family_name) + " convert overflow. Float is out of Decimal range",
|
throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "{} convert overflow. Float is out of Decimal range", ToDataType::family_name);
|
||||||
ErrorCodes::DECIMAL_OVERFLOW);
|
|
||||||
else
|
else
|
||||||
return ReturnType(false);
|
return ReturnType(false);
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,11 @@ void WriteBufferFromAzureBlobStorage::execWithRetry(std::function<void()> func,
|
|||||||
void WriteBufferFromAzureBlobStorage::finalizeImpl()
|
void WriteBufferFromAzureBlobStorage::finalizeImpl()
|
||||||
{
|
{
|
||||||
execWithRetry([this](){ next(); }, DEFAULT_RETRY_NUM);
|
execWithRetry([this](){ next(); }, DEFAULT_RETRY_NUM);
|
||||||
|
|
||||||
|
auto block_blob_client = blob_container_client->GetBlockBlobClient(blob_path);
|
||||||
|
execWithRetry([&](){ block_blob_client.CommitBlockList(block_ids); }, DEFAULT_RETRY_NUM);
|
||||||
|
|
||||||
|
LOG_TRACE(log, "Committed {} blocks for blob `{}`", block_ids.size(), blob_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteBufferFromAzureBlobStorage::nextImpl()
|
void WriteBufferFromAzureBlobStorage::nextImpl()
|
||||||
@ -78,7 +83,6 @@ void WriteBufferFromAzureBlobStorage::nextImpl()
|
|||||||
auto block_blob_client = blob_container_client->GetBlockBlobClient(blob_path);
|
auto block_blob_client = blob_container_client->GetBlockBlobClient(blob_path);
|
||||||
|
|
||||||
size_t current_size = 0;
|
size_t current_size = 0;
|
||||||
std::vector<std::string> block_ids;
|
|
||||||
|
|
||||||
while (current_size < total_size)
|
while (current_size < total_size)
|
||||||
{
|
{
|
||||||
@ -92,9 +96,6 @@ void WriteBufferFromAzureBlobStorage::nextImpl()
|
|||||||
LOG_TRACE(log, "Staged block (id: {}) of size {} (written {}/{}, blob path: {}).", block_id, part_len, current_size, total_size, blob_path);
|
LOG_TRACE(log, "Staged block (id: {}) of size {} (written {}/{}, blob path: {}).", block_id, part_len, current_size, total_size, blob_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
execWithRetry([&](){ block_blob_client.CommitBlockList(block_ids); }, DEFAULT_RETRY_NUM);
|
|
||||||
LOG_TRACE(log, "Committed {} blocks for blob `{}`", block_ids.size(), blob_path);
|
|
||||||
|
|
||||||
if (write_settings.remote_throttler)
|
if (write_settings.remote_throttler)
|
||||||
write_settings.remote_throttler->add(total_size);
|
write_settings.remote_throttler->add(total_size);
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ private:
|
|||||||
const WriteSettings write_settings;
|
const WriteSettings write_settings;
|
||||||
|
|
||||||
AzureClientPtr blob_container_client;
|
AzureClientPtr blob_container_client;
|
||||||
|
std::vector<std::string> block_ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,13 @@ list (APPEND PRIVATE_LIBS
|
|||||||
divide_impl
|
divide_impl
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (TARGET ch_rust::blake3)
|
||||||
|
list (APPEND PUBLIC_LIBS
|
||||||
|
ch_rust::blake3
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (TARGET OpenSSL::Crypto)
|
if (TARGET OpenSSL::Crypto)
|
||||||
list (APPEND PUBLIC_LIBS OpenSSL::Crypto)
|
list (APPEND PUBLIC_LIBS OpenSSL::Crypto)
|
||||||
endif()
|
endif()
|
||||||
|
26
src/Functions/DateTimeTransforms.cpp
Normal file
26
src/Functions/DateTimeTransforms.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <Functions/DateTimeTransforms.h>
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void throwDateIsNotSupported(const char * name)
|
||||||
|
{
|
||||||
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type Date of argument for function {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void throwDateTimeIsNotSupported(const char * name)
|
||||||
|
{
|
||||||
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type DateTime of argument for function {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void throwDate32IsNotSupported(const char * name)
|
||||||
|
{
|
||||||
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type Date32 of argument for function {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -36,20 +36,9 @@ namespace ErrorCodes
|
|||||||
* factor-transformation F is "round to the nearest month" (2015-02-03 -> 2015-02-01).
|
* factor-transformation F is "round to the nearest month" (2015-02-03 -> 2015-02-01).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline UInt32 dateIsNotSupported(const char * name)
|
[[noreturn]] void throwDateIsNotSupported(const char * name);
|
||||||
{
|
[[noreturn]] void throwDateTimeIsNotSupported(const char * name);
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type Date of argument for function {}", name);
|
[[noreturn]] void throwDate32IsNotSupported(const char * name);
|
||||||
}
|
|
||||||
|
|
||||||
static inline UInt32 dateTimeIsNotSupported(const char * name)
|
|
||||||
{
|
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type DateTime of argument for function {}", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Int64 date32IsNotSupported(const char * name)
|
|
||||||
{
|
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type Date32 of argument for function {}", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This factor transformation will say that the function is monotone everywhere.
|
/// This factor transformation will say that the function is monotone everywhere.
|
||||||
struct ZeroTransform
|
struct ZeroTransform
|
||||||
@ -335,11 +324,11 @@ struct ToTimeImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ToDateImpl;
|
using FactorTransform = ToDateImpl;
|
||||||
@ -362,11 +351,11 @@ struct ToStartOfMinuteImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
@ -374,7 +363,7 @@ struct ToStartOfMinuteImpl
|
|||||||
}
|
}
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -409,11 +398,11 @@ struct ToStartOfSecondImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -456,11 +445,11 @@ struct ToStartOfMillisecondImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -499,11 +488,11 @@ struct ToStartOfMicrosecondImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -536,11 +525,11 @@ struct ToStartOfNanosecondImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -560,11 +549,11 @@ struct ToStartOfFiveMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
@ -572,7 +561,7 @@ struct ToStartOfFiveMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -592,11 +581,11 @@ struct ToStartOfTenMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
@ -604,7 +593,7 @@ struct ToStartOfTenMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -624,11 +613,11 @@ struct ToStartOfFifteenMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
@ -636,7 +625,7 @@ struct ToStartOfFifteenMinutesImpl
|
|||||||
}
|
}
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -659,12 +648,12 @@ struct TimeSlotImpl
|
|||||||
|
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl &)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl &)
|
||||||
@ -676,7 +665,7 @@ struct TimeSlotImpl
|
|||||||
|
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -701,12 +690,12 @@ struct ToStartOfHourImpl
|
|||||||
|
|
||||||
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
static inline UInt32 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
static inline UInt32 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
static inline DecimalUtils::DecimalComponents<DateTime64> executeExtendedResult(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & time_zone)
|
||||||
@ -716,7 +705,7 @@ struct ToStartOfHourImpl
|
|||||||
|
|
||||||
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
static inline Int64 executeExtendedResult(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return date32IsNotSupported(name);
|
throwDate32IsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ZeroTransform;
|
using FactorTransform = ZeroTransform;
|
||||||
@ -880,11 +869,11 @@ struct ToHourImpl
|
|||||||
}
|
}
|
||||||
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ToDateImpl;
|
using FactorTransform = ToDateImpl;
|
||||||
@ -906,12 +895,12 @@ struct TimezoneOffsetImpl
|
|||||||
|
|
||||||
static inline time_t execute(Int32, const DateLUTImpl &)
|
static inline time_t execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline time_t execute(UInt16, const DateLUTImpl &)
|
static inline time_t execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ToTimeImpl;
|
using FactorTransform = ToTimeImpl;
|
||||||
@ -931,11 +920,11 @@ struct ToMinuteImpl
|
|||||||
}
|
}
|
||||||
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ToStartOfHourImpl;
|
using FactorTransform = ToStartOfHourImpl;
|
||||||
@ -955,11 +944,11 @@ struct ToSecondImpl
|
|||||||
}
|
}
|
||||||
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
static inline UInt8 execute(Int32, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
static inline UInt8 execute(UInt16, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return dateIsNotSupported(name);
|
throwDateTimeIsNotSupported(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
using FactorTransform = ToStartOfMinuteImpl;
|
using FactorTransform = ToStartOfMinuteImpl;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <Functions/FunctionsAES.h>
|
#include <Functions/FunctionsAES.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
|
||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
|
|
||||||
@ -8,7 +9,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Common/config.h>
|
#include <Common/config.h>
|
||||||
|
#include <Columns/ColumnNullable.h>
|
||||||
|
#include <Columns/ColumnsNumber.h>
|
||||||
|
#include <DataTypes/DataTypeNullable.h>
|
||||||
|
|
||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
#include <DataTypes/DataTypeString.h>
|
#include <DataTypes/DataTypeString.h>
|
||||||
@ -20,7 +23,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
@ -411,6 +413,7 @@ class FunctionDecrypt : public IFunction
|
|||||||
public:
|
public:
|
||||||
static constexpr OpenSSLDetails::CompatibilityMode compatibility_mode = Impl::compatibility_mode;
|
static constexpr OpenSSLDetails::CompatibilityMode compatibility_mode = Impl::compatibility_mode;
|
||||||
static constexpr auto name = Impl::name;
|
static constexpr auto name = Impl::name;
|
||||||
|
static constexpr bool use_null_when_decrypt_fail = Impl::use_null_when_decrypt_fail;
|
||||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionDecrypt>(); }
|
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionDecrypt>(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -445,6 +448,9 @@ private:
|
|||||||
optional_args
|
optional_args
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if constexpr (use_null_when_decrypt_fail)
|
||||||
|
return std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>());
|
||||||
|
|
||||||
return std::make_shared<DataTypeString>();
|
return std::make_shared<DataTypeString>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +474,7 @@ private:
|
|||||||
ColumnPtr result_column;
|
ColumnPtr result_column;
|
||||||
if (arguments.size() <= 3)
|
if (arguments.size() <= 3)
|
||||||
{
|
{
|
||||||
result_column = doDecrypt(evp_cipher, input_rows_count, input_column, key_column, nullptr, nullptr);
|
result_column = doDecrypt<use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -478,7 +484,7 @@ private:
|
|||||||
|
|
||||||
if (arguments.size() <= 4)
|
if (arguments.size() <= 4)
|
||||||
{
|
{
|
||||||
result_column = doDecrypt(evp_cipher, input_rows_count, input_column, key_column, iv_column, nullptr);
|
result_column = doDecrypt<use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, iv_column, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -486,13 +492,13 @@ private:
|
|||||||
throw Exception("AAD can be only set for GCM-mode", ErrorCodes::BAD_ARGUMENTS);
|
throw Exception("AAD can be only set for GCM-mode", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
const auto aad_column = arguments[4].column;
|
const auto aad_column = arguments[4].column;
|
||||||
result_column = doDecrypt(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
result_column = doDecrypt<use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result_column;
|
return result_column;
|
||||||
}
|
}
|
||||||
|
template<bool use_null_when_decrypt_fail>
|
||||||
static ColumnPtr doDecrypt(
|
static ColumnPtr doDecrypt(
|
||||||
const EVP_CIPHER * evp_cipher,
|
const EVP_CIPHER * evp_cipher,
|
||||||
size_t input_rows_count,
|
size_t input_rows_count,
|
||||||
@ -503,25 +509,25 @@ private:
|
|||||||
{
|
{
|
||||||
if constexpr (compatibility_mode == OpenSSLDetails::CompatibilityMode::MySQL)
|
if constexpr (compatibility_mode == OpenSSLDetails::CompatibilityMode::MySQL)
|
||||||
{
|
{
|
||||||
return doDecryptImpl<CipherMode::MySQLCompatibility>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
return doDecryptImpl<CipherMode::MySQLCompatibility, use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto cipher_mode = EVP_CIPHER_mode(evp_cipher);
|
const auto cipher_mode = EVP_CIPHER_mode(evp_cipher);
|
||||||
if (cipher_mode == EVP_CIPH_GCM_MODE)
|
if (cipher_mode == EVP_CIPH_GCM_MODE)
|
||||||
{
|
{
|
||||||
return doDecryptImpl<CipherMode::RFC5116_AEAD_AES_GCM>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
return doDecryptImpl<CipherMode::RFC5116_AEAD_AES_GCM, use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return doDecryptImpl<CipherMode::OpenSSLCompatibility>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
return doDecryptImpl<CipherMode::OpenSSLCompatibility, use_null_when_decrypt_fail>(evp_cipher, input_rows_count, input_column, key_column, iv_column, aad_column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <CipherMode mode>
|
template <CipherMode mode, bool use_null_when_decrypt_fail>
|
||||||
static ColumnPtr doDecryptImpl(const EVP_CIPHER * evp_cipher,
|
static ColumnPtr doDecryptImpl(const EVP_CIPHER * evp_cipher,
|
||||||
size_t input_rows_count,
|
size_t input_rows_count,
|
||||||
const ColumnPtr & input_column,
|
const ColumnPtr & input_column,
|
||||||
@ -541,6 +547,7 @@ private:
|
|||||||
static constexpr size_t tag_size = 16; // https://tools.ietf.org/html/rfc5116#section-5.1
|
static constexpr size_t tag_size = 16; // https://tools.ietf.org/html/rfc5116#section-5.1
|
||||||
|
|
||||||
auto decrypted_result_column = ColumnString::create();
|
auto decrypted_result_column = ColumnString::create();
|
||||||
|
auto null_map = ColumnUInt8::create();
|
||||||
auto & decrypted_result_column_data = decrypted_result_column->getChars();
|
auto & decrypted_result_column_data = decrypted_result_column->getChars();
|
||||||
auto & decrypted_result_column_offsets = decrypted_result_column->getOffsets();
|
auto & decrypted_result_column_offsets = decrypted_result_column->getOffsets();
|
||||||
|
|
||||||
@ -616,6 +623,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool decrypt_fail = false;
|
||||||
/// Avoid extra work on empty ciphertext/plaintext. Always decrypt empty to empty.
|
/// Avoid extra work on empty ciphertext/plaintext. Always decrypt empty to empty.
|
||||||
/// This makes sense for default implementation for NULLs.
|
/// This makes sense for default implementation for NULLs.
|
||||||
if (input_value.size > 0)
|
if (input_value.size > 0)
|
||||||
@ -662,28 +670,46 @@ private:
|
|||||||
if (EVP_DecryptUpdate(evp_ctx,
|
if (EVP_DecryptUpdate(evp_ctx,
|
||||||
reinterpret_cast<unsigned char*>(decrypted), &output_len,
|
reinterpret_cast<unsigned char*>(decrypted), &output_len,
|
||||||
reinterpret_cast<const unsigned char*>(input_value.data), static_cast<int>(input_value.size)) != 1)
|
reinterpret_cast<const unsigned char*>(input_value.data), static_cast<int>(input_value.size)) != 1)
|
||||||
onError("Failed to decrypt");
|
|
||||||
decrypted += output_len;
|
|
||||||
|
|
||||||
// 3: optionally get tag from the ciphertext (RFC5116) and feed it to the context
|
|
||||||
if constexpr (mode == CipherMode::RFC5116_AEAD_AES_GCM)
|
|
||||||
{
|
{
|
||||||
void * tag = const_cast<void *>(reinterpret_cast<const void *>(input_value.data + input_value.size));
|
if constexpr (!use_null_when_decrypt_fail)
|
||||||
if (EVP_CIPHER_CTX_ctrl(evp_ctx, EVP_CTRL_AEAD_SET_TAG, tag_size, tag) != 1)
|
onError("Failed to decrypt");
|
||||||
onError("Failed to set tag");
|
decrypt_fail = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decrypted += output_len;
|
||||||
|
// 3: optionally get tag from the ciphertext (RFC5116) and feed it to the context
|
||||||
|
if constexpr (mode == CipherMode::RFC5116_AEAD_AES_GCM)
|
||||||
|
{
|
||||||
|
void * tag = const_cast<void *>(reinterpret_cast<const void *>(input_value.data + input_value.size));
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(evp_ctx, EVP_CTRL_AEAD_SET_TAG, tag_size, tag) != 1)
|
||||||
|
onError("Failed to set tag");
|
||||||
|
}
|
||||||
|
|
||||||
// 4: retrieve encrypted data (ciphertext)
|
// 4: retrieve encrypted data (ciphertext)
|
||||||
if (EVP_DecryptFinal_ex(evp_ctx,
|
if (!decrypt_fail && EVP_DecryptFinal_ex(evp_ctx,
|
||||||
reinterpret_cast<unsigned char*>(decrypted), &output_len) != 1)
|
reinterpret_cast<unsigned char*>(decrypted), &output_len) != 1)
|
||||||
onError("Failed to decrypt");
|
{
|
||||||
decrypted += output_len;
|
if constexpr (!use_null_when_decrypt_fail)
|
||||||
|
onError("Failed to decrypt");
|
||||||
|
decrypt_fail = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
decrypted += output_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*decrypted = '\0';
|
*decrypted = '\0';
|
||||||
++decrypted;
|
++decrypted;
|
||||||
|
|
||||||
decrypted_result_column_offsets.push_back(decrypted - decrypted_result_column_data.data());
|
decrypted_result_column_offsets.push_back(decrypted - decrypted_result_column_data.data());
|
||||||
|
if constexpr (use_null_when_decrypt_fail)
|
||||||
|
{
|
||||||
|
if (decrypt_fail)
|
||||||
|
null_map->insertValue(1);
|
||||||
|
else
|
||||||
|
null_map->insertValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +720,10 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
decrypted_result_column->validate();
|
decrypted_result_column->validate();
|
||||||
return decrypted_result_column;
|
if constexpr (use_null_when_decrypt_fail)
|
||||||
|
return ColumnNullable::create(std::move(decrypted_result_column), std::move(null_map));
|
||||||
|
else
|
||||||
|
return decrypted_result_column;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,13 +323,13 @@ struct ToDateTimeImpl
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDateTime";
|
static constexpr auto name = "toDateTime";
|
||||||
|
|
||||||
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
|
static UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
auto date_time = time_zone.fromDayNum(ExtendedDayNum(d));
|
auto date_time = time_zone.fromDayNum(ExtendedDayNum(d));
|
||||||
return date_time <= 0xffffffff ? UInt32(date_time) : UInt32(0xffffffff);
|
return date_time <= 0xffffffff ? UInt32(date_time) : UInt32(0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(Int32 d, const DateLUTImpl & time_zone)
|
static UInt32 execute(Int32 d, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -338,12 +338,12 @@ struct ToDateTimeImpl
|
|||||||
return date_time <= 0xffffffff ? date_time : 0xffffffff;
|
return date_time <= 0xffffffff ? date_time : 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(UInt32 dt, const DateLUTImpl & /*time_zone*/)
|
static UInt32 execute(UInt32 dt, const DateLUTImpl & /*time_zone*/)
|
||||||
{
|
{
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(Int64 d, const DateLUTImpl & time_zone)
|
static UInt32 execute(Int64 d, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -352,7 +352,7 @@ struct ToDateTimeImpl
|
|||||||
return date_time <= 0xffffffff ? date_time : 0xffffffff;
|
return date_time <= 0xffffffff ? date_time : 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & /*time_zone*/)
|
static UInt32 execute(const DecimalUtils::DecimalComponents<DateTime64> & t, const DateLUTImpl & /*time_zone*/)
|
||||||
{
|
{
|
||||||
if (t.whole < 0 || (t.whole >= 0 && t.fractional < 0))
|
if (t.whole < 0 || (t.whole >= 0 && t.fractional < 0))
|
||||||
return 0;
|
return 0;
|
||||||
@ -374,7 +374,7 @@ struct ToDateTransform32Or64
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate";
|
static constexpr auto name = "toDate";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
// since converting to Date, no need in values outside of default LUT range.
|
// since converting to Date, no need in values outside of default LUT range.
|
||||||
if (from < 0)
|
if (from < 0)
|
||||||
@ -391,7 +391,7 @@ struct ToDateTransform32Or64Signed
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate";
|
static constexpr auto name = "toDate";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
// TODO: decide narrow or extended range based on FromType
|
// TODO: decide narrow or extended range based on FromType
|
||||||
/// The function should be monotonic (better for query optimizations), so we saturate instead of overflow.
|
/// The function should be monotonic (better for query optimizations), so we saturate instead of overflow.
|
||||||
@ -413,7 +413,7 @@ struct ToDateTransform8Or16Signed
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate";
|
static constexpr auto name = "toDate";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
if (from < 0)
|
if (from < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -431,7 +431,7 @@ struct ToDate32Transform32Or64
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate32";
|
static constexpr auto name = "toDate32";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
return (from < DATE_LUT_MAX_EXTEND_DAY_NUM)
|
return (from < DATE_LUT_MAX_EXTEND_DAY_NUM)
|
||||||
? from
|
? from
|
||||||
@ -444,7 +444,7 @@ struct ToDate32Transform32Or64Signed
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate32";
|
static constexpr auto name = "toDate32";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & time_zone)
|
||||||
{
|
{
|
||||||
static const Int32 daynum_min_offset = -static_cast<Int32>(DateLUT::instance().getDayNumOffsetEpoch());
|
static const Int32 daynum_min_offset = -static_cast<Int32>(DateLUT::instance().getDayNumOffsetEpoch());
|
||||||
if (from < daynum_min_offset)
|
if (from < daynum_min_offset)
|
||||||
@ -460,7 +460,7 @@ struct ToDate32Transform8Or16Signed
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDate32";
|
static constexpr auto name = "toDate32";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
@ -529,7 +529,7 @@ struct ToDateTimeTransform64
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDateTime";
|
static constexpr auto name = "toDateTime";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
return std::min<Int64>(Int64(from), Int64(0xFFFFFFFF));
|
return std::min<Int64>(Int64(from), Int64(0xFFFFFFFF));
|
||||||
}
|
}
|
||||||
@ -540,7 +540,7 @@ struct ToDateTimeTransformSigned
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDateTime";
|
static constexpr auto name = "toDateTime";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
|
||||||
{
|
{
|
||||||
if (from < 0)
|
if (from < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -553,7 +553,7 @@ struct ToDateTimeTransform64Signed
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "toDateTime";
|
static constexpr auto name = "toDateTime";
|
||||||
|
|
||||||
static inline NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & /* time_zone */)
|
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl & /* time_zone */)
|
||||||
{
|
{
|
||||||
if (from < 0)
|
if (from < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -581,9 +581,9 @@ template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDateTime, N
|
|||||||
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDateTime, Name>
|
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDateTime, Name>
|
||||||
: DateTimeTransformImpl<DataTypeFloat64, DataTypeDateTime, ToDateTimeTransform64Signed<Float64, UInt32>> {};
|
: DateTimeTransformImpl<DataTypeFloat64, DataTypeDateTime, ToDateTimeTransform64Signed<Float64, UInt32>> {};
|
||||||
|
|
||||||
const time_t LUT_MIN_TIME = -2208988800l; // 1900-01-01 UTC
|
constexpr time_t LUT_MIN_TIME = -2208988800l; // 1900-01-01 UTC
|
||||||
|
|
||||||
const time_t LUT_MAX_TIME = 10413791999l; // 2299-12-31 UTC
|
constexpr time_t LUT_MAX_TIME = 10413791999l; // 2299-12-31 UTC
|
||||||
|
|
||||||
/** Conversion of numeric to DateTime64
|
/** Conversion of numeric to DateTime64
|
||||||
*/
|
*/
|
||||||
@ -599,7 +599,7 @@ struct ToDateTime64TransformUnsigned
|
|||||||
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
||||||
{
|
{
|
||||||
from = std::min<time_t>(from, LUT_MAX_TIME);
|
from = std::min<time_t>(from, LUT_MAX_TIME);
|
||||||
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(from, 0, scale_multiplier);
|
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(from, 0, scale_multiplier);
|
||||||
@ -616,7 +616,7 @@ struct ToDateTime64TransformSigned
|
|||||||
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
||||||
{
|
{
|
||||||
from = std::max<time_t>(from, LUT_MIN_TIME);
|
from = std::max<time_t>(from, LUT_MIN_TIME);
|
||||||
from = std::min<time_t>(from, LUT_MAX_TIME);
|
from = std::min<time_t>(from, LUT_MAX_TIME);
|
||||||
@ -634,11 +634,10 @@ struct ToDateTime64TransformFloat
|
|||||||
: scale(scale_)
|
: scale(scale_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
NO_SANITIZE_UNDEFINED DateTime64::NativeType execute(FromType from, const DateLUTImpl &) const
|
||||||
{
|
{
|
||||||
if (from < 0)
|
from = std::max(from, static_cast<FromType>(LUT_MIN_TIME));
|
||||||
return 0;
|
from = std::min(from, static_cast<FromType>(LUT_MAX_TIME));
|
||||||
from = std::min<FromType>(from, FromType(0xFFFFFFFF));
|
|
||||||
return convertToDecimal<FromDataType, DataTypeDateTime64>(from, scale);
|
return convertToDecimal<FromDataType, DataTypeDateTime64>(from, scale);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -672,7 +671,7 @@ struct FromDateTime64Transform
|
|||||||
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline auto execute(DateTime64::NativeType dt, const DateLUTImpl & time_zone) const
|
auto execute(DateTime64::NativeType dt, const DateLUTImpl & time_zone) const
|
||||||
{
|
{
|
||||||
const auto c = DecimalUtils::splitWithScaleMultiplier(DateTime64(dt), scale_multiplier);
|
const auto c = DecimalUtils::splitWithScaleMultiplier(DateTime64(dt), scale_multiplier);
|
||||||
return Transform::execute(static_cast<UInt32>(c.whole), time_zone);
|
return Transform::execute(static_cast<UInt32>(c.whole), time_zone);
|
||||||
@ -694,19 +693,19 @@ struct ToDateTime64Transform
|
|||||||
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
: scale_multiplier(DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline DateTime64::NativeType execute(UInt16 d, const DateLUTImpl & time_zone) const
|
DateTime64::NativeType execute(UInt16 d, const DateLUTImpl & time_zone) const
|
||||||
{
|
{
|
||||||
const auto dt = ToDateTimeImpl::execute(d, time_zone);
|
const auto dt = ToDateTimeImpl::execute(d, time_zone);
|
||||||
return execute(dt, time_zone);
|
return execute(dt, time_zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DateTime64::NativeType execute(Int32 d, const DateLUTImpl & time_zone) const
|
DateTime64::NativeType execute(Int32 d, const DateLUTImpl & time_zone) const
|
||||||
{
|
{
|
||||||
const auto dt = time_zone.fromDayNum(ExtendedDayNum(d));
|
const auto dt = time_zone.fromDayNum(ExtendedDayNum(d));
|
||||||
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
|
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DateTime64::NativeType execute(UInt32 dt, const DateLUTImpl & /*time_zone*/) const
|
DateTime64::NativeType execute(UInt32 dt, const DateLUTImpl & /*time_zone*/) const
|
||||||
{
|
{
|
||||||
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
|
return DecimalUtils::decimalFromComponentsWithMultiplier<DateTime64>(dt, 0, scale_multiplier);
|
||||||
}
|
}
|
||||||
|
@ -41,5 +41,22 @@ REGISTER_FUNCTION(Hashing)
|
|||||||
factory.registerFunction<FunctionXxHash64>();
|
factory.registerFunction<FunctionXxHash64>();
|
||||||
|
|
||||||
factory.registerFunction<FunctionWyHash64>();
|
factory.registerFunction<FunctionWyHash64>();
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_BLAKE3
|
||||||
|
factory.registerFunction<FunctionBLAKE3>(
|
||||||
|
{
|
||||||
|
R"(
|
||||||
|
Calculates BLAKE3 hash string and returns the resulting set of bytes as FixedString.
|
||||||
|
This cryptographic hash-function is integrated into ClickHouse with BLAKE3 Rust library.
|
||||||
|
The function is rather fast and shows approximately two times faster performance compared to SHA-2, while generating hashes of the same length as SHA-256.
|
||||||
|
It returns a BLAKE3 hash as a byte array with type FixedString(32).
|
||||||
|
)",
|
||||||
|
Documentation::Examples{
|
||||||
|
{"hash", "SELECT hex(blake3('ABC'))"}},
|
||||||
|
Documentation::Categories{"Hash"}
|
||||||
|
},
|
||||||
|
FunctionFactory::CaseSensitive);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#include "config_functions.h"
|
#include "config_functions.h"
|
||||||
#include "config_core.h"
|
#include "config_core.h"
|
||||||
|
|
||||||
|
#if USE_BLAKE3
|
||||||
|
# include <blake3.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <Common/SipHash.h>
|
#include <Common/SipHash.h>
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
#include <Common/HashTable/Hash.h>
|
#include <Common/HashTable/Hash.h>
|
||||||
@ -615,6 +619,32 @@ struct ImplXxHash64
|
|||||||
static constexpr bool use_int_hash_for_pods = false;
|
static constexpr bool use_int_hash_for_pods = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_BLAKE3
|
||||||
|
struct ImplBLAKE3
|
||||||
|
{
|
||||||
|
static constexpr auto name = "blake3";
|
||||||
|
enum { length = 32 };
|
||||||
|
|
||||||
|
static void apply(const char * begin, const size_t size, unsigned char* out_char_data)
|
||||||
|
{
|
||||||
|
#if defined(MEMORY_SANITIZER)
|
||||||
|
auto err_msg = blake3_apply_shim_msan_compat(begin, size, out_char_data);
|
||||||
|
__msan_unpoison(out_char_data, length);
|
||||||
|
#else
|
||||||
|
auto err_msg = blake3_apply_shim(begin, size, out_char_data);
|
||||||
|
#endif
|
||||||
|
if (err_msg != nullptr)
|
||||||
|
{
|
||||||
|
auto err_st = std::string(err_msg);
|
||||||
|
blake3_free_char_pointer(err_msg);
|
||||||
|
throw Exception("Function returned error message: " + std::string(err_msg), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
template <typename Impl>
|
template <typename Impl>
|
||||||
class FunctionStringHashFixedString : public IFunction
|
class FunctionStringHashFixedString : public IFunction
|
||||||
{
|
{
|
||||||
@ -1474,4 +1504,8 @@ using FunctionXxHash64 = FunctionAnyHash<ImplXxHash64>;
|
|||||||
|
|
||||||
using FunctionWyHash64 = FunctionAnyHash<ImplWyHash64>;
|
using FunctionWyHash64 = FunctionAnyHash<ImplWyHash64>;
|
||||||
|
|
||||||
|
#if USE_BLAKE3
|
||||||
|
using FunctionBLAKE3 = FunctionStringHashFixedString<ImplBLAKE3>;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ struct DecryptMySQLModeImpl
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "aes_decrypt_mysql";
|
static constexpr auto name = "aes_decrypt_mysql";
|
||||||
static constexpr auto compatibility_mode = OpenSSLDetails::CompatibilityMode::MySQL;
|
static constexpr auto compatibility_mode = OpenSSLDetails::CompatibilityMode::MySQL;
|
||||||
|
static constexpr bool use_null_when_decrypt_fail = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,6 @@
|
|||||||
#cmakedefine01 USE_H3
|
#cmakedefine01 USE_H3
|
||||||
#cmakedefine01 USE_S2_GEOMETRY
|
#cmakedefine01 USE_S2_GEOMETRY
|
||||||
#cmakedefine01 USE_FASTOPS
|
#cmakedefine01 USE_FASTOPS
|
||||||
|
#cmakedefine01 USE_BLAKE3
|
||||||
#cmakedefine01 USE_NLP
|
#cmakedefine01 USE_NLP
|
||||||
#cmakedefine01 USE_VECTORSCAN
|
#cmakedefine01 USE_VECTORSCAN
|
||||||
|
@ -12,6 +12,7 @@ struct DecryptImpl
|
|||||||
{
|
{
|
||||||
static constexpr auto name = "decrypt";
|
static constexpr auto name = "decrypt";
|
||||||
static constexpr auto compatibility_mode = OpenSSLDetails::CompatibilityMode::OpenSSL;
|
static constexpr auto compatibility_mode = OpenSSLDetails::CompatibilityMode::OpenSSL;
|
||||||
|
static constexpr bool use_null_when_decrypt_fail = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -155,9 +155,9 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Hour>
|
struct Transform<IntervalKind::Hour>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32 t, Int64 hours, const DateLUTImpl & time_zone, Int64)
|
static UInt32 execute(UInt32 t, Int64 hours, const DateLUTImpl & time_zone, Int64)
|
||||||
{
|
{
|
||||||
@ -173,9 +173,9 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Minute>
|
struct Transform<IntervalKind::Minute>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32 t, Int64 minutes, const DateLUTImpl & time_zone, Int64)
|
static UInt32 execute(UInt32 t, Int64 minutes, const DateLUTImpl & time_zone, Int64)
|
||||||
{
|
{
|
||||||
@ -191,9 +191,9 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Second>
|
struct Transform<IntervalKind::Second>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32 t, Int64 seconds, const DateLUTImpl & time_zone, Int64)
|
static UInt32 execute(UInt32 t, Int64 seconds, const DateLUTImpl & time_zone, Int64)
|
||||||
{
|
{
|
||||||
@ -209,11 +209,11 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Millisecond>
|
struct Transform<IntervalKind::Millisecond>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { return dateTimeIsNotSupported(function_name); }
|
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { throwDateTimeIsNotSupported(function_name); }
|
||||||
|
|
||||||
static Int64 execute(Int64 t, Int64 milliseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
static Int64 execute(Int64 t, Int64 milliseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
||||||
{
|
{
|
||||||
@ -246,11 +246,11 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Microsecond>
|
struct Transform<IntervalKind::Microsecond>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { return dateTimeIsNotSupported(function_name); }
|
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { throwDateTimeIsNotSupported(function_name); }
|
||||||
|
|
||||||
static Int64 execute(Int64 t, Int64 microseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
static Int64 execute(Int64 t, Int64 microseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
||||||
{
|
{
|
||||||
@ -283,11 +283,11 @@ namespace
|
|||||||
template <>
|
template <>
|
||||||
struct Transform<IntervalKind::Nanosecond>
|
struct Transform<IntervalKind::Nanosecond>
|
||||||
{
|
{
|
||||||
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(UInt16, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { return dateIsNotSupported(function_name); }
|
static UInt32 execute(Int32, Int64, const DateLUTImpl &, Int64) { throwDateIsNotSupported(function_name); }
|
||||||
|
|
||||||
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { return dateTimeIsNotSupported(function_name); }
|
static UInt32 execute(UInt32, Int64, const DateLUTImpl &, Int64) { throwDateTimeIsNotSupported(function_name); }
|
||||||
|
|
||||||
static Int64 execute(Int64 t, Int64 nanoseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
static Int64 execute(Int64 t, Int64 nanoseconds, const DateLUTImpl &, Int64 scale_multiplier)
|
||||||
{
|
{
|
||||||
|
32
src/Functions/tryDecrypt.cpp
Normal file
32
src/Functions/tryDecrypt.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <Common/Documentation.h>
|
||||||
|
#include <Common/config.h>
|
||||||
|
|
||||||
|
#if USE_SSL
|
||||||
|
|
||||||
|
# include <Functions/FunctionFactory.h>
|
||||||
|
# include <Functions/FunctionsAES.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TryDecryptImpl
|
||||||
|
{
|
||||||
|
static constexpr auto name = "tryDecrypt";
|
||||||
|
static constexpr auto compatibility_mode = OpenSSLDetails::CompatibilityMode::OpenSSL;
|
||||||
|
static constexpr bool use_null_when_decrypt_fail = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
REGISTER_FUNCTION(TryDecrypt)
|
||||||
|
{
|
||||||
|
factory.registerFunction<FunctionDecrypt<TryDecryptImpl>>(Documentation(
|
||||||
|
"Similar to `decrypt`, but returns NULL if decryption fails because of using the wrong key."));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -6,6 +6,7 @@
|
|||||||
#include <Access/Common/AccessRightsElement.h>
|
#include <Access/Common/AccessRightsElement.h>
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
#include <Parsers/ASTExpressionList.h>
|
#include <Parsers/ASTExpressionList.h>
|
||||||
|
#include <Storages/MergeTree/MergeTreeData.h>
|
||||||
|
|
||||||
#include <Interpreters/processColumnTransformers.h>
|
#include <Interpreters/processColumnTransformers.h>
|
||||||
|
|
||||||
@ -75,6 +76,9 @@ BlockIO InterpreterOptimizeQuery::execute()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto * snapshot_data = dynamic_cast<MergeTreeData::SnapshotData *>(storage_snapshot->data.get()))
|
||||||
|
snapshot_data->parts = {};
|
||||||
|
|
||||||
table->optimize(query_ptr, metadata_snapshot, ast.partition, ast.final, ast.deduplicate, column_names, getContext());
|
table->optimize(query_ptr, metadata_snapshot, ast.partition, ast.final, ast.deduplicate, column_names, getContext());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||||
#include <llvm/ExecutionEngine/JITEventListener.h>
|
#include <llvm/ExecutionEngine/JITEventListener.h>
|
||||||
#include <llvm/MC/SubtargetFeature.h>
|
#include <llvm/MC/SubtargetFeature.h>
|
||||||
|
#include <llvm/MC/TargetRegistry.h>
|
||||||
#include <llvm/Support/DynamicLibrary.h>
|
#include <llvm/Support/DynamicLibrary.h>
|
||||||
#include <llvm/Support/Host.h>
|
#include <llvm/Support/Host.h>
|
||||||
#include <llvm/Support/TargetRegistry.h>
|
|
||||||
#include <llvm/Support/TargetSelect.h>
|
#include <llvm/Support/TargetSelect.h>
|
||||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||||
#include <llvm/Support/SmallVectorMemoryBuffer.h>
|
#include <llvm/Support/SmallVectorMemoryBuffer.h>
|
||||||
|
@ -873,15 +873,10 @@ CompiledSortDescriptionFunction compileSortDescription(
|
|||||||
auto * lhs_column_data = b.CreatePointerCast(b.CreateExtractValue(lhs_column, {0}), column_native_type_pointer);
|
auto * lhs_column_data = b.CreatePointerCast(b.CreateExtractValue(lhs_column, {0}), column_native_type_pointer);
|
||||||
auto * lhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(lhs_column, {1}) : nullptr;
|
auto * lhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(lhs_column, {1}) : nullptr;
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
#endif
|
|
||||||
auto * ty_lhs_column_data = llvm::cast<llvm::PointerType>(lhs_column_data->getType()->getScalarType())->getElementType();
|
auto * ty_lhs_column_data = llvm::cast<llvm::PointerType>(lhs_column_data->getType()->getScalarType())->getElementType();
|
||||||
llvm::Value * lhs_value = b.CreateLoad(b.CreateInBoundsGEP(ty_lhs_column_data, lhs_column_data, lhs_index_arg));
|
|
||||||
#ifdef __clang__
|
llvm::Value * lhs_cib_gep = b.CreateInBoundsGEP(ty_lhs_column_data, lhs_column_data, lhs_index_arg);
|
||||||
#pragma clang diagnostic pop
|
llvm::Value * lhs_value = b.CreateLoad(lhs_cib_gep->getType()->getPointerElementType(), lhs_cib_gep);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lhs_column_null_data)
|
if (lhs_column_null_data)
|
||||||
{
|
{
|
||||||
@ -896,15 +891,11 @@ CompiledSortDescriptionFunction compileSortDescription(
|
|||||||
auto * rhs_column_data = b.CreatePointerCast(b.CreateExtractValue(rhs_column, {0}), column_native_type_pointer);
|
auto * rhs_column_data = b.CreatePointerCast(b.CreateExtractValue(rhs_column, {0}), column_native_type_pointer);
|
||||||
auto * rhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(rhs_column, {1}) : nullptr;
|
auto * rhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(rhs_column, {1}) : nullptr;
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
#endif
|
|
||||||
auto * ty_rhs_column_data = llvm::cast<llvm::PointerType>(rhs_column_data->getType()->getScalarType())->getElementType();
|
auto * ty_rhs_column_data = llvm::cast<llvm::PointerType>(rhs_column_data->getType()->getScalarType())->getElementType();
|
||||||
llvm::Value * rhs_value = b.CreateLoad(b.CreateInBoundsGEP(ty_rhs_column_data, rhs_column_data, rhs_index_arg));
|
|
||||||
#ifdef __clang__
|
llvm::Value * rhs_cib_gep = b.CreateInBoundsGEP(ty_rhs_column_data, rhs_column_data, rhs_index_arg);
|
||||||
#pragma clang diagnostic pop
|
llvm::Value * rhs_value = b.CreateLoad(rhs_cib_gep->getType()->getPointerElementType(), rhs_cib_gep);
|
||||||
#endif
|
|
||||||
if (rhs_column_null_data)
|
if (rhs_column_null_data)
|
||||||
{
|
{
|
||||||
auto * ty_rhs_column_null_data = llvm::cast<llvm::PointerType>(rhs_column_null_data->getType()->getScalarType())->getElementType();
|
auto * ty_rhs_column_null_data = llvm::cast<llvm::PointerType>(rhs_column_null_data->getType()->getScalarType())->getElementType();
|
||||||
|
@ -116,29 +116,29 @@ String TransactionLog::serializeTID(const TransactionID & tid)
|
|||||||
|
|
||||||
void TransactionLog::loadEntries(Strings::const_iterator beg, Strings::const_iterator end)
|
void TransactionLog::loadEntries(Strings::const_iterator beg, Strings::const_iterator end)
|
||||||
{
|
{
|
||||||
std::vector<std::future<Coordination::GetResponse>> futures;
|
|
||||||
size_t entries_count = std::distance(beg, end);
|
size_t entries_count = std::distance(beg, end);
|
||||||
if (!entries_count)
|
if (!entries_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String last_entry = *std::prev(end);
|
String last_entry = *std::prev(end);
|
||||||
LOG_TRACE(log, "Loading {} entries from {}: {}..{}", entries_count, zookeeper_path_log, *beg, last_entry);
|
LOG_TRACE(log, "Loading {} entries from {}: {}..{}", entries_count, zookeeper_path_log, *beg, last_entry);
|
||||||
futures.reserve(entries_count);
|
std::vector<std::string> entry_paths;
|
||||||
|
entry_paths.reserve(entries_count);
|
||||||
for (auto it = beg; it != end; ++it)
|
for (auto it = beg; it != end; ++it)
|
||||||
futures.emplace_back(TSA_READ_ONE_THREAD(zookeeper)->asyncGet(fs::path(zookeeper_path_log) / *it));
|
entry_paths.emplace_back(fs::path(zookeeper_path_log) / *it);
|
||||||
|
|
||||||
|
auto entries = TSA_READ_ONE_THREAD(zookeeper)->get(entry_paths);
|
||||||
std::vector<std::pair<TIDHash, CSNEntry>> loaded;
|
std::vector<std::pair<TIDHash, CSNEntry>> loaded;
|
||||||
loaded.reserve(entries_count);
|
loaded.reserve(entries_count);
|
||||||
auto it = beg;
|
auto it = beg;
|
||||||
for (size_t i = 0; i < entries_count; ++i, ++it)
|
for (size_t i = 0; i < entries_count; ++i, ++it)
|
||||||
{
|
{
|
||||||
auto res = futures[i].get();
|
auto res = entries[i];
|
||||||
CSN csn = deserializeCSN(*it);
|
CSN csn = deserializeCSN(*it);
|
||||||
TransactionID tid = deserializeTID(res.data);
|
TransactionID tid = deserializeTID(res.data);
|
||||||
loaded.emplace_back(tid.getHash(), CSNEntry{csn, tid});
|
loaded.emplace_back(tid.getHash(), CSNEntry{csn, tid});
|
||||||
LOG_TEST(log, "Got entry {} -> {}", tid, csn);
|
LOG_TEST(log, "Got entry {} -> {}", tid, csn);
|
||||||
}
|
}
|
||||||
futures.clear();
|
|
||||||
|
|
||||||
NOEXCEPT_SCOPE_STRICT({
|
NOEXCEPT_SCOPE_STRICT({
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
|
@ -83,6 +83,7 @@ NamesAndTypesList ZooKeeperLogElement::getNamesAndTypes()
|
|||||||
{"List", static_cast<Int16>(Coordination::OpNum::List)},
|
{"List", static_cast<Int16>(Coordination::OpNum::List)},
|
||||||
{"Check", static_cast<Int16>(Coordination::OpNum::Check)},
|
{"Check", static_cast<Int16>(Coordination::OpNum::Check)},
|
||||||
{"Multi", static_cast<Int16>(Coordination::OpNum::Multi)},
|
{"Multi", static_cast<Int16>(Coordination::OpNum::Multi)},
|
||||||
|
{"MultiRead", static_cast<Int16>(Coordination::OpNum::MultiRead)},
|
||||||
{"Auth", static_cast<Int16>(Coordination::OpNum::Auth)},
|
{"Auth", static_cast<Int16>(Coordination::OpNum::Auth)},
|
||||||
{"SessionID", static_cast<Int16>(Coordination::OpNum::SessionID)},
|
{"SessionID", static_cast<Int16>(Coordination::OpNum::SessionID)},
|
||||||
{"FilteredList", static_cast<Int16>(Coordination::OpNum::FilteredList)},
|
{"FilteredList", static_cast<Int16>(Coordination::OpNum::FilteredList)},
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user