mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 23:52:03 +00:00
Merge branch 'ClickHouse:master' into interval_type_conversion
This commit is contained in:
commit
d82e9b79da
@ -187,14 +187,6 @@ else ()
|
||||
set(NO_WHOLE_ARCHIVE --no-whole-archive)
|
||||
endif ()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE")
|
||||
# Can be lld or ld-lld or lld-13 or /path/to/lld.
|
||||
if (LINKER_NAME MATCHES "lld")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gdb-index")
|
||||
message (STATUS "Adding .gdb-index via --gdb-index linker option.")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (NOT (SANITIZE_COVERAGE OR WITH_COVERAGE)
|
||||
AND (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE"
|
||||
OR CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO"
|
||||
@ -402,7 +394,7 @@ if ((NOT OS_LINUX AND NOT OS_ANDROID) OR (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG")
|
||||
set(ENABLE_GWP_ASAN OFF)
|
||||
endif ()
|
||||
|
||||
option (ENABLE_FIU "Enable Fiu" ON)
|
||||
option (ENABLE_LIBFIU "Enable libfiu" ON)
|
||||
|
||||
option(WERROR "Enable -Werror compiler option" ON)
|
||||
|
||||
@ -428,12 +420,17 @@ if (NOT SANITIZE)
|
||||
set (CMAKE_POSITION_INDEPENDENT_CODE OFF)
|
||||
endif()
|
||||
|
||||
if (OS_LINUX AND NOT (ARCH_AARCH64 OR ARCH_S390X) AND NOT SANITIZE)
|
||||
# Slightly more efficient code can be generated
|
||||
# It's disabled for ARM because otherwise ClickHouse cannot run on Android.
|
||||
if (NOT OS_ANDROID AND OS_LINUX AND NOT ARCH_S390X AND NOT SANITIZE)
|
||||
# Using '-no-pie' builds executables with fixed addresses, resulting in slightly more efficient code
|
||||
# and keeping binary addresses constant even with ASLR enabled.
|
||||
# Disabled on Android as it requires PIE: https://source.android.com/docs/security/enhancements#android-5
|
||||
# Disabled on IBM S390X due to build issues with 'no-pie'
|
||||
# Disabled with sanitizers to avoid issues with maximum relocation size: https://github.com/ClickHouse/ClickHouse/pull/49145
|
||||
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-pie")
|
||||
set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fno-pie")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -Wl,-no-pie")
|
||||
else ()
|
||||
message (WARNING "ClickHouse is built as PIE, system.trace_log will contain invalid addresses after server restart.")
|
||||
endif ()
|
||||
|
||||
if (ENABLE_TESTS)
|
||||
|
2
contrib/CMakeLists.txt
vendored
2
contrib/CMakeLists.txt
vendored
@ -179,7 +179,7 @@ else()
|
||||
message(STATUS "Not using QPL")
|
||||
endif ()
|
||||
|
||||
if (OS_LINUX AND ARCH_AMD64)
|
||||
if (OS_LINUX AND ARCH_AMD64 AND NOT NO_SSE3_OR_HIGHER)
|
||||
option (ENABLE_QATLIB "Enable Intel® QuickAssist Technology Library (QATlib)" ${ENABLE_LIBRARIES})
|
||||
elseif(ENABLE_QATLIB)
|
||||
message (${RECONFIGURE_MESSAGE_LEVEL} "QATLib is only supported on x86_64")
|
||||
|
@ -27,7 +27,7 @@ if (ENABLE_QAT_OUT_OF_TREE_BUILD)
|
||||
${QAT_AL_INCLUDE_DIR}
|
||||
${QAT_USDM_INCLUDE_DIR}
|
||||
${ZSTD_LIBRARY_DIR})
|
||||
target_compile_definitions(_qatzstd_plugin PRIVATE -DDEBUGLEVEL=0 PUBLIC -DENABLE_ZSTD_QAT_CODEC)
|
||||
target_compile_definitions(_qatzstd_plugin PRIVATE -DDEBUGLEVEL=0)
|
||||
add_library (ch_contrib::qatzstd_plugin ALIAS _qatzstd_plugin)
|
||||
else () # In-tree build
|
||||
message(STATUS "Intel QATZSTD in-tree build")
|
||||
@ -78,7 +78,7 @@ else () # In-tree build
|
||||
${QAT_USDM_INCLUDE_DIR}
|
||||
${ZSTD_LIBRARY_DIR}
|
||||
${LIBQAT_HEADER_DIR})
|
||||
target_compile_definitions(_qatzstd_plugin PRIVATE -DDEBUGLEVEL=0 PUBLIC -DENABLE_ZSTD_QAT_CODEC -DINTREE)
|
||||
target_compile_definitions(_qatzstd_plugin PRIVATE -DDEBUGLEVEL=0 PUBLIC -DINTREE)
|
||||
target_include_directories(_qatzstd_plugin SYSTEM PUBLIC $<BUILD_INTERFACE:${QATZSTD_SRC_DIR}> $<INSTALL_INTERFACE:include>)
|
||||
add_library (ch_contrib::qatzstd_plugin ALIAS _qatzstd_plugin)
|
||||
endif ()
|
||||
|
@ -1,20 +1,21 @@
|
||||
if (NOT ENABLE_FIU)
|
||||
message (STATUS "Not using fiu")
|
||||
if (NOT ENABLE_LIBFIU)
|
||||
message (STATUS "Not using libfiu")
|
||||
return ()
|
||||
endif ()
|
||||
|
||||
set(FIU_DIR "${ClickHouse_SOURCE_DIR}/contrib/libfiu/")
|
||||
set(LIBFIU_DIR "${ClickHouse_SOURCE_DIR}/contrib/libfiu/")
|
||||
|
||||
set(FIU_SOURCES
|
||||
${FIU_DIR}/libfiu/fiu.c
|
||||
${FIU_DIR}/libfiu/fiu-rc.c
|
||||
${FIU_DIR}/libfiu/backtrace.c
|
||||
${FIU_DIR}/libfiu/wtable.c
|
||||
set(LIBFIU_SOURCES
|
||||
${LIBFIU_DIR}/libfiu/fiu.c
|
||||
${LIBFIU_DIR}/libfiu/fiu-rc.c
|
||||
${LIBFIU_DIR}/libfiu/backtrace.c
|
||||
${LIBFIU_DIR}/libfiu/wtable.c
|
||||
)
|
||||
|
||||
set(FIU_HEADERS "${FIU_DIR}/libfiu")
|
||||
set(LIBFIU_HEADERS "${LIBFIU_DIR}/libfiu")
|
||||
|
||||
add_library(_fiu ${FIU_SOURCES})
|
||||
target_compile_definitions(_fiu PUBLIC DUMMY_BACKTRACE)
|
||||
target_include_directories(_fiu PUBLIC ${FIU_HEADERS})
|
||||
add_library(ch_contrib::fiu ALIAS _fiu)
|
||||
add_library(_libfiu ${LIBFIU_SOURCES})
|
||||
target_compile_definitions(_libfiu PUBLIC DUMMY_BACKTRACE)
|
||||
target_compile_definitions(_libfiu PUBLIC FIU_ENABLE)
|
||||
target_include_directories(_libfiu PUBLIC ${LIBFIU_HEADERS})
|
||||
add_library(ch_contrib::libfiu ALIAS _libfiu)
|
||||
|
@ -728,10 +728,6 @@ add_library(_qpl STATIC ${LIB_DEPS})
|
||||
target_include_directories(_qpl
|
||||
PUBLIC $<BUILD_INTERFACE:${QPL_PROJECT_DIR}/include/> $<INSTALL_INTERFACE:include>)
|
||||
|
||||
|
||||
target_compile_definitions(_qpl
|
||||
PUBLIC -DENABLE_QPL_COMPRESSION)
|
||||
|
||||
target_link_libraries(_qpl
|
||||
PRIVATE ch_contrib::accel-config)
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
# docker build -t clickhouse/cctools .
|
||||
|
||||
# This is a hack to significantly reduce the build time of the clickhouse/binary-builder
|
||||
# It's based on the assumption that we don't care of the cctools version so much
|
||||
# It event does not depend on the clickhouse/fasttest in the `docker/images.json`
|
||||
@ -30,5 +32,29 @@ RUN git clone https://github.com/tpoechtrager/cctools-port.git \
|
||||
&& cd ../.. \
|
||||
&& rm -rf cctools-port
|
||||
|
||||
#
|
||||
# GDB
|
||||
#
|
||||
# ld from binutils is 2.38, which has the following error:
|
||||
#
|
||||
# DWARF error: invalid or unhandled FORM value: 0x23
|
||||
#
|
||||
ENV LD=ld.lld-${LLVM_VERSION}
|
||||
ARG GDB_VERSION=15.1
|
||||
RUN apt-get update \
|
||||
&& apt-get install --yes \
|
||||
libgmp-dev \
|
||||
libmpfr-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/cache/debconf /tmp/*
|
||||
RUN wget https://sourceware.org/pub/gdb/releases/gdb-$GDB_VERSION.tar.gz \
|
||||
&& tar -xvf gdb-$GDB_VERSION.tar.gz \
|
||||
&& cd gdb-$GDB_VERSION \
|
||||
&& ./configure --prefix=/opt/gdb \
|
||||
&& make -j $(nproc) \
|
||||
&& make install \
|
||||
&& rm -fr gdb-$GDB_VERSION gdb-$GDB_VERSION.tar.gz
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /cctools /cctools
|
||||
COPY --from=builder /opt/gdb /opt/gdb
|
||||
|
@ -83,7 +83,7 @@ RUN arch=${TARGETARCH:-amd64} \
|
||||
|
||||
# Give suid to gdb to grant it attach permissions
|
||||
# chmod 777 to make the container user independent
|
||||
RUN chmod u+s /usr/bin/gdb \
|
||||
RUN chmod u+s /opt/gdb/bin/gdb \
|
||||
&& mkdir -p /var/lib/clickhouse \
|
||||
&& chmod 777 /var/lib/clickhouse
|
||||
|
||||
|
@ -11,7 +11,6 @@ RUN apt-get update \
|
||||
curl \
|
||||
default-jre \
|
||||
g++ \
|
||||
gdb \
|
||||
iproute2 \
|
||||
krb5-user \
|
||||
libicu-dev \
|
||||
@ -73,3 +72,6 @@ maxClientCnxns=80' > /opt/zookeeper/conf/zoo.cfg && \
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
COPY --from=clickhouse/cctools:0d6b90a7a490 /opt/gdb /opt/gdb
|
||||
ENV PATH="/opt/gdb/bin:${PATH}"
|
||||
|
@ -30,7 +30,6 @@ RUN apt-get update \
|
||||
luajit \
|
||||
libssl-dev \
|
||||
libcurl4-openssl-dev \
|
||||
gdb \
|
||||
default-jdk \
|
||||
software-properties-common \
|
||||
libkrb5-dev \
|
||||
@ -87,6 +86,8 @@ COPY modprobe.sh /usr/local/bin/modprobe
|
||||
COPY dockerd-entrypoint.sh /usr/local/bin/
|
||||
COPY misc/ /misc/
|
||||
|
||||
COPY --from=clickhouse/cctools:0d6b90a7a490 /opt/gdb /opt/gdb
|
||||
ENV PATH="/opt/gdb/bin:${PATH}"
|
||||
|
||||
# Same options as in test/base/Dockerfile
|
||||
# (in case you need to override them in tests)
|
||||
|
@ -9,7 +9,6 @@ RUN apt-get update \
|
||||
curl \
|
||||
dmidecode \
|
||||
g++ \
|
||||
gdb \
|
||||
git \
|
||||
gnuplot \
|
||||
imagemagick \
|
||||
@ -42,6 +41,9 @@ RUN pip3 --no-cache-dir install -r requirements.txt
|
||||
|
||||
COPY run.sh /
|
||||
|
||||
COPY --from=clickhouse/cctools:0d6b90a7a490 /opt/gdb /opt/gdb
|
||||
ENV PATH="/opt/gdb/bin:${PATH}"
|
||||
|
||||
CMD ["bash", "/run.sh"]
|
||||
|
||||
# docker run --network=host --volume <workspace>:/workspace --volume=<output>:/output -e PR_TO_TEST=<> -e SHA_TO_TEST=<> clickhouse/performance-comparison
|
||||
|
@ -232,15 +232,26 @@ function run_tests()
|
||||
|
||||
set +e
|
||||
|
||||
TEST_ARGS=(
|
||||
-j 2
|
||||
--testname
|
||||
--shard
|
||||
--zookeeper
|
||||
--check-zookeeper-session
|
||||
--no-stateless
|
||||
--hung-check
|
||||
--print-time
|
||||
--capture-client-stacktrace
|
||||
"${ADDITIONAL_OPTIONS[@]}"
|
||||
"$SKIP_TESTS_OPTION"
|
||||
)
|
||||
if [[ -n "$USE_PARALLEL_REPLICAS" ]] && [[ "$USE_PARALLEL_REPLICAS" -eq 1 ]]; then
|
||||
clickhouse-test --client="clickhouse-client --allow_experimental_parallel_reading_from_replicas=1 --parallel_replicas_for_non_replicated_merge_tree=1 \
|
||||
--max_parallel_replicas=100 --cluster_for_parallel_replicas='parallel_replicas'" \
|
||||
-j 2 --testname --shard --zookeeper --check-zookeeper-session --no-stateless --no-parallel-replicas --hung-check --print-time "${ADDITIONAL_OPTIONS[@]}" \
|
||||
"$SKIP_TESTS_OPTION" 2>&1 | ts '%Y-%m-%d %H:%M:%S' | tee test_output/test_result.txt
|
||||
else
|
||||
clickhouse-test -j 2 --testname --shard --zookeeper --check-zookeeper-session --no-stateless --hung-check --print-time "${ADDITIONAL_OPTIONS[@]}" \
|
||||
"$SKIP_TESTS_OPTION" 2>&1 | ts '%Y-%m-%d %H:%M:%S' | tee test_output/test_result.txt
|
||||
TEST_ARGS+=(
|
||||
--client="clickhouse-client --allow_experimental_parallel_reading_from_replicas=1 --parallel_replicas_for_non_replicated_merge_tree=1 --max_parallel_replicas=100 --cluster_for_parallel_replicas='parallel_replicas'"
|
||||
--no-parallel-replicas
|
||||
)
|
||||
fi
|
||||
clickhouse-test "${TEST_ARGS[@]}" 2>&1 | ts '%Y-%m-%d %H:%M:%S' | tee test_output/test_result.txt
|
||||
set -e
|
||||
}
|
||||
|
||||
|
@ -69,8 +69,8 @@ ENV MAX_RUN_TIME=0
|
||||
|
||||
# Unrelated to vars in setup_minio.sh, but should be the same there
|
||||
# to have the same binaries for local running scenario
|
||||
ARG MINIO_SERVER_VERSION=2022-01-03T18-22-58Z
|
||||
ARG MINIO_CLIENT_VERSION=2022-01-05T23-52-51Z
|
||||
ARG MINIO_SERVER_VERSION=2024-08-03T04-33-23Z
|
||||
ARG MINIO_CLIENT_VERSION=2024-07-31T15-58-33Z
|
||||
ARG TARGETARCH
|
||||
|
||||
# Download Minio-related binaries
|
||||
|
@ -54,8 +54,6 @@ source /utils.lib
|
||||
/usr/share/clickhouse-test/config/install.sh
|
||||
|
||||
./setup_minio.sh stateless
|
||||
./mc admin trace clickminio > /test_output/minio.log &
|
||||
MC_ADMIN_PID=$!
|
||||
|
||||
./setup_hdfs_minicluster.sh
|
||||
|
||||
@ -176,6 +174,55 @@ done
|
||||
setup_logs_replication
|
||||
attach_gdb_to_clickhouse
|
||||
|
||||
# create tables for minio log webhooks
|
||||
clickhouse-client --query "CREATE TABLE minio_audit_logs
|
||||
(
|
||||
log String,
|
||||
event_time DateTime64(9) MATERIALIZED parseDateTime64BestEffortOrZero(trim(BOTH '\"' FROM JSONExtractRaw(log, 'time')), 9, 'UTC')
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY tuple()"
|
||||
|
||||
clickhouse-client --query "CREATE TABLE minio_server_logs
|
||||
(
|
||||
log String,
|
||||
event_time DateTime64(9) MATERIALIZED parseDateTime64BestEffortOrZero(trim(BOTH '\"' FROM JSONExtractRaw(log, 'time')), 9, 'UTC')
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY tuple()"
|
||||
|
||||
# create minio log webhooks for both audit and server logs
|
||||
# use async inserts to avoid creating too many parts
|
||||
./mc admin config set clickminio logger_webhook:ch_server_webhook endpoint="http://localhost:8123/?async_insert=1&wait_for_async_insert=0&async_insert_busy_timeout_min_ms=5000&async_insert_busy_timeout_max_ms=5000&async_insert_max_query_number=1000&async_insert_max_data_size=10485760&query=INSERT%20INTO%20minio_server_logs%20FORMAT%20LineAsString" queue_size=1000000 batch_size=500
|
||||
./mc admin config set clickminio audit_webhook:ch_audit_webhook endpoint="http://localhost:8123/?async_insert=1&wait_for_async_insert=0&async_insert_busy_timeout_min_ms=5000&async_insert_busy_timeout_max_ms=5000&async_insert_max_query_number=1000&async_insert_max_data_size=10485760&query=INSERT%20INTO%20minio_audit_logs%20FORMAT%20LineAsString" queue_size=1000000 batch_size=500
|
||||
|
||||
max_retries=100
|
||||
retry=1
|
||||
while [ $retry -le $max_retries ]; do
|
||||
echo "clickminio restart attempt $retry:"
|
||||
|
||||
output=$(./mc admin service restart clickminio --wait --json 2>&1 | jq -r .status)
|
||||
echo "Output of restart status: $output"
|
||||
|
||||
expected_output="success
|
||||
success"
|
||||
if [ "$output" = "$expected_output" ]; then
|
||||
echo "Restarted clickminio successfully."
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
|
||||
retry=$((retry + 1))
|
||||
done
|
||||
|
||||
if [ $retry -gt $max_retries ]; then
|
||||
echo "Failed to restart clickminio after $max_retries attempts."
|
||||
fi
|
||||
|
||||
./mc admin trace clickminio > /test_output/minio.log &
|
||||
MC_ADMIN_PID=$!
|
||||
|
||||
function fn_exists() {
|
||||
declare -F "$1" > /dev/null;
|
||||
}
|
||||
@ -264,11 +311,22 @@ function run_tests()
|
||||
TIMEOUT=$((MAX_RUN_TIME - 800 > 8400 ? 8400 : MAX_RUN_TIME - 800))
|
||||
START_TIME=${SECONDS}
|
||||
set +e
|
||||
timeout --preserve-status --signal TERM --kill-after 60m ${TIMEOUT}s \
|
||||
clickhouse-test --testname --shard --zookeeper --check-zookeeper-session --hung-check --print-time \
|
||||
--no-drop-if-fail --test-runs "$NUM_TRIES" "${ADDITIONAL_OPTIONS[@]}" 2>&1 \
|
||||
| ts '%Y-%m-%d %H:%M:%S' \
|
||||
| tee -a test_output/test_result.txt
|
||||
|
||||
TEST_ARGS=(
|
||||
--testname
|
||||
--shard
|
||||
--zookeeper
|
||||
--check-zookeeper-session
|
||||
--hung-check
|
||||
--print-time
|
||||
--no-drop-if-fail
|
||||
--capture-client-stacktrace
|
||||
--test-runs "$NUM_TRIES"
|
||||
"${ADDITIONAL_OPTIONS[@]}"
|
||||
)
|
||||
timeout --preserve-status --signal TERM --kill-after 60m ${TIMEOUT}s clickhouse-test "${TEST_ARGS[@]}" 2>&1 \
|
||||
| ts '%Y-%m-%d %H:%M:%S' \
|
||||
| tee -a test_output/test_result.txt
|
||||
set -e
|
||||
DURATION=$((SECONDS - START_TIME))
|
||||
|
||||
@ -328,6 +386,14 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# collect minio audit and server logs
|
||||
# wait for minio to flush its batch if it has any
|
||||
sleep 1
|
||||
clickhouse-client -q "SYSTEM FLUSH ASYNC INSERT QUEUE"
|
||||
clickhouse-client -q "SELECT log FROM minio_audit_logs ORDER BY event_time INTO OUTFILE '/test_output/minio_audit_logs.jsonl.zst' FORMAT JSONEachRow"
|
||||
clickhouse-client -q "SELECT log FROM minio_server_logs ORDER BY event_time INTO OUTFILE '/test_output/minio_server_logs.jsonl.zst' FORMAT JSONEachRow"
|
||||
|
||||
# Stop server so we can safely read data with clickhouse-local.
|
||||
# Why do we read data with clickhouse-local?
|
||||
# Because it's the simplest way to read it when server has crashed.
|
||||
|
@ -59,8 +59,8 @@ find_os() {
|
||||
download_minio() {
|
||||
local os
|
||||
local arch
|
||||
local minio_server_version=${MINIO_SERVER_VERSION:-2022-09-07T22-25-02Z}
|
||||
local minio_client_version=${MINIO_CLIENT_VERSION:-2022-08-28T20-08-11Z}
|
||||
local minio_server_version=${MINIO_SERVER_VERSION:-2024-08-03T04-33-23Z}
|
||||
local minio_client_version=${MINIO_CLIENT_VERSION:-2024-07-31T15-58-33Z}
|
||||
|
||||
os=$(find_os)
|
||||
arch=$(find_arch)
|
||||
@ -82,10 +82,10 @@ setup_minio() {
|
||||
local test_type=$1
|
||||
./mc alias set clickminio http://localhost:11111 clickhouse clickhouse
|
||||
./mc admin user add clickminio test testtest
|
||||
./mc admin policy set clickminio readwrite user=test
|
||||
./mc admin policy attach clickminio readwrite --user=test
|
||||
./mc mb --ignore-existing clickminio/test
|
||||
if [ "$test_type" = "stateless" ]; then
|
||||
./mc policy set public clickminio/test
|
||||
./mc anonymous set public clickminio/test
|
||||
fi
|
||||
}
|
||||
|
||||
@ -148,4 +148,4 @@ main() {
|
||||
setup_aws_credentials
|
||||
}
|
||||
|
||||
main "$@"
|
||||
main "$@"
|
||||
|
@ -44,7 +44,6 @@ RUN apt-get update \
|
||||
bash \
|
||||
bsdmainutils \
|
||||
build-essential \
|
||||
gdb \
|
||||
git \
|
||||
gperf \
|
||||
moreutils \
|
||||
@ -58,3 +57,6 @@ RUN apt-get update \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/cache/debconf /tmp/*
|
||||
|
||||
COPY process_functional_tests_result.py /
|
||||
|
||||
COPY --from=clickhouse/cctools:0d6b90a7a490 /opt/gdb /opt/gdb
|
||||
ENV PATH="/opt/gdb/bin:${PATH}"
|
||||
|
@ -14,7 +14,7 @@ Each functional test sends one or multiple queries to the running ClickHouse ser
|
||||
|
||||
Tests are located in `queries` directory. There are two subdirectories: `stateless` and `stateful`. Stateless tests run queries without any preloaded test data - they often create small synthetic datasets on the fly, within the test itself. Stateful tests require preloaded test data from ClickHouse and it is available to general public.
|
||||
|
||||
Each test can be one of two types: `.sql` and `.sh`. `.sql` test is the simple SQL script that is piped to `clickhouse-client --multiquery`. `.sh` test is a script that is run by itself. SQL tests are generally preferable to `.sh` tests. You should use `.sh` tests only when you have to test some feature that cannot be exercised from pure SQL, such as piping some input data into `clickhouse-client` or testing `clickhouse-local`.
|
||||
Each test can be one of two types: `.sql` and `.sh`. `.sql` test is the simple SQL script that is piped to `clickhouse-client`. `.sh` test is a script that is run by itself. SQL tests are generally preferable to `.sh` tests. You should use `.sh` tests only when you have to test some feature that cannot be exercised from pure SQL, such as piping some input data into `clickhouse-client` or testing `clickhouse-local`.
|
||||
|
||||
:::note
|
||||
A common mistake when testing data types `DateTime` and `DateTime64` is assuming that the server uses a specific time zone (e.g. "UTC"). This is not the case, time zones in CI test runs
|
||||
@ -38,7 +38,7 @@ For more options, see `tests/clickhouse-test --help`. You can simply run all tes
|
||||
|
||||
### Adding a New Test
|
||||
|
||||
To add new test, create a `.sql` or `.sh` file in `queries/0_stateless` directory, check it manually and then generate `.reference` file in the following way: `clickhouse-client --multiquery < 00000_test.sql > 00000_test.reference` or `./00000_test.sh > ./00000_test.reference`.
|
||||
To add new test, create a `.sql` or `.sh` file in `queries/0_stateless` directory, check it manually and then generate `.reference` file in the following way: `clickhouse-client < 00000_test.sql > 00000_test.reference` or `./00000_test.sh > ./00000_test.reference`.
|
||||
|
||||
Tests should use (create, drop, etc) only tables in `test` database that is assumed to be created beforehand; also tests can use temporary tables.
|
||||
|
||||
|
@ -61,6 +61,7 @@ Engines in the family:
|
||||
- [RabbitMQ](../../engines/table-engines/integrations/rabbitmq.md)
|
||||
- [PostgreSQL](../../engines/table-engines/integrations/postgresql.md)
|
||||
- [S3Queue](../../engines/table-engines/integrations/s3queue.md)
|
||||
- [TimeSeries](../../engines/table-engines/integrations/time-series.md)
|
||||
|
||||
### Special Engines {#special-engines}
|
||||
|
||||
|
295
docs/en/engines/table-engines/integrations/time-series.md
Normal file
295
docs/en/engines/table-engines/integrations/time-series.md
Normal file
@ -0,0 +1,295 @@
|
||||
---
|
||||
slug: /en/engines/table-engines/special/time_series
|
||||
sidebar_position: 60
|
||||
sidebar_label: TimeSeries
|
||||
---
|
||||
|
||||
# TimeSeries Engine [Experimental]
|
||||
|
||||
A table engine storing time series, i.e. a set of values associated with timestamps and tags (or labels):
|
||||
|
||||
```
|
||||
metric_name1[tag1=value1, tag2=value2, ...] = {timestamp1: value1, timestamp2: value2, ...}
|
||||
metric_name2[...] = ...
|
||||
```
|
||||
|
||||
:::info
|
||||
This is an experimental feature that may change in backwards-incompatible ways in the future releases.
|
||||
Enable usage of the TimeSeries table engine
|
||||
with [allow_experimental_time_series_table](../../../operations/settings/settings.md#allow-experimental-time-series-table) setting.
|
||||
Input the command `set allow_experimental_time_series_table = 1`.
|
||||
:::
|
||||
|
||||
## Syntax {#syntax}
|
||||
|
||||
``` sql
|
||||
CREATE TABLE name [(columns)] ENGINE=TimeSeries
|
||||
[SETTINGS var1=value1, ...]
|
||||
[DATA db.data_table_name | DATA ENGINE data_table_engine(arguments)]
|
||||
[TAGS db.tags_table_name | TAGS ENGINE tags_table_engine(arguments)]
|
||||
[METRICS db.metrics_table_name | METRICS ENGINE metrics_table_engine(arguments)]
|
||||
```
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
It's easier to start with everything set by default (it's allowed to create a `TimeSeries` table without specifying a list of columns):
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table ENGINE=TimeSeries
|
||||
```
|
||||
|
||||
Then this table can be used with the following protocols (a port must be assigned in the server configuration):
|
||||
- [prometheus remote-write](../../../interfaces/prometheus.md#remote-write)
|
||||
- [prometheus remote-read](../../../interfaces/prometheus.md#remote-read)
|
||||
|
||||
## Target tables {#target-tables}
|
||||
|
||||
A `TimeSeries` table doesn't have its own data, everything is stored in its target tables.
|
||||
This is similar to how a [materialized view](../../../sql-reference/statements/create/view#materialized-view) works,
|
||||
with the difference that a materialized view has one target table
|
||||
whereas a `TimeSeries` table has three target tables named [data]{#data-table}, [tags]{#tags-table], and [metrics]{#metrics-table}.
|
||||
|
||||
The target tables can be either specified explicitly in the `CREATE TABLE` query
|
||||
or the `TimeSeries` table engine can generate inner target tables automatically.
|
||||
|
||||
The target tables are the following:
|
||||
1. The _data_ table {#data-table} contains time series associated with some identifier.
|
||||
The _data_ table must have columns:
|
||||
|
||||
| Name | Mandatory? | Default type | Possible types | Description |
|
||||
|---|---|---|---|---|
|
||||
| `id` | [x] | `UUID` | any | Identifies a combination of a metric names and tags |
|
||||
| `timestamp` | [x] | `DateTime64(3)` | `DateTime64(X)` | A time point |
|
||||
| `value` | [x] | `Float64` | `Float32` or `Float64` | A value associated with the `timestamp` |
|
||||
|
||||
2. The _tags_ table {#tags-table} contains identifiers calculated for each combination of a metric name and tags.
|
||||
The _tags_ table must have columns:
|
||||
|
||||
| Name | Mandatory? | Default type | Possible types | Description |
|
||||
|---|---|---|---|---|
|
||||
| `id` | [x] | `UUID` | any (must match the type of `id` in the [data]{#data-table} table) | An `id` identifies a combination of a metric name and tags. The DEFAULT expression specifies how to calculate such an identifier |
|
||||
| `metric_name` | [x] | `LowCardinality(String)` | `String` or `LowCardinality(String)` | The name of a metric |
|
||||
| `<tag_value_column>` | [ ] | `String` | `String` or `LowCardinality(String)` or `LowCardinality(Nullable(String))` | The value of a specific tag, the tag's name and the name of a corresponding column are specified in the [tags_to_columns](#settings) setting |
|
||||
| `tags` | [x] | `Map(LowCardinality(String), String)` | `Map(String, String)` or `Map(LowCardinality(String), String)` or `Map(LowCardinality(String), LowCardinality(String))` | Map of tags excluding the tag `__name__` containing the name of a metric and excluding tags with names enumerated in the [tags_to_columns](#settings) setting |
|
||||
| `all_tags` | [ ] | `Map(String, String)` | `Map(String, String)` or `Map(LowCardinality(String), String)` or `Map(LowCardinality(String), LowCardinality(String))` | Ephemeral column, each row is a map of all the tags excluding only the tag `__name__` containing the name of a metric. The only purpose of that column is to be used while calculating `id` |
|
||||
| `min_time` | [ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` or `Nullable(DateTime64(X))` | Minimum timestamp of time series with that `id`. The column is created if [store_min_time_and_max_time](#settings) is `true` |
|
||||
| `max_time` | [ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` or `Nullable(DateTime64(X))` | Maximum timestamp of time series with that `id`. The column is created if [store_min_time_and_max_time](#settings) is `true` |
|
||||
|
||||
3. The _metrics_ table {#metrics-table} contains some information about metrics been collected, the types of those metrics and their descriptions.
|
||||
The _metrics_ table must have columns:
|
||||
|
||||
| Name | Mandatory? | Default type | Possible types | Description |
|
||||
|---|---|---|---|---|
|
||||
| `metric_family_name` | [x] | `String` | `String` or `LowCardinality(String)` | The name of a metric family |
|
||||
| `type` | [x] | `String` | `String` or `LowCardinality(String)` | The type of a metric family, one of "counter", "gauge", "summary", "stateset", "histogram", "gaugehistogram" |
|
||||
| `unit` | [x] | `String` | `String` or `LowCardinality(String)` | The unit used in a metric |
|
||||
| `help` | [x] | `String` | `String` or `LowCardinality(String)` | The description of a metric |
|
||||
|
||||
Any row inserted into a `TimeSeries` table will be in fact stored in those three target tables.
|
||||
A `TimeSeries` table contains all those columns from the [data]{#data-table}, [tags]{#tags-table}, [metrics]{#metrics-table} tables.
|
||||
|
||||
## Creation {#creation}
|
||||
|
||||
There are multiple ways to create a table with the `TimeSeries` table engine.
|
||||
The simplest statement
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table ENGINE=TimeSeries
|
||||
```
|
||||
|
||||
will actually create the following table (you can see that by executing `SHOW CREATE TABLE my_table`):
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table
|
||||
(
|
||||
`id` UUID DEFAULT reinterpretAsUUID(sipHash128(metric_name, all_tags)),
|
||||
`timestamp` DateTime64(3),
|
||||
`value` Float64,
|
||||
`metric_name` LowCardinality(String),
|
||||
`tags` Map(LowCardinality(String), String),
|
||||
`all_tags` Map(String, String),
|
||||
`min_time` Nullable(DateTime64(3)),
|
||||
`max_time` Nullable(DateTime64(3)),
|
||||
`metric_family_name` String,
|
||||
`type` String,
|
||||
`unit` String,
|
||||
`help` String
|
||||
)
|
||||
ENGINE = TimeSeries
|
||||
DATA ENGINE = MergeTree ORDER BY (id, timestamp)
|
||||
DATA INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
TAGS ENGINE = AggregatingMergeTree PRIMARY KEY metric_name ORDER BY (metric_name, id)
|
||||
TAGS INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
METRICS ENGINE = ReplacingMergeTree ORDER BY metric_family_name
|
||||
METRICS INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
```
|
||||
|
||||
So the columns were generated automatically and also there are three inner UUIDs in this statement -
|
||||
one per each inner target table that was created.
|
||||
(Inner UUIDs are not shown normally until setting
|
||||
[show_table_uuid_in_table_create_query_if_not_nil](../../../operations/settings/settings#show_table_uuid_in_table_create_query_if_not_nil)
|
||||
is set.)
|
||||
|
||||
Inner target tables have names like `.inner_id.data.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
|
||||
`.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, `.inner_id.metrics.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
and each target table has columns which is a subset of the columns of the main `TimeSeries` table:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE default.`.inner_id.data.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
(
|
||||
`id` UUID,
|
||||
`timestamp` DateTime64(3),
|
||||
`value` Float64
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY (id, timestamp)
|
||||
```
|
||||
|
||||
``` sql
|
||||
CREATE TABLE default.`.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
(
|
||||
`id` UUID DEFAULT reinterpretAsUUID(sipHash128(metric_name, all_tags)),
|
||||
`metric_name` LowCardinality(String),
|
||||
`tags` Map(LowCardinality(String), String),
|
||||
`all_tags` Map(String, String) EPHEMERAL,
|
||||
`min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
|
||||
`max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3)))
|
||||
)
|
||||
ENGINE = AggregatingMergeTree
|
||||
PRIMARY KEY metric_name
|
||||
ORDER BY (metric_name, id)
|
||||
```
|
||||
|
||||
``` sql
|
||||
CREATE TABLE default.`.inner_id.metrics.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
(
|
||||
`metric_family_name` String,
|
||||
`type` String,
|
||||
`unit` String,
|
||||
`help` String
|
||||
)
|
||||
ENGINE = ReplacingMergeTree
|
||||
ORDER BY metric_family_name
|
||||
```
|
||||
|
||||
## Adjusting types of columns {#adjusting-column-types}
|
||||
|
||||
You can adjust the types of almost any column of the inner target tables by specifying them explicitly
|
||||
while defining the main table. For example,
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table
|
||||
(
|
||||
timestamp DateTime64(6)
|
||||
) ENGINE=TimeSeries
|
||||
```
|
||||
|
||||
will make the inner [data]{#data-table} table store timestamp in microseconds instead of milliseconds:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE default.`.inner_id.data.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
(
|
||||
`id` UUID,
|
||||
`timestamp` DateTime64(6),
|
||||
`value` Float64
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY (id, timestamp)
|
||||
```
|
||||
|
||||
## The `id` column {#id-column}
|
||||
|
||||
The `id` column contains identifiers, every identifier is calculated for a combination of a metric name and tags.
|
||||
The DEFAULT expression for the `id` column is an expression which will be used to calculate such identifiers.
|
||||
Both the type of the `id` column and that expression can be adjusted by specifying them explicitly:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table
|
||||
(
|
||||
id UInt64 DEFAULT sipHash64(metric_name, all_tags)
|
||||
) ENGINE=TimeSeries
|
||||
```
|
||||
|
||||
## The `tags` and `all_tags` columns {#tags-and-all-tags}
|
||||
|
||||
There are two columns containing maps of tags - `tags` and `all_tags`. In this example they mean the same, however they can be different
|
||||
if setting `tags_to_columns` is used. This setting allows to specify that a specific tag should be stored in a separate column instead of storing
|
||||
in a map inside the `tags` column:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table ENGINE=TimeSeries SETTINGS = {'instance': 'instance', 'job': 'job'}
|
||||
```
|
||||
|
||||
This statement will add columns
|
||||
```
|
||||
`instance` String,
|
||||
`job` String
|
||||
```
|
||||
to the definition of both `my_table` and its inner [tags]{#tags-table} target table. In this case the `tags` column will not contain tags `instance` and `job`,
|
||||
but the `all_tags` column will contain them. The `all_tags` column is ephemeral and its only purpose to be used in the DEFAULT expression
|
||||
for the `id` column.
|
||||
|
||||
The types of columns can be adjusted by specifying them explicitly:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table (instance LowCardinality(String), job LowCardinality(Nullable(String)))
|
||||
ENGINE=TimeSeries SETTINGS = {'instance': 'instance', 'job': 'job'}
|
||||
```
|
||||
|
||||
## Table engines of inner target tables {#inner-table-engines}
|
||||
|
||||
By default inner target tables use the following table engines:
|
||||
- the [data]{#data-table} table uses [MergeTree](../mergetree-family/mergetree);
|
||||
- the [tags]{#tags-table} table uses [AggregatingMergeTree](../mergetree-family/aggregatingmergetree) because the same data is often inserted multiple times to this table so we need a way
|
||||
to remove duplicates, and also because it's required to do aggregation for columns `min_time` and `max_time`;
|
||||
- the [metrics]{#metrics-table} table uses [ReplacingMergeTree](../mergetree-family/replacingmergetree) because the same data is often inserted multiple times to this table so we need a way
|
||||
to remove duplicates.
|
||||
|
||||
Other table engines also can be used for inner target tables if it's specified so:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE my_table ENGINE=TimeSeries
|
||||
DATA ENGINE=ReplicatedMergeTree
|
||||
TAGS ENGINE=ReplicatedAggregatingMergeTree
|
||||
METRICS ENGINE=ReplicatedReplacingMergeTree
|
||||
```
|
||||
|
||||
## External target tables {#external-target-tables}
|
||||
|
||||
It's possible to make a `TimeSeries` table use a manually created table:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE data_for_my_table
|
||||
(
|
||||
`id` UUID,
|
||||
`timestamp` DateTime64(3),
|
||||
`value` Float64
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY (id, timestamp);
|
||||
|
||||
CREATE TABLE tags_for_my_table ...
|
||||
|
||||
CREATE TABLE metrics_for_my_table ...
|
||||
|
||||
CREATE TABLE my_table ENGINE=TimeSeries DATA data_for_my_table TAGS tags_for_my_table METRICS metrics_for_my_table;
|
||||
```
|
||||
|
||||
## Settings {#settings}
|
||||
|
||||
Here is a list of settings which can be specified while defining a `TimeSeries` table:
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `tags_to_columns` | Map | {} | Map specifying which tags should be put to separate columns in the [tags]{#tags-table} table. Syntax: `{'tag1': 'column1', 'tag2' : column2, ...}` |
|
||||
| `use_all_tags_column_to_generate_id` | Bool | true | When generating an expression to calculate an identifier of a time series, this flag enables using the `all_tags` column in that calculation |
|
||||
| `store_min_time_and_max_time` | Bool | true | If set to true then the table will store `min_time` and `max_time` for each time series |
|
||||
| `aggregate_min_time_and_max_time` | Bool | true | When creating an inner target `tags` table, this flag enables using `SimpleAggregateFunction(min, Nullable(DateTime64(3)))` instead of just `Nullable(DateTime64(3))` as the type of the `min_time` column, and the same for the `max_time` column |
|
||||
| `filter_by_min_time_and_max_time` | Bool | true | If set to true then the table will use the `min_time` and `max_time` columns for filtering time series |
|
||||
|
||||
# Functions {#functions}
|
||||
|
||||
Here is a list of functions supporting a `TimeSeries` table as an argument:
|
||||
- [timeSeriesData](../../../sql-reference/table-functions/timeSeriesData.md)
|
||||
- [timeSeriesTags](../../../sql-reference/table-functions/timeSeriesTags.md)
|
||||
- [timeSeriesMetrics](../../../sql-reference/table-functions/timeSeriesMetrics.md)
|
160
docs/en/interfaces/prometheus.md
Normal file
160
docs/en/interfaces/prometheus.md
Normal file
@ -0,0 +1,160 @@
|
||||
---
|
||||
slug: /en/interfaces/prometheus
|
||||
sidebar_position: 19
|
||||
sidebar_label: Prometheus protocols
|
||||
---
|
||||
|
||||
# Prometheus protocols
|
||||
|
||||
## Exposing metrics {#expose}
|
||||
|
||||
:::note
|
||||
ClickHouse Cloud does not currently support connecting to Prometheus. To be notified when this feature is supported, please contact support@clickhouse.com.
|
||||
:::
|
||||
|
||||
ClickHouse can expose its own metrics for scraping from Prometheus:
|
||||
|
||||
```xml
|
||||
<prometheus>
|
||||
<port>9363</port>
|
||||
<endpoint>/metrics</endpoint>
|
||||
<metrics>true</metrics>
|
||||
<asynchronous_metrics>true</asynchronous_metrics>
|
||||
<events>true</events>
|
||||
<errors>true</errors>
|
||||
</prometheus>
|
||||
|
||||
Section `<prometheus.handlers>` can be used to make more extended handlers.
|
||||
This section is similar to [<http_handlers>](/en/interfaces/http) but works for prometheus protocols:
|
||||
|
||||
```xml
|
||||
<prometheus>
|
||||
<port>9363</port>
|
||||
<handlers>
|
||||
<my_rule_1>
|
||||
<url>/metrics</url>
|
||||
<handler>
|
||||
<type>expose_metrics</type>
|
||||
<metrics>true</metrics>
|
||||
<asynchronous_metrics>true</asynchronous_metrics>
|
||||
<events>true</events>
|
||||
<errors>true</errors>
|
||||
</handler>
|
||||
</my_rule_1>
|
||||
</handlers>
|
||||
</prometheus>
|
||||
```
|
||||
|
||||
Settings:
|
||||
|
||||
| Name | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `port` | none | Port for serving the exposing metrics protocol. |
|
||||
| `endpoint` | `/metrics` | HTTP endpoint for scraping metrics by prometheus server. Starts with `/`. Should not be used with the `<handlers>` section. |
|
||||
| `url` / `headers` / `method` | none | Filters used to find a matching handler for a request. Similar to the fields with the same names in the [<http_handlers>](/en/interfaces/http) section. |
|
||||
| `metrics` | true | Expose metrics from the [system.metrics](/en/operations/system-tables/metrics) table. |
|
||||
| `asynchronous_metrics` | true | Expose current metrics values from the [system.asynchronous_metrics](/en/operations/system-tables/asynchronous_metrics) table. |
|
||||
| `events` | true | Expose metrics from the [system.events](/en/operations/system-tables/events) table. |
|
||||
| `errors` | true | Expose the number of errors by error codes occurred since the last server restart. This information could be obtained from the [system.errors](/en/operations/system-tables/errors) as well. |
|
||||
|
||||
Check (replace `127.0.0.1` with the IP addr or hostname of your ClickHouse server):
|
||||
```bash
|
||||
curl 127.0.0.1:9363/metrics
|
||||
```
|
||||
|
||||
## Remote-write protocol {#remote-write}
|
||||
|
||||
ClickHouse supports the [remote-write](https://prometheus.io/docs/specs/remote_write_spec/) protocol.
|
||||
Data are received by this protocol and written to a [TimeSeries](/en/engines/table-engines/special/time_series) table
|
||||
(which should be created beforehand).
|
||||
|
||||
```xml
|
||||
<prometheus>
|
||||
<port>9363</port>
|
||||
<handlers>
|
||||
<my_rule_1>
|
||||
<url>/write</url>
|
||||
<handler>
|
||||
<type>remote_write</type>
|
||||
<database>db_name</database>
|
||||
<table>time_series_table</table>
|
||||
</handler>
|
||||
</my_rule_1>
|
||||
</handlers>
|
||||
</prometheus>
|
||||
```
|
||||
|
||||
Settings:
|
||||
|
||||
| Name | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `port` | none | Port for serving the `remote-write` protocol. |
|
||||
| `url` / `headers` / `method` | none | Filters used to find a matching handler for a request. Similar to the fields with the same names in the [<http_handlers>](/en/interfaces/http) section. |
|
||||
| `table` | none | The name of a [TimeSeries](/en/engines/table-engines/special/time_series) table to write data received by the `remote-write` protocol. This name can optionally contain the name of a database too. |
|
||||
| `database` | none | The name of a database where the table specified in the `table` setting is located if it's not specified in the `table` setting. |
|
||||
|
||||
## Remote-read protocol {#remote-read}
|
||||
|
||||
ClickHouse supports the [remote-read](https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/) protocol.
|
||||
Data are read from a [TimeSeries](/en/engines/table-engines/special/time_series) table and sent via this protocol.
|
||||
|
||||
```xml
|
||||
<prometheus>
|
||||
<port>9363</port>
|
||||
<handlers>
|
||||
<my_rule_1>
|
||||
<url>/read</url>
|
||||
<handler>
|
||||
<type>remote_read</type>
|
||||
<database>db_name</database>
|
||||
<table>time_series_table</table>
|
||||
</handler>
|
||||
</my_rule_1>
|
||||
</handlers>
|
||||
</prometheus>
|
||||
```
|
||||
|
||||
Settings:
|
||||
|
||||
| Name | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `port` | none | Port for serving the `remote-read` protocol. |
|
||||
| `url` / `headers` / `method` | none | Filters used to find a matching handler for a request. Similar to the fields with the same names in the [<http_handlers>](/en/interfaces/http) section. |
|
||||
| `table` | none | The name of a [TimeSeries](/en/engines/table-engines/special/time_series) table to read data to send by the `remote-read` protocol. This name can optionally contain the name of a database too. |
|
||||
| `database` | none | The name of a database where the table specified in the `table` setting is located if it's not specified in the `table` setting. |
|
||||
|
||||
## Configuration for multiple protocols {#multiple-protocols}
|
||||
|
||||
Multiple protocols can be specified together in one place:
|
||||
|
||||
```xml
|
||||
<prometheus>
|
||||
<port>9363</port>
|
||||
<handlers>
|
||||
<my_rule_1>
|
||||
<url>/metrics</url>
|
||||
<handler>
|
||||
<type>expose_metrics</type>
|
||||
<metrics>true</metrics>
|
||||
<asynchronous_metrics>true</asynchronous_metrics>
|
||||
<events>true</events>
|
||||
<errors>true</errors>
|
||||
</handler>
|
||||
</my_rule_1>
|
||||
<my_rule_2>
|
||||
<url>/write</url>
|
||||
<handler>
|
||||
<type>remote_write</type>
|
||||
<table>db_name.time_series_table</table>
|
||||
</handler>
|
||||
</my_rule_2>
|
||||
<my_rule_3>
|
||||
<url>/read</url>
|
||||
<handler>
|
||||
<type>remote_read</type>
|
||||
<table>db_name.time_series_table</table>
|
||||
</handler>
|
||||
</my_rule_3>
|
||||
</handlers>
|
||||
</prometheus>
|
||||
```
|
@ -2112,48 +2112,6 @@ The trailing slash is mandatory.
|
||||
<path>/var/lib/clickhouse/</path>
|
||||
```
|
||||
|
||||
## Prometheus {#prometheus}
|
||||
|
||||
:::note
|
||||
ClickHouse Cloud does not currently support connecting to Prometheus. To be notified when this feature is supported, please contact support@clickhouse.com.
|
||||
:::
|
||||
|
||||
Exposing metrics data for scraping from [Prometheus](https://prometheus.io).
|
||||
|
||||
Settings:
|
||||
|
||||
- `endpoint` – HTTP endpoint for scraping metrics by prometheus server. Start from ‘/’.
|
||||
- `port` – Port for `endpoint`.
|
||||
- `metrics` – Expose metrics from the [system.metrics](../../operations/system-tables/metrics.md#system_tables-metrics) table.
|
||||
- `events` – Expose metrics from the [system.events](../../operations/system-tables/events.md#system_tables-events) table.
|
||||
- `asynchronous_metrics` – Expose current metrics values from the [system.asynchronous_metrics](../../operations/system-tables/asynchronous_metrics.md#system_tables-asynchronous_metrics) table.
|
||||
- `errors` - Expose the number of errors by error codes occurred since the last server restart. This information could be obtained from the [system.errors](../../operations/system-tables/asynchronous_metrics.md#system_tables-errors) as well.
|
||||
|
||||
**Example**
|
||||
|
||||
``` xml
|
||||
<clickhouse>
|
||||
<listen_host>0.0.0.0</listen_host>
|
||||
<http_port>8123</http_port>
|
||||
<tcp_port>9000</tcp_port>
|
||||
<!-- highlight-start -->
|
||||
<prometheus>
|
||||
<endpoint>/metrics</endpoint>
|
||||
<port>9363</port>
|
||||
<metrics>true</metrics>
|
||||
<events>true</events>
|
||||
<asynchronous_metrics>true</asynchronous_metrics>
|
||||
<errors>true</errors>
|
||||
</prometheus>
|
||||
<!-- highlight-end -->
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
Check (replace `127.0.0.1` with the IP addr or hostname of your ClickHouse server):
|
||||
```bash
|
||||
curl 127.0.0.1:9363/metrics
|
||||
```
|
||||
|
||||
## query_log {#query-log}
|
||||
|
||||
Setting for logging queries received with the [log_queries=1](../../operations/settings/settings.md) setting.
|
||||
|
@ -5626,3 +5626,14 @@ Default value: `False`
|
||||
Disable all insert and mutations (alter table update / alter table delete / alter table drop partition). Set to true, can make this node focus on reading queries.
|
||||
|
||||
Default value: `false`.
|
||||
|
||||
## allow_experimental_time_series_table {#allow-experimental-time-series-table}
|
||||
|
||||
Allows creation of tables with the [TimeSeries](../../engines/table-engines/integrations/time-series.md) table engine.
|
||||
|
||||
Possible values:
|
||||
|
||||
- 0 — the [TimeSeries](../../engines/table-engines/integrations/time-series.md) table engine is disabled.
|
||||
- 1 — the [TimeSeries](../../engines/table-engines/integrations/time-series.md) table engine is enabled.
|
||||
|
||||
Default value: `0`.
|
||||
|
@ -24,6 +24,7 @@ Columns:
|
||||
- `num_rebalance_revocations`, (UInt64) - number of times the consumer was revoked its partitions
|
||||
- `num_rebalance_assignments`, (UInt64) - number of times the consumer was assigned to Kafka cluster
|
||||
- `is_currently_used`, (UInt8) - consumer is in use
|
||||
- `last_used`, (UInt64) - last time this consumer was in use, unix time in microseconds
|
||||
- `rdkafka_stat` (String) - library internal statistic. See https://github.com/ClickHouse/librdkafka/blob/master/STATISTICS.md . Set `statistics_interval_ms` to 0 disable, default is 3000 (once in three seconds).
|
||||
|
||||
Example:
|
||||
|
@ -52,6 +52,48 @@ Result:
|
||||
└───────────────────────────────┴───────────────┘
|
||||
```
|
||||
|
||||
## LineString
|
||||
|
||||
`LineString` is a line stored as an array of points: [Array](array.md)([Point](#point)).
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
CREATE TABLE geo_linestring (l LineString) ENGINE = Memory();
|
||||
INSERT INTO geo_linestring VALUES([(0, 0), (10, 0), (10, 10), (0, 10)]);
|
||||
SELECT l, toTypeName(l) FROM geo_linestring;
|
||||
```
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─r─────────────────────────────┬─toTypeName(r)─┐
|
||||
│ [(0,0),(10,0),(10,10),(0,10)] │ LineString │
|
||||
└───────────────────────────────┴───────────────┘
|
||||
```
|
||||
|
||||
## MultiLineString
|
||||
|
||||
`MultiLineString` is multiple lines stored as an array of `LineString`: [Array](array.md)([LineString](#linestring)).
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
CREATE TABLE geo_multilinestring (l MultiLineString) ENGINE = Memory();
|
||||
INSERT INTO geo_multilinestring VALUES([[(0, 0), (10, 0), (10, 10), (0, 10)], [(1, 1), (2, 2), (3, 3)]]);
|
||||
SELECT l, toTypeName(l) FROM geo_multilinestring;
|
||||
```
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─l───────────────────────────────────────────────────┬─toTypeName(l)───┐
|
||||
│ [[(0,0),(10,0),(10,10),(0,10)],[(1,1),(2,2),(3,3)]] │ MultiLineString │
|
||||
└─────────────────────────────────────────────────────┴─────────────────┘
|
||||
```
|
||||
|
||||
## Polygon
|
||||
|
||||
`Polygon` is a polygon with holes stored as an array of rings: [Array](array.md)([Ring](#ring)). First element of outer array is the outer shape of polygon and all the following elements are holes.
|
||||
|
@ -6,11 +6,13 @@ title: "Functions for Working with Polygons"
|
||||
|
||||
## WKT
|
||||
|
||||
Returns a WKT (Well Known Text) geometric object from various [Geo Data Types](../../data-types/geo.md). Supported WKT objects are:
|
||||
Returns a WKT (Well Known Text) geometric object from various [Geo Data Types](../../data-types/geo.md). Supported WKT objects are:
|
||||
|
||||
- POINT
|
||||
- POLYGON
|
||||
- MULTIPOLYGON
|
||||
- LINESTRING
|
||||
- MULTILINESTRING
|
||||
|
||||
**Syntax**
|
||||
|
||||
@ -26,12 +28,16 @@ WKT(geo_data)
|
||||
- [Ring](../../data-types/geo.md#ring)
|
||||
- [Polygon](../../data-types/geo.md#polygon)
|
||||
- [MultiPolygon](../../data-types/geo.md#multipolygon)
|
||||
- [LineString](../../data-types/geo.md#linestring)
|
||||
- [MultiLineString](../../data-types/geo.md#multilinestring)
|
||||
|
||||
**Returned value**
|
||||
|
||||
- WKT geometric object `POINT` is returned for a Point.
|
||||
- WKT geometric object `POLYGON` is returned for a Polygon
|
||||
- WKT geometric object `MULTIPOLYGON` is returned for a MultiPolygon.
|
||||
- WKT geometric object `MULTIPOLYGON` is returned for a MultiPolygon.
|
||||
- WKT geometric object `LINESTRING` is returned for a LineString.
|
||||
- WKT geometric object `MULTILINESTRING` is returned for a MultiLineString.
|
||||
|
||||
**Examples**
|
||||
|
||||
@ -84,7 +90,7 @@ SELECT
|
||||
|
||||
### Input parameters
|
||||
|
||||
String starting with `MULTIPOLYGON`
|
||||
String starting with `MULTIPOLYGON`
|
||||
|
||||
### Returned value
|
||||
|
||||
@ -170,6 +176,34 @@ SELECT readWKTLineString('LINESTRING (1 1, 2 2, 3 3, 1 1)');
|
||||
[(1,1),(2,2),(3,3),(1,1)]
|
||||
```
|
||||
|
||||
## readWKTMultiLineString
|
||||
|
||||
Parses a Well-Known Text (WKT) representation of a MultiLineString geometry and returns it in the internal ClickHouse format.
|
||||
|
||||
### Syntax
|
||||
|
||||
```sql
|
||||
readWKTMultiLineString(wkt_string)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- `wkt_string`: The input WKT string representing a MultiLineString geometry.
|
||||
|
||||
### Returned value
|
||||
|
||||
The function returns a ClickHouse internal representation of the multilinestring geometry.
|
||||
|
||||
### Example
|
||||
|
||||
```sql
|
||||
SELECT readWKTMultiLineString('MULTILINESTRING ((1 1, 2 2, 3 3), (4 4, 5 5, 6 6))');
|
||||
```
|
||||
|
||||
```response
|
||||
[[(1,1),(2,2),(3,3)],[(4,4),(5,5),(6,6)]]
|
||||
```
|
||||
|
||||
## readWKTRing
|
||||
|
||||
Parses a Well-Known Text (WKT) representation of a Polygon geometry and returns a ring (closed linestring) in the internal ClickHouse format.
|
||||
@ -219,7 +253,7 @@ UInt8, 0 for false, 1 for true
|
||||
|
||||
## polygonsDistanceSpherical
|
||||
|
||||
Calculates the minimal distance between two points where one point belongs to the first polygon and the second to another polygon. Spherical means that coordinates are interpreted as coordinates on a pure and ideal sphere, which is not true for the Earth. Using this type of coordinate system speeds up execution, but of course is not precise.
|
||||
Calculates the minimal distance between two points where one point belongs to the first polygon and the second to another polygon. Spherical means that coordinates are interpreted as coordinates on a pure and ideal sphere, which is not true for the Earth. Using this type of coordinate system speeds up execution, but of course is not precise.
|
||||
|
||||
### Example
|
||||
|
||||
|
@ -4189,3 +4189,94 @@ Result:
|
||||
│ 32 │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
## getSubcolumn
|
||||
|
||||
Takes a table expression or identifier and constant string with the name of the sub-column, and returns the requested sub-column extracted from the expression.
|
||||
|
||||
**Syntax**
|
||||
|
||||
```sql
|
||||
getSubcolumn(col_name, subcol_name)
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `col_name` — Table expression or identifier. [Expression](../syntax.md/#expressions), [Identifier](../syntax.md/#identifiers).
|
||||
- `subcol_name` — The name of the sub-column. [String](../data-types/string.md).
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Returns the extracted sub-column.
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
CREATE TABLE t_arr (arr Array(Tuple(subcolumn1 UInt32, subcolumn2 String))) ENGINE = MergeTree ORDER BY tuple();
|
||||
INSERT INTO t_arr VALUES ([(1, 'Hello'), (2, 'World')]), ([(3, 'This'), (4, 'is'), (5, 'subcolumn')]);
|
||||
SELECT getSubcolumn(arr, 'subcolumn1'), getSubcolumn(arr, 'subcolumn2') FROM t_arr;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─getSubcolumn(arr, 'subcolumn1')─┬─getSubcolumn(arr, 'subcolumn2')─┐
|
||||
1. │ [1,2] │ ['Hello','World'] │
|
||||
2. │ [3,4,5] │ ['This','is','subcolumn'] │
|
||||
└─────────────────────────────────┴─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## getTypeSerializationStreams
|
||||
|
||||
Enumerates stream paths of a data type.
|
||||
|
||||
:::note
|
||||
This function is intended for use by developers.
|
||||
:::
|
||||
|
||||
**Syntax**
|
||||
|
||||
```sql
|
||||
getTypeSerializationStreams(col)
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `col` — Column or string representation of a data-type from which the data type will be detected.
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Returns an array with all the serialization sub-stream paths.[Array](../data-types/array.md)([String](../data-types/string.md)).
|
||||
|
||||
**Examples**
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
SELECT getTypeSerializationStreams(tuple('a', 1, 'b', 2));
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─getTypeSerializationStreams(('a', 1, 'b', 2))─────────────────────────────────────────────────────────────────────────┐
|
||||
1. │ ['{TupleElement(1), Regular}','{TupleElement(2), Regular}','{TupleElement(3), Regular}','{TupleElement(4), Regular}'] │
|
||||
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
SELECT getTypeSerializationStreams('Map(String, Int64)');
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─getTypeSerializationStreams('Map(String, Int64)')────────────────────────────────────────────────────────────────┐
|
||||
1. │ ['{ArraySizes}','{ArrayElements, TupleElement(keys), Regular}','{ArrayElements, TupleElement(values), Regular}'] │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ The following operations with [partitions](/docs/en/engines/table-engines/merget
|
||||
|
||||
- [DETACH PARTITION\|PART](#detach-partitionpart) — Moves a partition or part to the `detached` directory and forget it.
|
||||
- [DROP PARTITION\|PART](#drop-partitionpart) — Deletes a partition or part.
|
||||
- [DROP DETACHED PARTITION\|PART](#drop-detached-partitionpart) - Delete a part or all parts of a partition from `detached`.
|
||||
- [FORGET PARTITION](#forget-partition) — Deletes a partition metadata from zookeeper if it's empty.
|
||||
- [ATTACH PARTITION\|PART](#attach-partitionpart) — Adds a partition or part from the `detached` directory to the table.
|
||||
- [ATTACH PARTITION FROM](#attach-partition-from) — Copies the data partition from one table to another and adds.
|
||||
@ -68,7 +69,7 @@ ALTER TABLE mt DROP PART 'all_4_4_0';
|
||||
## DROP DETACHED PARTITION\|PART
|
||||
|
||||
``` sql
|
||||
ALTER TABLE table_name [ON CLUSTER cluster] DROP DETACHED PARTITION|PART partition_expr
|
||||
ALTER TABLE table_name [ON CLUSTER cluster] DROP DETACHED PARTITION|PART ALL|partition_expr
|
||||
```
|
||||
|
||||
Removes the specified part or all parts of the specified partition from `detached`.
|
||||
|
@ -8,26 +8,28 @@ sidebar_label: STATISTICS
|
||||
|
||||
The following operations are available:
|
||||
|
||||
- `ALTER TABLE [db].table ADD STATISTICS (columns list) TYPE (type list)` - Adds statistic description to tables metadata.
|
||||
- `ALTER TABLE [db].table ADD STATISTICS [IF NOT EXISTS] (column list) TYPE (type list)` - Adds statistic description to tables metadata.
|
||||
|
||||
- `ALTER TABLE [db].table MODIFY STATISTICS (columns list) TYPE (type list)` - Modifies statistic description to tables metadata.
|
||||
- `ALTER TABLE [db].table MODIFY STATISTICS (column list) TYPE (type list)` - Modifies statistic description to tables metadata.
|
||||
|
||||
- `ALTER TABLE [db].table DROP STATISTICS (columns list)` - Removes statistics from the metadata of the specified columns and deletes all statistics objects in all parts for the specified columns.
|
||||
- `ALTER TABLE [db].table DROP STATISTICS [IF EXISTS] (column list)` - Removes statistics from the metadata of the specified columns and deletes all statistics objects in all parts for the specified columns.
|
||||
|
||||
- `ALTER TABLE [db].table CLEAR STATISTICS (columns list)` - Deletes all statistics objects in all parts for the specified columns. Statistics objects can be rebuild using `ALTER TABLE MATERIALIZE STATISTICS`.
|
||||
- `ALTER TABLE [db].table CLEAR STATISTICS [IF EXISTS] (column list)` - Deletes all statistics objects in all parts for the specified columns. Statistics objects can be rebuild using `ALTER TABLE MATERIALIZE STATISTICS`.
|
||||
|
||||
- `ALTER TABLE [db.]table MATERIALIZE STATISTICS (columns list)` - Rebuilds the statistic for columns. Implemented as a [mutation](../../../sql-reference/statements/alter/index.md#mutations).
|
||||
- `ALTER TABLE [db.]table MATERIALIZE STATISTICS [IF EXISTS] (column list)` - Rebuilds the statistic for columns. Implemented as a [mutation](../../../sql-reference/statements/alter/index.md#mutations).
|
||||
|
||||
The first two commands are lightweight in a sense that they only change metadata or remove files.
|
||||
|
||||
Also, they are replicated, syncing statistics metadata via ZooKeeper.
|
||||
|
||||
There is an example adding two statistics types to two columns:
|
||||
## Example:
|
||||
|
||||
Adding two statistics types to two columns:
|
||||
|
||||
```
|
||||
ALTER TABLE t1 MODIFY STATISTICS c, d TYPE TDigest, Uniq;
|
||||
```
|
||||
|
||||
:::note
|
||||
Statistic manipulation is supported only for tables with [`*MergeTree`](../../../engines/table-engines/mergetree-family/mergetree.md) engine (including [replicated](../../../engines/table-engines/mergetree-family/replication.md) variants).
|
||||
Statistic are supported only for [`*MergeTree`](../../../engines/table-engines/mergetree-family/mergetree.md) engine tables (including [replicated](../../../engines/table-engines/mergetree-family/replication.md) variants).
|
||||
:::
|
||||
|
@ -186,7 +186,7 @@ Otherwise, you'll get `INVALID_JOIN_ON_EXPRESSION`.
|
||||
|
||||
:::
|
||||
|
||||
Clickhouse currently supports `ALL INNER/LEFT/RIGHT/FULL JOIN` with inequality conditions in addition to equality conditions. The inequality conditions are supported only for `hash` and `grace_hash` join algorithms. The inequality conditions are not supported with `join_use_nulls`.
|
||||
Clickhouse currently supports `ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN` with inequality conditions in addition to equality conditions. The inequality conditions are supported only for `hash` and `grace_hash` join algorithms. The inequality conditions are not supported with `join_use_nulls`.
|
||||
|
||||
**Example**
|
||||
|
||||
|
36
docs/en/sql-reference/table-functions/fuzzQuery.md
Normal file
36
docs/en/sql-reference/table-functions/fuzzQuery.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
slug: /en/sql-reference/table-functions/fuzzQuery
|
||||
sidebar_position: 75
|
||||
sidebar_label: fuzzQuery
|
||||
---
|
||||
|
||||
# fuzzQuery
|
||||
|
||||
Perturbs the given query string with random variations.
|
||||
|
||||
``` sql
|
||||
fuzzQuery(query[, max_query_length[, random_seed]])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `query` (String) - The source query to perform the fuzzing on.
|
||||
- `max_query_length` (UInt64) - A maximum length the query can get during the fuzzing process.
|
||||
- `random_seed` (UInt64) - A random seed for producing stable results.
|
||||
|
||||
**Returned Value**
|
||||
|
||||
A table object with a single column containing perturbed query strings.
|
||||
|
||||
## Usage Example
|
||||
|
||||
``` sql
|
||||
SELECT * FROM fuzzQuery('SELECT materialize(\'a\' AS key) GROUP BY key') LIMIT 2;
|
||||
```
|
||||
|
||||
```
|
||||
┌─query──────────────────────────────────────────────────────────┐
|
||||
1. │ SELECT 'a' AS key GROUP BY key │
|
||||
2. │ EXPLAIN PIPELINE compact = true SELECT 'a' AS key GROUP BY key │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
```
|
28
docs/en/sql-reference/table-functions/timeSeriesData.md
Normal file
28
docs/en/sql-reference/table-functions/timeSeriesData.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
slug: /en/sql-reference/table-functions/timeSeriesData
|
||||
sidebar_position: 145
|
||||
sidebar_label: timeSeriesData
|
||||
---
|
||||
|
||||
# timeSeriesData
|
||||
|
||||
`timeSeriesData(db_name.time_series_table)` - Returns the [data](../../engines/table-engines/integrations/time-series.md#data-table) table
|
||||
used by table `db_name.time_series_table` which table engine is [TimeSeries](../../engines/table-engines/integrations/time-series.md):
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries DATA data_table
|
||||
```
|
||||
|
||||
The function also works if the _data_ table is inner:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries DATA INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
```
|
||||
|
||||
The following queries are equivalent:
|
||||
|
||||
``` sql
|
||||
SELECT * FROM timeSeriesData(db_name.time_series_table);
|
||||
SELECT * FROM timeSeriesData('db_name.time_series_table');
|
||||
SELECT * FROM timeSeriesData('db_name', 'time_series_table');
|
||||
```
|
28
docs/en/sql-reference/table-functions/timeSeriesMetrics.md
Normal file
28
docs/en/sql-reference/table-functions/timeSeriesMetrics.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
slug: /en/sql-reference/table-functions/timeSeriesMetrics
|
||||
sidebar_position: 145
|
||||
sidebar_label: timeSeriesMetrics
|
||||
---
|
||||
|
||||
# timeSeriesMetrics
|
||||
|
||||
`timeSeriesMetrics(db_name.time_series_table)` - Returns the [metrics](../../engines/table-engines/integrations/time-series.md#metrics-table) table
|
||||
used by table `db_name.time_series_table` which table engine is [TimeSeries](../../engines/table-engines/integrations/time-series.md):
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries METRICS metrics_table
|
||||
```
|
||||
|
||||
The function also works if the _metrics_ table is inner:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries METRICS INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
```
|
||||
|
||||
The following queries are equivalent:
|
||||
|
||||
``` sql
|
||||
SELECT * FROM timeSeriesMetrics(db_name.time_series_table);
|
||||
SELECT * FROM timeSeriesMetrics('db_name.time_series_table');
|
||||
SELECT * FROM timeSeriesMetrics('db_name', 'time_series_table');
|
||||
```
|
28
docs/en/sql-reference/table-functions/timeSeriesTags.md
Normal file
28
docs/en/sql-reference/table-functions/timeSeriesTags.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
slug: /en/sql-reference/table-functions/timeSeriesTags
|
||||
sidebar_position: 145
|
||||
sidebar_label: timeSeriesTags
|
||||
---
|
||||
|
||||
# timeSeriesTags
|
||||
|
||||
`timeSeriesTags(db_name.time_series_table)` - Returns the [tags](../../engines/table-engines/integrations/time-series.md#tags-table) table
|
||||
used by table `db_name.time_series_table` which table engine is [TimeSeries](../../engines/table-engines/integrations/time-series.md):
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries TAGS tags_table
|
||||
```
|
||||
|
||||
The function also works if the _tags_ table is inner:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE db_name.time_series_table ENGINE=TimeSeries TAGS INNER UUID '01234567-89ab-cdef-0123-456789abcdef'
|
||||
```
|
||||
|
||||
The following queries are equivalent:
|
||||
|
||||
``` sql
|
||||
SELECT * FROM timeSeriesTags(db_name.time_series_table);
|
||||
SELECT * FROM timeSeriesTags('db_name.time_series_table');
|
||||
SELECT * FROM timeSeriesTags('db_name', 'time_series_table');
|
||||
```
|
@ -23,30 +23,30 @@ slug: /zh/operations/external-authenticators/kerberos
|
||||
|
||||
示例 (进入 `config.xml`):
|
||||
```xml
|
||||
<yandex>
|
||||
<clickhouse>
|
||||
<!- ... -->
|
||||
<kerberos />
|
||||
</yandex>
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
主体规范:
|
||||
```xml
|
||||
<yandex>
|
||||
<clickhouse>
|
||||
<!- ... -->
|
||||
<kerberos>
|
||||
<principal>HTTP/clickhouse.example.com@EXAMPLE.COM</principal>
|
||||
</kerberos>
|
||||
</yandex>
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
按领域过滤:
|
||||
```xml
|
||||
<yandex>
|
||||
<clickhouse>
|
||||
<!- ... -->
|
||||
<kerberos>
|
||||
<realm>EXAMPLE.COM</realm>
|
||||
</kerberos>
|
||||
</yandex>
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
!!! warning "注意"
|
||||
@ -74,7 +74,7 @@ Kerberos主体名称格式通常遵循以下模式:
|
||||
|
||||
示例 (进入 `users.xml`):
|
||||
```
|
||||
<yandex>
|
||||
<clickhouse>
|
||||
<!- ... -->
|
||||
<users>
|
||||
<!- ... -->
|
||||
@ -85,7 +85,7 @@ Kerberos主体名称格式通常遵循以下模式:
|
||||
</kerberos>
|
||||
</my_user>
|
||||
</users>
|
||||
</yandex>
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
!!! warning "警告"
|
||||
|
@ -223,7 +223,7 @@ std::vector<String> Client::loadWarningMessages()
|
||||
|
||||
size_t rows = packet.block.rows();
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
messages.emplace_back(column[i].get<String>());
|
||||
messages.emplace_back(column[i].safeGet<String>());
|
||||
}
|
||||
continue;
|
||||
|
||||
|
@ -11,7 +11,10 @@ class Client : public ClientApplicationBase
|
||||
public:
|
||||
using Arguments = ClientApplicationBase::Arguments;
|
||||
|
||||
Client() = default;
|
||||
Client()
|
||||
{
|
||||
fuzzer = QueryFuzzer(randomSeed(), &std::cout, &std::cerr);
|
||||
}
|
||||
|
||||
void initialize(Poco::Util::Application & self) override;
|
||||
|
||||
|
@ -95,7 +95,7 @@ void SetCommand::execute(const ASTKeeperQuery * query, KeeperClient * client) co
|
||||
client->zookeeper->set(
|
||||
client->getAbsolutePath(query->args[0].safeGet<String>()),
|
||||
query->args[1].safeGet<String>(),
|
||||
static_cast<Int32>(query->args[2].get<Int32>()));
|
||||
static_cast<Int32>(query->args[2].safeGet<Int32>()));
|
||||
}
|
||||
|
||||
bool CreateCommand::parse(IParser::Pos & pos, std::shared_ptr<ASTKeeperQuery> & node, Expected & expected) const
|
||||
@ -494,7 +494,7 @@ void RMCommand::execute(const ASTKeeperQuery * query, KeeperClient * client) con
|
||||
{
|
||||
Int32 version{-1};
|
||||
if (query->args.size() == 2)
|
||||
version = static_cast<Int32>(query->args[1].get<Int32>());
|
||||
version = static_cast<Int32>(query->args[1].safeGet<Int32>());
|
||||
|
||||
client->zookeeper->remove(client->getAbsolutePath(query->args[0].safeGet<String>()), version);
|
||||
}
|
||||
@ -549,7 +549,7 @@ void ReconfigCommand::execute(const DB::ASTKeeperQuery * query, DB::KeeperClient
|
||||
String leaving;
|
||||
String new_members;
|
||||
|
||||
auto operation = query->args[0].get<ReconfigCommand::Operation>();
|
||||
auto operation = query->args[0].safeGet<ReconfigCommand::Operation>();
|
||||
switch (operation)
|
||||
{
|
||||
case static_cast<UInt8>(ReconfigCommand::Operation::ADD):
|
||||
|
@ -143,7 +143,7 @@ void LocalServer::initialize(Poco::Util::Application & self)
|
||||
|
||||
if (fs::exists(config_path))
|
||||
{
|
||||
ConfigProcessor config_processor(config_path, false, true);
|
||||
ConfigProcessor config_processor(config_path);
|
||||
ConfigProcessor::setConfigPath(fs::path(config_path).parent_path());
|
||||
auto loaded_config = config_processor.loadConfig();
|
||||
getClientConfiguration().add(loaded_config.configuration.duplicate(), PRIO_DEFAULT, false);
|
||||
|
@ -814,10 +814,11 @@ try
|
||||
|
||||
const size_t physical_server_memory = getMemoryAmount();
|
||||
|
||||
LOG_INFO(log, "Available RAM: {}; physical cores: {}; logical cores: {}.",
|
||||
LOG_INFO(log, "Available RAM: {}; logical cores: {}; used cores: {}.",
|
||||
formatReadableSizeWithBinarySuffix(physical_server_memory),
|
||||
getNumberOfPhysicalCPUCores(), // on ARM processors it can show only enabled at current moment cores
|
||||
std::thread::hardware_concurrency());
|
||||
std::thread::hardware_concurrency(),
|
||||
getNumberOfPhysicalCPUCores() // on ARM processors it can show only enabled at current moment cores
|
||||
);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
String cpu_info;
|
||||
@ -1623,7 +1624,7 @@ try
|
||||
concurrent_threads_soft_limit = new_server_settings.concurrent_threads_soft_limit_num;
|
||||
if (new_server_settings.concurrent_threads_soft_limit_ratio_to_cores > 0)
|
||||
{
|
||||
auto value = new_server_settings.concurrent_threads_soft_limit_ratio_to_cores * std::thread::hardware_concurrency();
|
||||
auto value = new_server_settings.concurrent_threads_soft_limit_ratio_to_cores * getNumberOfPhysicalCPUCores();
|
||||
if (value > 0 && value < concurrent_threads_soft_limit)
|
||||
concurrent_threads_soft_limit = value;
|
||||
}
|
||||
|
1
programs/server/config.d/transactions.xml
Symbolic link
1
programs/server/config.d/transactions.xml
Symbolic link
@ -0,0 +1 @@
|
||||
../../../tests/config/config.d/transactions.xml
|
@ -780,12 +780,12 @@ AggregateFunctionPtr createAggregateFunctionGroupArray(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[0].get<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].get<UInt64>() == 0))
|
||||
if ((type == Field::Types::Int64 && parameters[0].safeGet<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
has_limit = true;
|
||||
max_elems = parameters[0].get<UInt64>();
|
||||
max_elems = parameters[0].safeGet<UInt64>();
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
@ -816,11 +816,11 @@ AggregateFunctionPtr createAggregateFunctionGroupArraySample(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[i].get<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[i].get<UInt64>() == 0))
|
||||
if ((type == Field::Types::Int64 && parameters[i].safeGet<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[i].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
return parameters[i].get<UInt64>();
|
||||
return parameters[i].safeGet<UInt64>();
|
||||
};
|
||||
|
||||
UInt64 max_elems = get_parameter(0);
|
||||
|
@ -83,16 +83,16 @@ public:
|
||||
if (version == 1)
|
||||
{
|
||||
for (size_t i = 0; i < arr_size; ++i)
|
||||
set.insert(static_cast<T>((*data_column)[offset + i].get<T>()));
|
||||
set.insert(static_cast<T>((*data_column)[offset + i].safeGet<T>()));
|
||||
}
|
||||
else if (!set.empty())
|
||||
{
|
||||
typename State::Set new_set;
|
||||
for (size_t i = 0; i < arr_size; ++i)
|
||||
{
|
||||
typename State::Set::LookupResult set_value = set.find(static_cast<T>((*data_column)[offset + i].get<T>()));
|
||||
typename State::Set::LookupResult set_value = set.find(static_cast<T>((*data_column)[offset + i].safeGet<T>()));
|
||||
if (set_value != nullptr)
|
||||
new_set.insert(static_cast<T>((*data_column)[offset + i].get<T>()));
|
||||
new_set.insert(static_cast<T>((*data_column)[offset + i].safeGet<T>()));
|
||||
}
|
||||
set = std::move(new_set);
|
||||
}
|
||||
|
@ -269,12 +269,12 @@ AggregateFunctionPtr createAggregateFunctionMoving(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive integer", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[0].get<Int64>() <= 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].get<UInt64>() == 0))
|
||||
if ((type == Field::Types::Int64 && parameters[0].safeGet<Int64>() <= 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive integer", name);
|
||||
|
||||
limit_size = true;
|
||||
max_elems = parameters[0].get<UInt64>();
|
||||
max_elems = parameters[0].safeGet<UInt64>();
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
|
@ -397,11 +397,11 @@ AggregateFunctionPtr createAggregateFunctionGroupArray(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[0].get<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].get<UInt64>() == 0))
|
||||
if ((type == Field::Types::Int64 && parameters[0].safeGet<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
max_elems = parameters[0].get<UInt64>();
|
||||
max_elems = parameters[0].safeGet<UInt64>();
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
|
@ -247,7 +247,7 @@ AggregateFunctionPtr createAggregateFunctionGroupConcat(
|
||||
if (type != Field::Types::String)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "First parameter for aggregate function {} should be string", name);
|
||||
|
||||
delimiter = parameters[0].get<String>();
|
||||
delimiter = parameters[0].safeGet<String>();
|
||||
}
|
||||
if (parameters.size() == 2)
|
||||
{
|
||||
@ -256,12 +256,12 @@ AggregateFunctionPtr createAggregateFunctionGroupConcat(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Second parameter for aggregate function {} should be a positive number", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[1].get<Int64>() <= 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[1].get<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Second parameter for aggregate function {} should be a positive number, got: {}", name, parameters[1].get<Int64>());
|
||||
if ((type == Field::Types::Int64 && parameters[1].safeGet<Int64>() <= 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[1].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Second parameter for aggregate function {} should be a positive number, got: {}", name, parameters[1].safeGet<Int64>());
|
||||
|
||||
has_limit = true;
|
||||
limit = parameters[1].get<UInt64>();
|
||||
limit = parameters[1].safeGet<UInt64>();
|
||||
}
|
||||
|
||||
if (has_limit)
|
||||
|
@ -323,12 +323,12 @@ AggregateFunctionPtr createAggregateFunctionGroupUniqArray(
|
||||
if (type != Field::Types::Int64 && type != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
if ((type == Field::Types::Int64 && parameters[0].get<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].get<UInt64>() == 0))
|
||||
if ((type == Field::Types::Int64 && parameters[0].safeGet<Int64>() < 0) ||
|
||||
(type == Field::Types::UInt64 && parameters[0].safeGet<UInt64>() == 0))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Parameter for aggregate function {} should be positive number", name);
|
||||
|
||||
limit_size = true;
|
||||
max_elems = parameters[0].get<UInt64>();
|
||||
max_elems = parameters[0].safeGet<UInt64>();
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
|
@ -238,7 +238,7 @@ public:
|
||||
if (params[0].getType() != Field::Types::String)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} require first parameter to be a String", getName());
|
||||
|
||||
const auto & param = params[0].get<String>();
|
||||
const auto & param = params[0].safeGet<String>();
|
||||
if (param == "two-sided")
|
||||
alternative = Alternative::TwoSided;
|
||||
else if (param == "less")
|
||||
@ -255,7 +255,7 @@ public:
|
||||
if (params[1].getType() != Field::Types::String)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} require second parameter to be a String", getName());
|
||||
|
||||
method = params[1].get<String>();
|
||||
method = params[1].safeGet<String>();
|
||||
if (method != "auto" && method != "exact" && method != "asymp" && method != "asymptotic")
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Unknown method in aggregate function {}. "
|
||||
"It must be one of: 'auto', 'exact', 'asymp' (or 'asymptotic')", getName());
|
||||
|
@ -181,7 +181,7 @@ public:
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} require first parameter to be a UInt64", getName());
|
||||
|
||||
total_buckets = params[0].get<UInt64>();
|
||||
total_buckets = params[0].safeGet<UInt64>();
|
||||
|
||||
this->x_type = WhichDataType(arguments[0]).idx;
|
||||
this->y_type = WhichDataType(arguments[1]).idx;
|
||||
|
@ -152,7 +152,7 @@ public:
|
||||
if (params[0].getType() != Field::Types::String)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} require first parameter to be a String", getName());
|
||||
|
||||
const auto & param = params[0].get<String>();
|
||||
const auto & param = params[0].safeGet<String>();
|
||||
if (param == "two-sided")
|
||||
alternative = Alternative::TwoSided;
|
||||
else if (param == "less")
|
||||
@ -169,7 +169,7 @@ public:
|
||||
if (params[1].getType() != Field::Types::UInt64)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} require second parameter to be a UInt64", getName());
|
||||
|
||||
continuity_correction = static_cast<bool>(params[1].get<UInt64>());
|
||||
continuity_correction = static_cast<bool>(params[1].safeGet<UInt64>());
|
||||
}
|
||||
|
||||
String getName() const override
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} requires relative accuracy parameter with Float64 type", getName());
|
||||
|
||||
relative_accuracy = relative_accuracy_field.get<Float64>();
|
||||
relative_accuracy = relative_accuracy_field.safeGet<Float64>();
|
||||
|
||||
if (relative_accuracy <= 0 || relative_accuracy >= 1 || isNaN(relative_accuracy))
|
||||
throw Exception(
|
||||
@ -147,9 +147,9 @@ public:
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Aggregate function {} requires accuracy parameter with integer type", getName());
|
||||
|
||||
if (accuracy_field.getType() == Field::Types::Int64)
|
||||
accuracy = accuracy_field.get<Int64>();
|
||||
accuracy = accuracy_field.safeGet<Int64>();
|
||||
else
|
||||
accuracy = accuracy_field.get<UInt64>();
|
||||
accuracy = accuracy_field.safeGet<UInt64>();
|
||||
|
||||
if (accuracy <= 0)
|
||||
throw Exception(
|
||||
|
@ -300,12 +300,12 @@ public:
|
||||
/// Compatibility with previous versions.
|
||||
if (value.getType() == Field::Types::Decimal32)
|
||||
{
|
||||
auto source = value.get<DecimalField<Decimal32>>();
|
||||
auto source = value.safeGet<DecimalField<Decimal32>>();
|
||||
value = DecimalField<Decimal128>(source.getValue(), source.getScale());
|
||||
}
|
||||
else if (value.getType() == Field::Types::Decimal64)
|
||||
{
|
||||
auto source = value.get<DecimalField<Decimal64>>();
|
||||
auto source = value.safeGet<DecimalField<Decimal64>>();
|
||||
value = DecimalField<Decimal128>(source.getValue(), source.getScale());
|
||||
}
|
||||
|
||||
@ -355,7 +355,7 @@ public:
|
||||
/// Compatibility with previous versions.
|
||||
if (value.getType() == Field::Types::Decimal128)
|
||||
{
|
||||
auto source = value.get<DecimalField<Decimal128>>();
|
||||
auto source = value.safeGet<DecimalField<Decimal128>>();
|
||||
WhichDataType value_type(values_types[col_idx]);
|
||||
if (value_type.isDecimal32())
|
||||
{
|
||||
@ -560,7 +560,7 @@ private:
|
||||
template <typename FieldType>
|
||||
bool compareImpl(FieldType & x) const
|
||||
{
|
||||
auto val = rhs.get<FieldType>();
|
||||
auto val = rhs.safeGet<FieldType>();
|
||||
if (val > x)
|
||||
{
|
||||
x = val;
|
||||
@ -600,7 +600,7 @@ private:
|
||||
template <typename FieldType>
|
||||
bool compareImpl(FieldType & x) const
|
||||
{
|
||||
auto val = rhs.get<FieldType>();
|
||||
auto val = rhs.safeGet<FieldType>();
|
||||
if (val < x)
|
||||
{
|
||||
x = val;
|
||||
|
@ -137,7 +137,7 @@ private:
|
||||
if (constant_node_value.getType() != Field::Types::Which::Tuple)
|
||||
return {};
|
||||
|
||||
const auto & constant_tuple = constant_node_value.get<const Tuple &>();
|
||||
const auto & constant_tuple = constant_node_value.safeGet<const Tuple &>();
|
||||
|
||||
const auto & function_arguments_nodes = function_node_typed.getArguments().getNodes();
|
||||
size_t function_arguments_nodes_size = function_arguments_nodes.size();
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
if (!pattern || !isString(pattern->getResultType()))
|
||||
continue;
|
||||
|
||||
auto regexp = likePatternToRegexp(pattern->getValue().get<String>());
|
||||
auto regexp = likePatternToRegexp(pattern->getValue().safeGet<String>());
|
||||
/// Case insensitive. Works with UTF-8 as well.
|
||||
if (is_ilike)
|
||||
regexp = "(?i)" + regexp;
|
||||
|
@ -68,10 +68,10 @@ void optimizeFunctionEmpty(QueryTreeNodePtr &, FunctionNode & function_node, Col
|
||||
String getSubcolumnNameForElement(const Field & value, const DataTypeTuple & data_type_tuple)
|
||||
{
|
||||
if (value.getType() == Field::Types::String)
|
||||
return value.get<const String &>();
|
||||
return value.safeGet<const String &>();
|
||||
|
||||
if (value.getType() == Field::Types::UInt64)
|
||||
return data_type_tuple.getNameByPosition(value.get<UInt64>());
|
||||
return data_type_tuple.getNameByPosition(value.safeGet<UInt64>());
|
||||
|
||||
return "";
|
||||
}
|
||||
@ -79,7 +79,7 @@ String getSubcolumnNameForElement(const Field & value, const DataTypeTuple & dat
|
||||
String getSubcolumnNameForElement(const Field & value, const DataTypeVariant &)
|
||||
{
|
||||
if (value.getType() == Field::Types::String)
|
||||
return value.get<const String &>();
|
||||
return value.safeGet<const String &>();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ FunctionNodePtr createFusedQuantilesNode(std::vector<QueryTreeNodePtr *> & nodes
|
||||
/// Sort nodes and parameters in ascending order of quantile level
|
||||
std::vector<size_t> permutation(nodes.size());
|
||||
iota(permutation.data(), permutation.size(), size_t(0));
|
||||
std::sort(permutation.begin(), permutation.end(), [&](size_t i, size_t j) { return parameters[i].get<Float64>() < parameters[j].get<Float64>(); });
|
||||
std::sort(permutation.begin(), permutation.end(), [&](size_t i, size_t j) { return parameters[i].safeGet<Float64>() < parameters[j].safeGet<Float64>(); });
|
||||
|
||||
std::vector<QueryTreeNodePtr *> new_nodes;
|
||||
new_nodes.reserve(permutation.size());
|
||||
|
@ -134,8 +134,8 @@ public:
|
||||
return;
|
||||
|
||||
std::set<std::string> string_values;
|
||||
string_values.insert(first_literal->getValue().get<std::string>());
|
||||
string_values.insert(second_literal->getValue().get<std::string>());
|
||||
string_values.insert(first_literal->getValue().safeGet<std::string>());
|
||||
string_values.insert(second_literal->getValue().safeGet<std::string>());
|
||||
|
||||
changeIfArguments(*function_if_node, string_values, context);
|
||||
wrapIntoToString(*function_node, std::move(modified_if_node), context);
|
||||
@ -163,7 +163,7 @@ public:
|
||||
if (!isArray(literal_to->getResultType()) || !isString(literal_default->getResultType()))
|
||||
return;
|
||||
|
||||
auto array_to = literal_to->getValue().get<Array>();
|
||||
auto array_to = literal_to->getValue().safeGet<Array>();
|
||||
|
||||
if (array_to.empty())
|
||||
return;
|
||||
@ -178,9 +178,9 @@ public:
|
||||
std::set<std::string> string_values;
|
||||
|
||||
for (const auto & value : array_to)
|
||||
string_values.insert(value.get<std::string>());
|
||||
string_values.insert(value.safeGet<std::string>());
|
||||
|
||||
string_values.insert(literal_default->getValue().get<std::string>());
|
||||
string_values.insert(literal_default->getValue().safeGet<std::string>());
|
||||
|
||||
changeTransformArguments(*function_modified_transform_node, string_values, context);
|
||||
wrapIntoToString(*function_node, std::move(modified_transform_node), context);
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
}
|
||||
else if (function_node->getFunctionName() == "sum" &&
|
||||
first_argument_constant_literal.getType() == Field::Types::UInt64 &&
|
||||
first_argument_constant_literal.get<UInt64>() == 1)
|
||||
first_argument_constant_literal.safeGet<UInt64>() == 1)
|
||||
{
|
||||
function_node->getArguments().getNodes().clear();
|
||||
resolveAggregateFunctionNodeByName(*function_node, "count");
|
||||
|
@ -143,13 +143,13 @@ private:
|
||||
const auto & column_type = column_node_typed.getColumnType().get();
|
||||
if (isDateOrDate32(column_type))
|
||||
{
|
||||
start_date_or_date_time = date_lut.dateToString(range.first.get<DateLUTImpl::Time>());
|
||||
end_date_or_date_time = date_lut.dateToString(range.second.get<DateLUTImpl::Time>());
|
||||
start_date_or_date_time = date_lut.dateToString(range.first.safeGet<DateLUTImpl::Time>());
|
||||
end_date_or_date_time = date_lut.dateToString(range.second.safeGet<DateLUTImpl::Time>());
|
||||
}
|
||||
else if (isDateTime(column_type) || isDateTime64(column_type))
|
||||
{
|
||||
start_date_or_date_time = date_lut.timeToString(range.first.get<DateLUTImpl::Time>());
|
||||
end_date_or_date_time = date_lut.timeToString(range.second.get<DateLUTImpl::Time>());
|
||||
start_date_or_date_time = date_lut.timeToString(range.first.safeGet<DateLUTImpl::Time>());
|
||||
end_date_or_date_time = date_lut.timeToString(range.second.safeGet<DateLUTImpl::Time>());
|
||||
}
|
||||
else [[unlikely]]
|
||||
return {};
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
{
|
||||
const auto & second_const_value = second_const_node->getValue();
|
||||
if (second_const_value.isNull()
|
||||
|| (lower_name == "sum" && isInt64OrUInt64FieldType(second_const_value.getType()) && second_const_value.get<UInt64>() == 0
|
||||
|| (lower_name == "sum" && isInt64OrUInt64FieldType(second_const_value.getType()) && second_const_value.safeGet<UInt64>() == 0
|
||||
&& !if_node->getResultType()->isNullable()))
|
||||
{
|
||||
/// avg(if(cond, a, null)) -> avgIf(a::ResultTypeIf, cond)
|
||||
@ -89,7 +89,7 @@ public:
|
||||
{
|
||||
const auto & first_const_value = first_const_node->getValue();
|
||||
if (first_const_value.isNull()
|
||||
|| (lower_name == "sum" && isInt64OrUInt64FieldType(first_const_value.getType()) && first_const_value.get<UInt64>() == 0
|
||||
|| (lower_name == "sum" && isInt64OrUInt64FieldType(first_const_value.getType()) && first_const_value.safeGet<UInt64>() == 0
|
||||
&& !if_node->getResultType()->isNullable()))
|
||||
{
|
||||
/// avg(if(cond, null, a) -> avgIf(a::ResultTypeIf, !cond))
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
resolveAggregateFunctionNodeByName(*function_node, "countIf");
|
||||
|
||||
if (constant_value_literal.get<UInt64>() != 1)
|
||||
if (constant_value_literal.safeGet<UInt64>() != 1)
|
||||
{
|
||||
/// Rewrite `sumIf(123, cond)` into `123 * countIf(cond)`
|
||||
node = getMultiplyFunction(std::move(multiplier_node), node);
|
||||
@ -105,8 +105,8 @@ public:
|
||||
const auto & if_true_condition_constant_value_literal = if_true_condition_constant_node->getValue();
|
||||
const auto & if_false_condition_constant_value_literal = if_false_condition_constant_node->getValue();
|
||||
|
||||
auto if_true_condition_value = if_true_condition_constant_value_literal.get<UInt64>();
|
||||
auto if_false_condition_value = if_false_condition_constant_value_literal.get<UInt64>();
|
||||
auto if_true_condition_value = if_true_condition_constant_value_literal.safeGet<UInt64>();
|
||||
auto if_false_condition_value = if_false_condition_constant_value_literal.safeGet<UInt64>();
|
||||
|
||||
if (if_false_condition_value == 0)
|
||||
{
|
||||
|
@ -471,7 +471,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSortList(const ASTPtr & order_by_express
|
||||
|
||||
std::shared_ptr<Collator> collator;
|
||||
if (order_by_element.getCollation())
|
||||
collator = std::make_shared<Collator>(order_by_element.getCollation()->as<ASTLiteral &>().value.get<String &>());
|
||||
collator = std::make_shared<Collator>(order_by_element.getCollation()->as<ASTLiteral &>().value.safeGet<String &>());
|
||||
|
||||
const auto & sort_expression_ast = order_by_element.children.at(0);
|
||||
auto sort_expression = buildExpression(sort_expression_ast, context);
|
||||
|
@ -1273,7 +1273,7 @@ QueryTreeNodePtr IdentifierResolver::matchArrayJoinSubcolumns(
|
||||
const auto & constant_node_value = constant_node.getValue();
|
||||
if (constant_node_value.getType() == Field::Types::String)
|
||||
{
|
||||
array_join_subcolumn_prefix = constant_node_value.get<String>() + ".";
|
||||
array_join_subcolumn_prefix = constant_node_value.safeGet<String>() + ".";
|
||||
array_join_parent_column = argument_nodes.at(0).get();
|
||||
}
|
||||
}
|
||||
@ -1287,7 +1287,7 @@ QueryTreeNodePtr IdentifierResolver::matchArrayJoinSubcolumns(
|
||||
if (!second_argument || second_argument->getValue().getType() != Field::Types::String)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree());
|
||||
|
||||
const auto & resolved_subcolumn_path = second_argument->getValue().get<String &>();
|
||||
const auto & resolved_subcolumn_path = second_argument->getValue().safeGet<String &>();
|
||||
if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix))
|
||||
return {};
|
||||
|
||||
@ -1331,7 +1331,7 @@ QueryTreeNodePtr IdentifierResolver::tryResolveExpressionFromArrayJoinExpression
|
||||
size_t nested_function_arguments_size = nested_function_arguments.size();
|
||||
|
||||
const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as<ConstantNode & >();
|
||||
const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get<Array &>();
|
||||
const auto & nested_keys_names = nested_keys_names_constant_node.getValue().safeGet<Array &>();
|
||||
size_t nested_keys_names_size = nested_keys_names.size();
|
||||
|
||||
if (nested_keys_names_size == nested_function_arguments_size - 1)
|
||||
@ -1344,7 +1344,7 @@ QueryTreeNodePtr IdentifierResolver::tryResolveExpressionFromArrayJoinExpression
|
||||
auto array_join_column = std::make_shared<ColumnNode>(array_join_column_expression_typed.getColumn(),
|
||||
array_join_column_expression_typed.getColumnSource());
|
||||
|
||||
const auto & nested_key_name = nested_keys_names[i - 1].get<String &>();
|
||||
const auto & nested_key_name = nested_keys_names[i - 1].safeGet<String &>();
|
||||
Identifier nested_identifier = Identifier(nested_key_name);
|
||||
array_join_resolved_expression = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier, scope.context);
|
||||
break;
|
||||
|
@ -748,11 +748,11 @@ void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_
|
||||
UInt64 pos;
|
||||
if (constant_node->getValue().getType() == Field::Types::UInt64)
|
||||
{
|
||||
pos = constant_node->getValue().get<UInt64>();
|
||||
pos = constant_node->getValue().safeGet<UInt64>();
|
||||
}
|
||||
else // Int64
|
||||
{
|
||||
auto value = constant_node->getValue().get<Int64>();
|
||||
auto value = constant_node->getValue().safeGet<Int64>();
|
||||
if (value > 0)
|
||||
pos = value;
|
||||
else
|
||||
|
@ -99,7 +99,7 @@ Block createBlockFromCollection(const Collection & collection, const DataTypes&
|
||||
"Invalid type in set. Expected tuple, got {}",
|
||||
value.getTypeName());
|
||||
|
||||
const auto & tuple = value.template get<const Tuple &>();
|
||||
const auto & tuple = value.template safeGet<const Tuple &>();
|
||||
const DataTypePtr & value_type = value_types[collection_index];
|
||||
const DataTypes & tuple_value_type = typeid_cast<const DataTypeTuple *>(value_type.get())->getElements();
|
||||
|
||||
@ -175,15 +175,15 @@ Block getSetElementsForConstantValue(const DataTypePtr & expression_type, const
|
||||
if (rhs_which_type.isArray())
|
||||
{
|
||||
const DataTypeArray * value_array_type = assert_cast<const DataTypeArray *>(value_type.get());
|
||||
size_t value_array_size = value.get<const Array &>().size();
|
||||
size_t value_array_size = value.safeGet<const Array &>().size();
|
||||
DataTypes value_types(value_array_size, value_array_type->getNestedType());
|
||||
result_block = createBlockFromCollection(value.get<const Array &>(), value_types, set_element_types, transform_null_in);
|
||||
result_block = createBlockFromCollection(value.safeGet<const Array &>(), value_types, set_element_types, transform_null_in);
|
||||
}
|
||||
else if (rhs_which_type.isTuple())
|
||||
{
|
||||
const DataTypeTuple * value_tuple_type = assert_cast<const DataTypeTuple *>(value_type.get());
|
||||
const DataTypes & value_types = value_tuple_type->getElements();
|
||||
result_block = createBlockFromCollection(value.get<const Tuple &>(), value_types, set_element_types, transform_null_in);
|
||||
result_block = createBlockFromCollection(value.safeGet<const Tuple &>(), value_types, set_element_types, transform_null_in);
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||
|
@ -126,7 +126,7 @@ std::vector<Strings> BackupSettings::Util::clusterHostIDsFromAST(const IAST & as
|
||||
throw Exception(
|
||||
ErrorCodes::CANNOT_PARSE_BACKUP_SETTINGS,
|
||||
"Setting cluster_host_ids has wrong format, must be array of arrays of string literals");
|
||||
const auto & replicas = array_of_replicas->value.get<const Array &>();
|
||||
const auto & replicas = array_of_replicas->value.safeGet<const Array &>();
|
||||
res[i].resize(replicas.size());
|
||||
for (size_t j = 0; j != replicas.size(); ++j)
|
||||
{
|
||||
@ -135,7 +135,7 @@ std::vector<Strings> BackupSettings::Util::clusterHostIDsFromAST(const IAST & as
|
||||
throw Exception(
|
||||
ErrorCodes::CANNOT_PARSE_BACKUP_SETTINGS,
|
||||
"Setting cluster_host_ids has wrong format, must be array of arrays of string literals");
|
||||
res[i][j] = replica.get<const String &>();
|
||||
res[i][j] = replica.safeGet<const String &>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,6 +490,8 @@ OperationID BackupsWorker::startMakingBackup(const ASTPtr & query, const Context
|
||||
|
||||
/// process_list_element_holder is used to make an element in ProcessList live while BACKUP is working asynchronously.
|
||||
auto process_list_element = context_in_use->getProcessListElement();
|
||||
/// Update context to preserve query information in processlist (settings, current_database)
|
||||
process_list_element->updateContext(context_in_use);
|
||||
|
||||
thread_pool.scheduleOrThrowOnError(
|
||||
[this,
|
||||
@ -853,6 +855,8 @@ OperationID BackupsWorker::startRestoring(const ASTPtr & query, ContextMutablePt
|
||||
|
||||
/// process_list_element_holder is used to make an element in ProcessList live while RESTORE is working asynchronously.
|
||||
auto process_list_element = context_in_use->getProcessListElement();
|
||||
/// Update context to preserve query information in processlist (settings, current_database)
|
||||
process_list_element->updateContext(context_in_use);
|
||||
|
||||
thread_pool.scheduleOrThrowOnError(
|
||||
[this,
|
||||
|
@ -46,8 +46,8 @@ namespace
|
||||
if (zookeeper_path_ast && (zookeeper_path_ast->value.getType() == Field::Types::String) &&
|
||||
replica_name_ast && (replica_name_ast->value.getType() == Field::Types::String))
|
||||
{
|
||||
String & zookeeper_path_arg = zookeeper_path_ast->value.get<String>();
|
||||
String & replica_name_arg = replica_name_ast->value.get<String>();
|
||||
String & zookeeper_path_arg = zookeeper_path_ast->value.safeGet<String>();
|
||||
String & replica_name_arg = replica_name_ast->value.safeGet<String>();
|
||||
if (create.uuid != UUIDHelpers::Nil)
|
||||
{
|
||||
String table_uuid_str = toString(create.uuid);
|
||||
|
@ -31,7 +31,7 @@ namespace
|
||||
{
|
||||
if (field.getType() == Field::Types::String)
|
||||
{
|
||||
const String & str = field.get<const String &>();
|
||||
const String & str = field.safeGet<const String &>();
|
||||
if (str == "1" || boost::iequals(str, "true") || boost::iequals(str, "create"))
|
||||
{
|
||||
value = RestoreTableCreationMode::kCreate;
|
||||
@ -54,7 +54,7 @@ namespace
|
||||
|
||||
if (field.getType() == Field::Types::UInt64)
|
||||
{
|
||||
UInt64 number = field.get<UInt64>();
|
||||
UInt64 number = field.safeGet<UInt64>();
|
||||
if (number == 1)
|
||||
{
|
||||
value = RestoreTableCreationMode::kCreate;
|
||||
@ -95,7 +95,7 @@ namespace
|
||||
{
|
||||
if (field.getType() == Field::Types::String)
|
||||
{
|
||||
const String & str = field.get<const String &>();
|
||||
const String & str = field.safeGet<const String &>();
|
||||
if (str == "1" || boost::iequals(str, "true") || boost::iequals(str, "create"))
|
||||
{
|
||||
value = RestoreAccessCreationMode::kCreate;
|
||||
@ -118,7 +118,7 @@ namespace
|
||||
|
||||
if (field.getType() == Field::Types::UInt64)
|
||||
{
|
||||
UInt64 number = field.get<UInt64>();
|
||||
UInt64 number = field.safeGet<UInt64>();
|
||||
if (number == 1)
|
||||
{
|
||||
value = RestoreAccessCreationMode::kCreate;
|
||||
|
@ -19,7 +19,7 @@ SettingFieldOptionalString::SettingFieldOptionalString(const Field & field)
|
||||
|
||||
if (field.getType() == Field::Types::String)
|
||||
{
|
||||
value = field.get<const String &>();
|
||||
value = field.safeGet<const String &>();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace ErrorCodes
|
||||
|
||||
if (field.getType() == Field::Types::String)
|
||||
{
|
||||
const String & str = field.get<const String &>();
|
||||
const String & str = field.safeGet<const String &>();
|
||||
if (str.empty())
|
||||
{
|
||||
value = std::nullopt;
|
||||
|
@ -68,13 +68,19 @@ const WithRetries::KeeperSettings & WithRetries::getKeeperSettings() const
|
||||
|
||||
WithRetries::FaultyKeeper WithRetries::getFaultyZooKeeper() const
|
||||
{
|
||||
/// We need to create new instance of ZooKeeperWithFaultInjection each time a copy a pointer to ZooKeeper client there
|
||||
zkutil::ZooKeeperPtr current_zookeeper;
|
||||
{
|
||||
std::lock_guard lock(zookeeper_mutex);
|
||||
current_zookeeper = zookeeper;
|
||||
}
|
||||
|
||||
/// We need to create new instance of ZooKeeperWithFaultInjection each time and copy a pointer to ZooKeeper client there
|
||||
/// The reason is that ZooKeeperWithFaultInjection may reset the underlying pointer and there could be a race condition
|
||||
/// when the same object is used from multiple threads.
|
||||
auto faulty_zookeeper = ZooKeeperWithFaultInjection::createInstance(
|
||||
settings.keeper_fault_injection_probability,
|
||||
settings.keeper_fault_injection_seed,
|
||||
zookeeper,
|
||||
current_zookeeper,
|
||||
log->name(),
|
||||
log);
|
||||
|
||||
|
@ -353,8 +353,8 @@ target_link_libraries(clickhouse_common_io
|
||||
Poco::Foundation
|
||||
)
|
||||
|
||||
if (TARGET ch_contrib::fiu)
|
||||
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::fiu)
|
||||
if (TARGET ch_contrib::libfiu)
|
||||
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::libfiu)
|
||||
endif()
|
||||
|
||||
if (TARGET ch_contrib::cpuid)
|
||||
@ -556,14 +556,13 @@ target_link_libraries (clickhouse_common_io PRIVATE ch_contrib::lz4)
|
||||
|
||||
if (TARGET ch_contrib::qpl)
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::qpl)
|
||||
target_link_libraries (clickhouse_compression PUBLIC ch_contrib::qpl)
|
||||
target_link_libraries (clickhouse_compression PUBLIC ch_contrib::accel-config)
|
||||
endif ()
|
||||
|
||||
if (TARGET ch_contrib::accel-config)
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::accel-config)
|
||||
endif ()
|
||||
|
||||
if (TARGET ch_contrib::qatzstd_plugin)
|
||||
if (TARGET ch_contrib::accel-config AND TARGET ch_contrib::qatzstd_plugin)
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::qatzstd_plugin)
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::accel-config)
|
||||
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::qatzstd_plugin)
|
||||
endif ()
|
||||
|
||||
|
@ -200,8 +200,6 @@ void ClientApplicationBase::init(int argc, char ** argv)
|
||||
("pager", po::value<std::string>(), "Pipe all output into this command (less or similar)")
|
||||
("max_memory_usage_in_client", po::value<std::string>(), "Set memory limit in client/local server")
|
||||
|
||||
("fuzzer-args", po::value<std::string>(), "Command line arguments for the LLVM's libFuzzer driver. Only relevant if the application is compiled with libFuzzer.")
|
||||
|
||||
("client_logs_file", po::value<std::string>(), "Path to a file for writing client logs. Currently we only have fatal logs (when the client crashes)")
|
||||
;
|
||||
|
||||
|
@ -477,6 +477,8 @@ void ClientBase::onProfileInfo(const ProfileInfo & profile_info)
|
||||
{
|
||||
if (profile_info.hasAppliedLimit() && output_format)
|
||||
output_format->setRowsBeforeLimit(profile_info.getRowsBeforeLimit());
|
||||
if (profile_info.hasAppliedAggregation() && output_format)
|
||||
output_format->setRowsBeforeAggregation(profile_info.getRowsBeforeAggregation());
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
#include <Client/Suggest.h>
|
||||
#include <Client/QueryFuzzer.h>
|
||||
#include <Common/QueryFuzzer.h>
|
||||
#include <Common/DNSResolver.h>
|
||||
#include <Common/InterruptListener.h>
|
||||
#include <Common/ProgressIndication.h>
|
||||
|
@ -1319,7 +1319,7 @@ Progress Connection::receiveProgress() const
|
||||
ProfileInfo Connection::receiveProfileInfo() const
|
||||
{
|
||||
ProfileInfo profile_info;
|
||||
profile_info.read(*in);
|
||||
profile_info.read(*in, server_revision);
|
||||
return profile_info;
|
||||
}
|
||||
|
||||
|
@ -365,7 +365,7 @@ bool LocalConnection::poll(size_t)
|
||||
{
|
||||
while (pollImpl())
|
||||
{
|
||||
LOG_DEBUG(&Poco::Logger::get("LocalConnection"), "Executor timeout encountered, will retry");
|
||||
LOG_TEST(&Poco::Logger::get("LocalConnection"), "Executor timeout encountered, will retry");
|
||||
|
||||
if (needSendProgressOrMetrics())
|
||||
return true;
|
||||
|
@ -214,7 +214,7 @@ void Suggest::fillWordsFromBlock(const Block & block)
|
||||
Words new_words;
|
||||
new_words.reserve(rows);
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
new_words.emplace_back(column[i].get<String>());
|
||||
new_words.emplace_back(column[i].safeGet<String>());
|
||||
|
||||
addWords(std::move(new_words));
|
||||
}
|
||||
|
@ -457,9 +457,9 @@ MutableColumnPtr ColumnAggregateFunction::cloneEmpty() const
|
||||
Field ColumnAggregateFunction::operator[](size_t n) const
|
||||
{
|
||||
Field field = AggregateFunctionStateData();
|
||||
field.get<AggregateFunctionStateData &>().name = type_string;
|
||||
field.safeGet<AggregateFunctionStateData &>().name = type_string;
|
||||
{
|
||||
WriteBufferFromString buffer(field.get<AggregateFunctionStateData &>().data);
|
||||
WriteBufferFromString buffer(field.safeGet<AggregateFunctionStateData &>().data);
|
||||
func->serialize(data[n], buffer, version);
|
||||
}
|
||||
return field;
|
||||
@ -467,12 +467,7 @@ Field ColumnAggregateFunction::operator[](size_t n) const
|
||||
|
||||
void ColumnAggregateFunction::get(size_t n, Field & res) const
|
||||
{
|
||||
res = AggregateFunctionStateData();
|
||||
res.get<AggregateFunctionStateData &>().name = type_string;
|
||||
{
|
||||
WriteBufferFromString buffer(res.get<AggregateFunctionStateData &>().data);
|
||||
func->serialize(data[n], buffer, version);
|
||||
}
|
||||
res = operator[](n);
|
||||
}
|
||||
|
||||
StringRef ColumnAggregateFunction::getDataAt(size_t n) const
|
||||
@ -552,7 +547,7 @@ void ColumnAggregateFunction::insert(const Field & x)
|
||||
"Inserting field of type {} into ColumnAggregateFunction. Expected {}",
|
||||
x.getTypeName(), Field::Types::AggregateFunctionState);
|
||||
|
||||
const auto & field_name = x.get<const AggregateFunctionStateData &>().name;
|
||||
const auto & field_name = x.safeGet<const AggregateFunctionStateData &>().name;
|
||||
if (type_string != field_name)
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot insert filed with type {} into column with type {}",
|
||||
field_name, type_string);
|
||||
@ -560,7 +555,7 @@ void ColumnAggregateFunction::insert(const Field & x)
|
||||
ensureOwnership();
|
||||
Arena & arena = createOrGetArena();
|
||||
pushBackAndCreateState(data, arena, func.get());
|
||||
ReadBufferFromString read_buffer(x.get<const AggregateFunctionStateData &>().data);
|
||||
ReadBufferFromString read_buffer(x.safeGet<const AggregateFunctionStateData &>().data);
|
||||
func->deserialize(data.back(), read_buffer, version, &arena);
|
||||
}
|
||||
|
||||
@ -569,14 +564,14 @@ bool ColumnAggregateFunction::tryInsert(const DB::Field & x)
|
||||
if (x.getType() != Field::Types::AggregateFunctionState)
|
||||
return false;
|
||||
|
||||
const auto & field_name = x.get<const AggregateFunctionStateData &>().name;
|
||||
const auto & field_name = x.safeGet<const AggregateFunctionStateData &>().name;
|
||||
if (type_string != field_name)
|
||||
return false;
|
||||
|
||||
ensureOwnership();
|
||||
Arena & arena = createOrGetArena();
|
||||
pushBackAndCreateState(data, arena, func.get());
|
||||
ReadBufferFromString read_buffer(x.get<const AggregateFunctionStateData &>().data);
|
||||
ReadBufferFromString read_buffer(x.safeGet<const AggregateFunctionStateData &>().data);
|
||||
func->deserialize(data.back(), read_buffer, version, &arena);
|
||||
return true;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ void ColumnArray::get(size_t n, Field & res) const
|
||||
size, max_array_size_as_field);
|
||||
|
||||
res = Array();
|
||||
Array & res_arr = res.get<Array &>();
|
||||
Array & res_arr = res.safeGet<Array &>();
|
||||
res_arr.reserve(size);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
@ -309,7 +309,7 @@ void ColumnArray::updateHashFast(SipHash & hash) const
|
||||
|
||||
void ColumnArray::insert(const Field & x)
|
||||
{
|
||||
const Array & array = x.get<const Array &>();
|
||||
const Array & array = x.safeGet<const Array &>();
|
||||
size_t size = array.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
getData().insert(array[i]);
|
||||
@ -321,7 +321,7 @@ bool ColumnArray::tryInsert(const Field & x)
|
||||
if (x.getType() != Field::Types::Which::Array)
|
||||
return false;
|
||||
|
||||
const Array & array = x.get<const Array &>();
|
||||
const Array & array = x.safeGet<const Array &>();
|
||||
size_t size = array.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
@ -452,6 +452,22 @@ void ColumnArray::reserve(size_t n)
|
||||
getData().reserve(n); /// The average size of arrays is not taken into account here. Or it is considered to be no more than 1.
|
||||
}
|
||||
|
||||
void ColumnArray::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
size_t new_size = size();
|
||||
Columns source_data_columns;
|
||||
source_data_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
{
|
||||
const auto & source_array_column = assert_cast<const ColumnArray &>(*source_column);
|
||||
new_size += source_array_column.size();
|
||||
source_data_columns.push_back(source_array_column.getDataPtr());
|
||||
}
|
||||
|
||||
getOffsets().reserve_exact(new_size);
|
||||
data->prepareForSquashing(source_data_columns);
|
||||
}
|
||||
|
||||
void ColumnArray::shrinkToFit()
|
||||
{
|
||||
getOffsets().shrink_to_fit();
|
||||
|
@ -118,6 +118,7 @@ public:
|
||||
void updatePermutationWithCollation(const Collator & collator, PermutationSortDirection direction, PermutationSortStability stability,
|
||||
size_t limit, int nan_direction_hint, Permutation & res, EqualRanges& equal_ranges) const override;
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void shrinkToFit() override;
|
||||
void ensureOwnership() override;
|
||||
size_t byteSize() const override;
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
void insertData(const char * src, size_t /*length*/) override;
|
||||
void insertDefault() override { data.push_back(T()); }
|
||||
void insertManyDefaults(size_t length) override { data.resize_fill(data.size() + length); }
|
||||
void insert(const Field & x) override { data.push_back(x.get<T>()); }
|
||||
void insert(const Field & x) override { data.push_back(x.safeGet<T>()); }
|
||||
bool tryInsert(const Field & x) override;
|
||||
#if !defined(DEBUG_OR_SANITIZER_BUILD)
|
||||
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
|
||||
|
@ -643,6 +643,116 @@ ColumnPtr ColumnDynamic::compress() const
|
||||
});
|
||||
}
|
||||
|
||||
void ColumnDynamic::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
if (source_columns.empty())
|
||||
return;
|
||||
|
||||
/// Internal variants of source dynamic columns may differ.
|
||||
/// We want to preallocate memory for all variants we will have after squashing.
|
||||
/// It may happen that the total number of variants in source columns will
|
||||
/// exceed the limit, in this case we will choose the most frequent variants.
|
||||
|
||||
/// First, preallocate memory for variant discriminators and offsets.
|
||||
size_t new_size = size();
|
||||
for (const auto & source_column : source_columns)
|
||||
new_size += source_column->size();
|
||||
auto & variant_col = getVariantColumn();
|
||||
variant_col.getLocalDiscriminators().reserve_exact(new_size);
|
||||
variant_col.getOffsets().reserve_exact(new_size);
|
||||
|
||||
/// Second, collect all variants and their total sizes.
|
||||
std::unordered_map<String, size_t> total_variant_sizes;
|
||||
DataTypes all_variants;
|
||||
|
||||
auto add_variants = [&](const ColumnDynamic & source_dynamic)
|
||||
{
|
||||
const auto & source_variant_column = source_dynamic.getVariantColumn();
|
||||
const auto & source_variant_info = source_dynamic.getVariantInfo();
|
||||
const auto & source_variants = assert_cast<const DataTypeVariant &>(*source_variant_info.variant_type).getVariants();
|
||||
|
||||
for (size_t i = 0; i != source_variants.size(); ++i)
|
||||
{
|
||||
const auto & variant_name = source_variant_info.variant_names[i];
|
||||
auto it = total_variant_sizes.find(variant_name);
|
||||
/// Add this variant to the list of all variants if we didn't see it yet.
|
||||
if (it == total_variant_sizes.end())
|
||||
{
|
||||
all_variants.push_back(source_variants[i]);
|
||||
it = total_variant_sizes.emplace(variant_name, 0).first;
|
||||
}
|
||||
|
||||
it->second += source_variant_column.getVariantByGlobalDiscriminator(i).size();
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto & source_column : source_columns)
|
||||
add_variants(assert_cast<const ColumnDynamic &>(*source_column));
|
||||
|
||||
/// Add variants from this dynamic column.
|
||||
add_variants(*this);
|
||||
|
||||
DataTypePtr result_variant_type;
|
||||
/// Check if the number of all variants exceeds the limit.
|
||||
if (all_variants.size() > max_dynamic_types || (all_variants.size() == max_dynamic_types && !total_variant_sizes.contains("String")))
|
||||
{
|
||||
/// We want to keep the most frequent variants in the resulting dynamic column.
|
||||
DataTypes result_variants;
|
||||
result_variants.reserve(max_dynamic_types);
|
||||
/// Add variants from current variant column as we will not rewrite it.
|
||||
for (const auto & variant : assert_cast<const DataTypeVariant &>(*variant_info.variant_type).getVariants())
|
||||
result_variants.push_back(variant);
|
||||
/// Add String variant in advance (if we didn't add it yet) as we must have it across variants when we reach the limit.
|
||||
if (!variant_info.variant_name_to_discriminator.contains("String"))
|
||||
result_variants.push_back(std::make_shared<DataTypeString>());
|
||||
|
||||
/// Create list of remaining variants with their sizes and sort it.
|
||||
std::vector<std::pair<size_t, DataTypePtr>> variants_with_sizes;
|
||||
variants_with_sizes.reserve(all_variants.size() - variant_info.variant_names.size());
|
||||
for (const auto & variant : all_variants)
|
||||
{
|
||||
/// Add variant to the list only of we didn't add it yet.
|
||||
auto variant_name = variant->getName();
|
||||
if (variant_name != "String" && !variant_info.variant_name_to_discriminator.contains(variant_name))
|
||||
variants_with_sizes.emplace_back(total_variant_sizes[variant->getName()], variant);
|
||||
}
|
||||
|
||||
std::sort(variants_with_sizes.begin(), variants_with_sizes.end(), std::greater());
|
||||
/// Add the most frequent variants until we reach max_dynamic_types.
|
||||
size_t num_new_variants = max_dynamic_types - result_variants.size();
|
||||
for (size_t i = 0; i != num_new_variants; ++i)
|
||||
result_variants.push_back(variants_with_sizes[i].second);
|
||||
|
||||
result_variant_type = std::make_shared<DataTypeVariant>(result_variants);
|
||||
}
|
||||
else
|
||||
{
|
||||
result_variant_type = std::make_shared<DataTypeVariant>(all_variants);
|
||||
}
|
||||
|
||||
if (!result_variant_type->equals(*variant_info.variant_type))
|
||||
updateVariantInfoAndExpandVariantColumn(result_variant_type);
|
||||
|
||||
/// Now current dynamic column has all resulting variants and we can call
|
||||
/// prepareForSquashing on them to preallocate the memory.
|
||||
for (size_t i = 0; i != variant_info.variant_names.size(); ++i)
|
||||
{
|
||||
Columns source_variant_columns;
|
||||
source_variant_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
{
|
||||
const auto & source_dynamic_column = assert_cast<const ColumnDynamic &>(*source_column);
|
||||
const auto & source_variant_info = source_dynamic_column.getVariantInfo();
|
||||
/// Try to find this variant in the current source column.
|
||||
auto it = source_variant_info.variant_name_to_discriminator.find(variant_info.variant_names[i]);
|
||||
if (it != source_variant_info.variant_name_to_discriminator.end())
|
||||
source_variant_columns.push_back(source_dynamic_column.getVariantColumn().getVariantPtrByGlobalDiscriminator(it->second));
|
||||
}
|
||||
|
||||
variant_col.getVariantByGlobalDiscriminator(i).prepareForSquashing(source_variant_columns);
|
||||
}
|
||||
}
|
||||
|
||||
void ColumnDynamic::takeDynamicStructureFromSourceColumns(const Columns & source_columns)
|
||||
{
|
||||
if (!empty())
|
||||
|
@ -254,6 +254,8 @@ public:
|
||||
variant_column->reserve(n);
|
||||
}
|
||||
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
|
||||
void ensureOwnership() override
|
||||
{
|
||||
variant_column->ensureOwnership();
|
||||
|
@ -59,7 +59,7 @@ bool ColumnFixedString::isDefaultAt(size_t index) const
|
||||
|
||||
void ColumnFixedString::insert(const Field & x)
|
||||
{
|
||||
const String & s = x.get<const String &>();
|
||||
const String & s = x.safeGet<const String &>();
|
||||
insertData(s.data(), s.size());
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ bool ColumnFixedString::tryInsert(const Field & x)
|
||||
{
|
||||
if (x.getType() != Field::Types::Which::String)
|
||||
return false;
|
||||
const String & s = x.get<const String &>();
|
||||
const String & s = x.safeGet<const String &>();
|
||||
if (s.size() > n)
|
||||
return false;
|
||||
insertData(s.data(), s.size());
|
||||
|
@ -72,7 +72,7 @@ void ColumnMap::get(size_t n, Field & res) const
|
||||
size_t size = offsets[n] - offsets[n - 1];
|
||||
|
||||
res = Map();
|
||||
auto & map = res.get<Map &>();
|
||||
auto & map = res.safeGet<Map &>();
|
||||
map.reserve(size);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
@ -96,7 +96,7 @@ void ColumnMap::insertData(const char *, size_t)
|
||||
|
||||
void ColumnMap::insert(const Field & x)
|
||||
{
|
||||
const auto & map = x.get<const Map &>();
|
||||
const auto & map = x.safeGet<const Map &>();
|
||||
nested->insert(Array(map.begin(), map.end()));
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ bool ColumnMap::tryInsert(const Field & x)
|
||||
if (x.getType() != Field::Types::Which::Map)
|
||||
return false;
|
||||
|
||||
const auto & map = x.get<const Map &>();
|
||||
const auto & map = x.safeGet<const Map &>();
|
||||
return nested->tryInsert(Array(map.begin(), map.end()));
|
||||
}
|
||||
|
||||
@ -249,6 +249,15 @@ void ColumnMap::reserve(size_t n)
|
||||
nested->reserve(n);
|
||||
}
|
||||
|
||||
void ColumnMap::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
Columns nested_source_columns;
|
||||
nested_source_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
nested_source_columns.push_back(assert_cast<const ColumnMap &>(*source_column).getNestedColumnPtr());
|
||||
nested->prepareForSquashing(nested_source_columns);
|
||||
}
|
||||
|
||||
void ColumnMap::shrinkToFit()
|
||||
{
|
||||
nested->shrinkToFit();
|
||||
@ -288,8 +297,8 @@ void ColumnMap::getExtremes(Field & min, Field & max) const
|
||||
|
||||
/// Convert result Array fields to Map fields because client expect min and max field to have type Map
|
||||
|
||||
Array nested_min_value = nested_min.get<Array>();
|
||||
Array nested_max_value = nested_max.get<Array>();
|
||||
Array nested_min_value = nested_min.safeGet<Array>();
|
||||
Array nested_max_value = nested_max.safeGet<Array>();
|
||||
|
||||
Map map_min_value(nested_min_value.begin(), nested_min_value.end());
|
||||
Map map_max_value(nested_max_value.begin(), nested_max_value.end());
|
||||
|
@ -94,6 +94,7 @@ public:
|
||||
void updatePermutation(IColumn::PermutationSortDirection direction, IColumn::PermutationSortStability stability,
|
||||
size_t limit, int nan_direction_hint, IColumn::Permutation & res, EqualRanges & equal_ranges) const override;
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void shrinkToFit() override;
|
||||
void ensureOwnership() override;
|
||||
size_t byteSize() const override;
|
||||
|
@ -706,6 +706,22 @@ void ColumnNullable::reserve(size_t n)
|
||||
getNullMapData().reserve(n);
|
||||
}
|
||||
|
||||
void ColumnNullable::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
size_t new_size = size();
|
||||
Columns nested_source_columns;
|
||||
nested_source_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
{
|
||||
const auto & source_nullable_column = assert_cast<const ColumnNullable &>(*source_column);
|
||||
new_size += source_nullable_column.size();
|
||||
nested_source_columns.push_back(source_nullable_column.getNestedColumnPtr());
|
||||
}
|
||||
|
||||
nested_column->prepareForSquashing(nested_source_columns);
|
||||
getNullMapData().reserve(new_size);
|
||||
}
|
||||
|
||||
void ColumnNullable::shrinkToFit()
|
||||
{
|
||||
getNestedColumn().shrinkToFit();
|
||||
|
@ -125,6 +125,7 @@ public:
|
||||
size_t limit, int null_direction_hint, Permutation & res, EqualRanges& equal_ranges) const override;
|
||||
size_t estimateCardinalityInPermutedRange(const Permutation & permutation, const EqualRange & equal_range) const override;
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void shrinkToFit() override;
|
||||
void ensureOwnership() override;
|
||||
size_t byteSize() const override;
|
||||
|
@ -698,7 +698,7 @@ void ColumnObject::forEachSubcolumnRecursively(RecursiveMutableColumnCallback ca
|
||||
|
||||
void ColumnObject::insert(const Field & field)
|
||||
{
|
||||
const auto & object = field.get<const Object &>();
|
||||
const auto & object = field.safeGet<const Object &>();
|
||||
|
||||
HashSet<StringRef, StringRefHash> inserted_paths;
|
||||
size_t old_size = size();
|
||||
@ -754,7 +754,7 @@ void ColumnObject::get(size_t n, Field & res) const
|
||||
{
|
||||
assert(n < size());
|
||||
res = Object();
|
||||
auto & object = res.get<Object &>();
|
||||
auto & object = res.safeGet<Object &>();
|
||||
|
||||
for (const auto & entry : subcolumns)
|
||||
{
|
||||
|
@ -557,6 +557,21 @@ void ColumnString::reserve(size_t n)
|
||||
offsets.reserve_exact(n);
|
||||
}
|
||||
|
||||
void ColumnString::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
size_t new_size = size();
|
||||
size_t new_chars_size = chars.size();
|
||||
for (const auto & source_column : source_columns)
|
||||
{
|
||||
const auto & source_string_column = assert_cast<const ColumnString &>(*source_column);
|
||||
new_size += source_string_column.size();
|
||||
new_chars_size += source_string_column.chars.size();
|
||||
}
|
||||
|
||||
offsets.reserve_exact(new_size);
|
||||
chars.reserve_exact(new_chars_size);
|
||||
}
|
||||
|
||||
void ColumnString::shrinkToFit()
|
||||
{
|
||||
chars.shrink_to_fit();
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
|
||||
void insert(const Field & x) override
|
||||
{
|
||||
const String & s = x.get<const String &>();
|
||||
const String & s = x.safeGet<const String &>();
|
||||
const size_t old_size = chars.size();
|
||||
const size_t size_to_append = s.size() + 1;
|
||||
const size_t new_size = old_size + size_to_append;
|
||||
@ -283,6 +283,7 @@ public:
|
||||
ColumnPtr compress() const override;
|
||||
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void shrinkToFit() override;
|
||||
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
|
@ -141,7 +141,7 @@ void ColumnTuple::get(size_t n, Field & res) const
|
||||
const size_t tuple_size = columns.size();
|
||||
|
||||
res = Tuple();
|
||||
Tuple & res_tuple = res.get<Tuple &>();
|
||||
Tuple & res_tuple = res.safeGet<Tuple &>();
|
||||
res_tuple.reserve(tuple_size);
|
||||
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
@ -169,7 +169,7 @@ void ColumnTuple::insertData(const char *, size_t)
|
||||
|
||||
void ColumnTuple::insert(const Field & x)
|
||||
{
|
||||
const auto & tuple = x.get<const Tuple &>();
|
||||
const auto & tuple = x.safeGet<const Tuple &>();
|
||||
|
||||
const size_t tuple_size = columns.size();
|
||||
if (tuple.size() != tuple_size)
|
||||
@ -185,7 +185,7 @@ bool ColumnTuple::tryInsert(const Field & x)
|
||||
if (x.getType() != Field::Types::Which::Tuple)
|
||||
return false;
|
||||
|
||||
const auto & tuple = x.get<const Tuple &>();
|
||||
const auto & tuple = x.safeGet<const Tuple &>();
|
||||
|
||||
const size_t tuple_size = columns.size();
|
||||
if (tuple.size() != tuple_size)
|
||||
@ -595,6 +595,19 @@ void ColumnTuple::reserve(size_t n)
|
||||
getColumn(i).reserve(n);
|
||||
}
|
||||
|
||||
void ColumnTuple::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
{
|
||||
Columns nested_columns;
|
||||
nested_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
nested_columns.push_back(assert_cast<const ColumnTuple &>(*source_column).getColumnPtr(i));
|
||||
getColumn(i).prepareForSquashing(nested_columns);
|
||||
}
|
||||
}
|
||||
|
||||
void ColumnTuple::shrinkToFit()
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
|
@ -110,6 +110,7 @@ public:
|
||||
void updatePermutationWithCollation(const Collator & collator, IColumn::PermutationSortDirection direction, IColumn::PermutationSortStability stability,
|
||||
size_t limit, int nan_direction_hint, IColumn::Permutation & res, EqualRanges& equal_ranges) const override;
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void shrinkToFit() override;
|
||||
void ensureOwnership() override;
|
||||
size_t byteSize() const override;
|
||||
|
@ -1247,8 +1247,25 @@ void ColumnVariant::updatePermutation(IColumn::PermutationSortDirection directio
|
||||
|
||||
void ColumnVariant::reserve(size_t n)
|
||||
{
|
||||
local_discriminators->reserve(n);
|
||||
offsets->reserve(n);
|
||||
getLocalDiscriminators().reserve_exact(n);
|
||||
getOffsets().reserve_exact(n);
|
||||
}
|
||||
|
||||
void ColumnVariant::prepareForSquashing(const Columns & source_columns)
|
||||
{
|
||||
size_t new_size = size();
|
||||
for (const auto & source_column : source_columns)
|
||||
new_size += source_column->size();
|
||||
reserve(new_size);
|
||||
|
||||
for (size_t i = 0; i != variants.size(); ++i)
|
||||
{
|
||||
Columns source_variant_columns;
|
||||
source_variant_columns.reserve(source_columns.size());
|
||||
for (const auto & source_column : source_columns)
|
||||
source_variant_columns.push_back(assert_cast<const ColumnVariant &>(*source_column).getVariantPtrByGlobalDiscriminator(i));
|
||||
getVariantByGlobalDiscriminator(i).prepareForSquashing(source_variant_columns);
|
||||
}
|
||||
}
|
||||
|
||||
void ColumnVariant::ensureOwnership()
|
||||
|
@ -237,6 +237,7 @@ public:
|
||||
size_t limit, int nan_direction_hint, IColumn::Permutation & res, EqualRanges & equal_ranges) const override;
|
||||
|
||||
void reserve(size_t n) override;
|
||||
void prepareForSquashing(const Columns & source_columns) override;
|
||||
void ensureOwnership() override;
|
||||
size_t byteSize() const override;
|
||||
size_t byteSizeAt(size_t n) const override;
|
||||
|
@ -85,7 +85,7 @@ public:
|
||||
|
||||
void insertMany(const Field & field, size_t length) override
|
||||
{
|
||||
data.resize_fill(data.size() + length, static_cast<T>(field.get<T>()));
|
||||
data.resize_fill(data.size() + length, static_cast<T>(field.safeGet<T>()));
|
||||
}
|
||||
|
||||
void insertData(const char * pos, size_t) override
|
||||
@ -235,7 +235,7 @@ public:
|
||||
|
||||
void insert(const Field & x) override
|
||||
{
|
||||
data.push_back(static_cast<T>(x.get<T>()));
|
||||
data.push_back(static_cast<T>(x.safeGet<T>()));
|
||||
}
|
||||
|
||||
bool tryInsert(const DB::Field & x) override;
|
||||
|
@ -475,6 +475,15 @@ public:
|
||||
/// It affects performance only (not correctness).
|
||||
virtual void reserve(size_t /*n*/) {}
|
||||
|
||||
/// Reserve memory before squashing all specified source columns into this column.
|
||||
virtual void prepareForSquashing(const std::vector<Ptr> & source_columns)
|
||||
{
|
||||
size_t new_size = size();
|
||||
for (const auto & source_column : source_columns)
|
||||
new_size += source_column->size();
|
||||
reserve(new_size);
|
||||
}
|
||||
|
||||
/// Requests the removal of unused capacity.
|
||||
/// It is a non-binding request to reduce the capacity of the underlying container to its size.
|
||||
virtual void shrinkToFit() {}
|
||||
|
@ -108,10 +108,10 @@ void checkColumnVariant1(ColumnVariant * column)
|
||||
ASSERT_EQ(offsets[1], 0);
|
||||
ASSERT_EQ(offsets[3], 1);
|
||||
ASSERT_TRUE(column->isDefaultAt(2) && column->isDefaultAt(4));
|
||||
ASSERT_EQ((*column)[0].get<UInt32>(), 42);
|
||||
ASSERT_EQ((*column)[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*column)[0].safeGet<UInt32>(), 42);
|
||||
ASSERT_EQ((*column)[1].safeGet<String>(), "Hello");
|
||||
ASSERT_TRUE((*column)[2].isNull());
|
||||
ASSERT_EQ((*column)[3].get<String>(), "World");
|
||||
ASSERT_EQ((*column)[3].safeGet<String>(), "World");
|
||||
ASSERT_TRUE((*column)[4].isNull());
|
||||
}
|
||||
|
||||
@ -209,9 +209,9 @@ TEST(ColumnVariant, CreateFromDiscriminatorsAndOneFullColumnNoNulls)
|
||||
ASSERT_EQ(offsets[0], 0);
|
||||
ASSERT_EQ(offsets[1], 1);
|
||||
ASSERT_EQ(offsets[2], 2);
|
||||
ASSERT_EQ((*column)[0].get<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*column)[2].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*column)[0].safeGet<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*column)[2].safeGet<UInt64>(), 2);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, CreateFromDiscriminatorsAndOneFullColumnNoNullsWithLocalOrder)
|
||||
@ -222,9 +222,9 @@ TEST(ColumnVariant, CreateFromDiscriminatorsAndOneFullColumnNoNullsWithLocalOrde
|
||||
ASSERT_EQ(offsets[0], 0);
|
||||
ASSERT_EQ(offsets[1], 1);
|
||||
ASSERT_EQ(offsets[2], 2);
|
||||
ASSERT_EQ((*column)[0].get<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*column)[2].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*column)[0].safeGet<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*column)[2].safeGet<UInt64>(), 2);
|
||||
ASSERT_EQ(column->localDiscriminatorAt(0), 2);
|
||||
ASSERT_EQ(column->localDiscriminatorAt(1), 2);
|
||||
ASSERT_EQ(column->localDiscriminatorAt(2), 2);
|
||||
@ -331,9 +331,9 @@ TEST(ColumnVariant, CloneResizedGeneral1)
|
||||
ASSERT_EQ(offsets[0], 0);
|
||||
ASSERT_EQ(offsets[1], 0);
|
||||
ASSERT_EQ(offsets[3], 1);
|
||||
ASSERT_EQ((*resized_column_variant)[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*resized_column_variant)[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*resized_column_variant)[3].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*resized_column_variant)[0].safeGet<UInt64>(), 42);
|
||||
ASSERT_EQ((*resized_column_variant)[1].safeGet<String>(), "Hello");
|
||||
ASSERT_EQ((*resized_column_variant)[3].safeGet<UInt64>(), 43);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, CloneResizedGeneral2)
|
||||
@ -367,7 +367,7 @@ TEST(ColumnVariant, CloneResizedGeneral2)
|
||||
ASSERT_EQ(discriminators[2], ColumnVariant::NULL_DISCRIMINATOR);
|
||||
const auto & offsets = resized_column_variant->getOffsets();
|
||||
ASSERT_EQ(offsets[0], 0);
|
||||
ASSERT_EQ((*resized_column_variant)[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*resized_column_variant)[0].safeGet<UInt64>(), 42);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, CloneResizedGeneral3)
|
||||
@ -405,10 +405,10 @@ TEST(ColumnVariant, CloneResizedGeneral3)
|
||||
ASSERT_EQ(offsets[1], 0);
|
||||
ASSERT_EQ(offsets[2], 1);
|
||||
ASSERT_EQ(offsets[3], 1);
|
||||
ASSERT_EQ((*resized_column_variant)[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*resized_column_variant)[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*resized_column_variant)[2].get<String>(), "World");
|
||||
ASSERT_EQ((*resized_column_variant)[3].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*resized_column_variant)[0].safeGet<UInt64>(), 42);
|
||||
ASSERT_EQ((*resized_column_variant)[1].safeGet<String>(), "Hello");
|
||||
ASSERT_EQ((*resized_column_variant)[2].safeGet<String>(), "World");
|
||||
ASSERT_EQ((*resized_column_variant)[3].safeGet<UInt64>(), 43);
|
||||
}
|
||||
|
||||
MutableColumnPtr createDiscriminators2()
|
||||
@ -465,7 +465,7 @@ TEST(ColumnVariant, InsertFrom)
|
||||
auto column_from = createVariantColumn2(change_order);
|
||||
column_to->insertFrom(*column_from, 3);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(5), 0);
|
||||
ASSERT_EQ((*column_to)[5].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[5].safeGet<UInt64>(), 43);
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,8 +478,8 @@ TEST(ColumnVariant, InsertRangeFromOneColumnNoNulls)
|
||||
column_to->insertRangeFrom(*column_from, 2, 2);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(7), 0);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(8), 0);
|
||||
ASSERT_EQ((*column_to)[7].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*column_to)[8].get<UInt64>(), 3);
|
||||
ASSERT_EQ((*column_to)[7].safeGet<UInt64>(), 2);
|
||||
ASSERT_EQ((*column_to)[8].safeGet<UInt64>(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,9 +494,9 @@ TEST(ColumnVariant, InsertRangeFromGeneral)
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(6), ColumnVariant::NULL_DISCRIMINATOR);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(7), 0);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(8), 1);
|
||||
ASSERT_EQ((*column_to)[5].get<String>(), "Hello");
|
||||
ASSERT_EQ((*column_to)[7].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[8].get<String>(), "World");
|
||||
ASSERT_EQ((*column_to)[5].safeGet<String>(), "Hello");
|
||||
ASSERT_EQ((*column_to)[7].safeGet<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[8].safeGet<String>(), "World");
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,8 +509,8 @@ TEST(ColumnVariant, InsertManyFrom)
|
||||
column_to->insertManyFrom(*column_from, 3, 2);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(5), 0);
|
||||
ASSERT_EQ(column_to->globalDiscriminatorAt(6), 0);
|
||||
ASSERT_EQ((*column_to)[5].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[6].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[5].safeGet<UInt64>(), 43);
|
||||
ASSERT_EQ((*column_to)[6].safeGet<UInt64>(), 43);
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,8 +520,8 @@ TEST(ColumnVariant, PopBackOneColumnNoNulls)
|
||||
column->popBack(3);
|
||||
ASSERT_EQ(column->size(), 2);
|
||||
ASSERT_EQ(column->getVariantByLocalDiscriminator(0).size(), 2);
|
||||
ASSERT_EQ((*column)[0].get<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*column)[0].safeGet<UInt64>(), 0);
|
||||
ASSERT_EQ((*column)[1].safeGet<UInt64>(), 1);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, PopBackGeneral)
|
||||
@ -531,8 +531,8 @@ TEST(ColumnVariant, PopBackGeneral)
|
||||
ASSERT_EQ(column->size(), 3);
|
||||
ASSERT_EQ(column->getVariantByLocalDiscriminator(0).size(), 1);
|
||||
ASSERT_EQ(column->getVariantByLocalDiscriminator(1).size(), 1);
|
||||
ASSERT_EQ((*column)[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*column)[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*column)[0].safeGet<UInt64>(), 42);
|
||||
ASSERT_EQ((*column)[1].safeGet<String>(), "Hello");
|
||||
ASSERT_TRUE((*column)[2].isNull());
|
||||
}
|
||||
|
||||
@ -545,8 +545,8 @@ TEST(ColumnVariant, FilterOneColumnNoNulls)
|
||||
filter.push_back(1);
|
||||
auto filtered_column = column->filter(filter, -1);
|
||||
ASSERT_EQ(filtered_column->size(), 2);
|
||||
ASSERT_EQ((*filtered_column)[0].get<UInt64>(), 0);
|
||||
ASSERT_EQ((*filtered_column)[1].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*filtered_column)[0].safeGet<UInt64>(), 0);
|
||||
ASSERT_EQ((*filtered_column)[1].safeGet<UInt64>(), 2);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, FilterGeneral)
|
||||
@ -562,7 +562,7 @@ TEST(ColumnVariant, FilterGeneral)
|
||||
filter.push_back(0);
|
||||
auto filtered_column = column->filter(filter, -1);
|
||||
ASSERT_EQ(filtered_column->size(), 3);
|
||||
ASSERT_EQ((*filtered_column)[0].get<String>(), "Hello");
|
||||
ASSERT_EQ((*filtered_column)[0].safeGet<String>(), "Hello");
|
||||
ASSERT_TRUE((*filtered_column)[1].isNull());
|
||||
ASSERT_TRUE((*filtered_column)[2].isNull());
|
||||
}
|
||||
@ -577,9 +577,9 @@ TEST(ColumnVariant, PermuteAndIndexOneColumnNoNulls)
|
||||
permutation.push_back(0);
|
||||
auto permuted_column = column->permute(permutation, 3);
|
||||
ASSERT_EQ(permuted_column->size(), 3);
|
||||
ASSERT_EQ((*permuted_column)[0].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*permuted_column)[1].get<UInt64>(), 3);
|
||||
ASSERT_EQ((*permuted_column)[2].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*permuted_column)[0].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*permuted_column)[1].safeGet<UInt64>(), 3);
|
||||
ASSERT_EQ((*permuted_column)[2].safeGet<UInt64>(), 2);
|
||||
|
||||
auto index = ColumnUInt64::create();
|
||||
index->getData().push_back(1);
|
||||
@ -588,9 +588,9 @@ TEST(ColumnVariant, PermuteAndIndexOneColumnNoNulls)
|
||||
index->getData().push_back(0);
|
||||
auto indexed_column = column->index(*index, 3);
|
||||
ASSERT_EQ(indexed_column->size(), 3);
|
||||
ASSERT_EQ((*indexed_column)[0].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*indexed_column)[1].get<UInt64>(), 3);
|
||||
ASSERT_EQ((*indexed_column)[2].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*indexed_column)[0].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*indexed_column)[1].safeGet<UInt64>(), 3);
|
||||
ASSERT_EQ((*indexed_column)[2].safeGet<UInt64>(), 2);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, PermuteGeneral)
|
||||
@ -603,9 +603,9 @@ TEST(ColumnVariant, PermuteGeneral)
|
||||
permutation.push_back(5);
|
||||
auto permuted_column = column->permute(permutation, 4);
|
||||
ASSERT_EQ(permuted_column->size(), 4);
|
||||
ASSERT_EQ((*permuted_column)[0].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*permuted_column)[1].get<String>(), "World");
|
||||
ASSERT_EQ((*permuted_column)[2].get<String>(), "Hello");
|
||||
ASSERT_EQ((*permuted_column)[0].safeGet<UInt64>(), 43);
|
||||
ASSERT_EQ((*permuted_column)[1].safeGet<String>(), "World");
|
||||
ASSERT_EQ((*permuted_column)[2].safeGet<String>(), "Hello");
|
||||
ASSERT_TRUE((*permuted_column)[3].isNull());
|
||||
}
|
||||
|
||||
@ -618,12 +618,12 @@ TEST(ColumnVariant, ReplicateOneColumnNoNull)
|
||||
offsets.push_back(6);
|
||||
auto replicated_column = column->replicate(offsets);
|
||||
ASSERT_EQ(replicated_column->size(), 6);
|
||||
ASSERT_EQ((*replicated_column)[0].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[1].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[2].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[3].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*replicated_column)[4].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*replicated_column)[5].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*replicated_column)[0].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[1].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[2].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*replicated_column)[3].safeGet<UInt64>(), 2);
|
||||
ASSERT_EQ((*replicated_column)[4].safeGet<UInt64>(), 2);
|
||||
ASSERT_EQ((*replicated_column)[5].safeGet<UInt64>(), 2);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, ReplicateGeneral)
|
||||
@ -637,9 +637,9 @@ TEST(ColumnVariant, ReplicateGeneral)
|
||||
offsets.push_back(7);
|
||||
auto replicated_column = column->replicate(offsets);
|
||||
ASSERT_EQ(replicated_column->size(), 7);
|
||||
ASSERT_EQ((*replicated_column)[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*replicated_column)[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*replicated_column)[2].get<String>(), "Hello");
|
||||
ASSERT_EQ((*replicated_column)[0].safeGet<UInt64>(), 42);
|
||||
ASSERT_EQ((*replicated_column)[1].safeGet<String>(), "Hello");
|
||||
ASSERT_EQ((*replicated_column)[2].safeGet<String>(), "Hello");
|
||||
ASSERT_TRUE((*replicated_column)[3].isNull());
|
||||
ASSERT_TRUE((*replicated_column)[4].isNull());
|
||||
ASSERT_TRUE((*replicated_column)[5].isNull());
|
||||
@ -657,13 +657,13 @@ TEST(ColumnVariant, ScatterOneColumnNoNulls)
|
||||
selector.push_back(1);
|
||||
auto columns = column->scatter(3, selector);
|
||||
ASSERT_EQ(columns[0]->size(), 2);
|
||||
ASSERT_EQ((*columns[0])[0].get<UInt64>(), 0);
|
||||
ASSERT_EQ((*columns[0])[1].get<UInt64>(), 3);
|
||||
ASSERT_EQ((*columns[0])[0].safeGet<UInt64>(), 0);
|
||||
ASSERT_EQ((*columns[0])[1].safeGet<UInt64>(), 3);
|
||||
ASSERT_EQ(columns[1]->size(), 2);
|
||||
ASSERT_EQ((*columns[1])[0].get<UInt64>(), 1);
|
||||
ASSERT_EQ((*columns[1])[1].get<UInt64>(), 4);
|
||||
ASSERT_EQ((*columns[1])[0].safeGet<UInt64>(), 1);
|
||||
ASSERT_EQ((*columns[1])[1].safeGet<UInt64>(), 4);
|
||||
ASSERT_EQ(columns[2]->size(), 1);
|
||||
ASSERT_EQ((*columns[2])[0].get<UInt64>(), 2);
|
||||
ASSERT_EQ((*columns[2])[0].safeGet<UInt64>(), 2);
|
||||
}
|
||||
|
||||
TEST(ColumnVariant, ScatterGeneral)
|
||||
@ -680,12 +680,12 @@ TEST(ColumnVariant, ScatterGeneral)
|
||||
|
||||
auto columns = column->scatter(3, selector);
|
||||
ASSERT_EQ(columns[0]->size(), 3);
|
||||
ASSERT_EQ((*columns[0])[0].get<UInt64>(), 42);
|
||||
ASSERT_EQ((*columns[0])[1].get<String>(), "Hello");
|
||||
ASSERT_EQ((*columns[0])[2].get<UInt64>(), 43);
|
||||
ASSERT_EQ((*columns[0])[0].safeGet<UInt64>(), 42);
|
||||
ASSERT_EQ((*columns[0])[1].safeGet<String>(), "Hello");
|
||||
ASSERT_EQ((*columns[0])[2].safeGet<UInt64>(), 43);
|
||||
ASSERT_EQ(columns[1]->size(), 2);
|
||||
ASSERT_EQ((*columns[1])[0].get<String>(), "World");
|
||||
ASSERT_EQ((*columns[1])[1].get<UInt64>(), 44);
|
||||
ASSERT_EQ((*columns[1])[0].safeGet<String>(), "World");
|
||||
ASSERT_EQ((*columns[1])[1].safeGet<UInt64>(), 44);
|
||||
ASSERT_EQ(columns[2]->size(), 2);
|
||||
ASSERT_TRUE((*columns[2])[0].isNull());
|
||||
ASSERT_TRUE((*columns[2])[1].isNull());
|
||||
|
@ -20,13 +20,13 @@ void testLowCardinalityNumberInsert(const DataTypePtr & data_type)
|
||||
|
||||
Field value;
|
||||
column->get(0, value);
|
||||
ASSERT_EQ(value.get<T>(), 15);
|
||||
ASSERT_EQ(value.safeGet<T>(), 15);
|
||||
|
||||
column->get(1, value);
|
||||
ASSERT_EQ(value.get<T>(), 20);
|
||||
ASSERT_EQ(value.safeGet<T>(), 20);
|
||||
|
||||
column->get(2, value);
|
||||
ASSERT_EQ(value.get<T>(), 25);
|
||||
ASSERT_EQ(value.safeGet<T>(), 25);
|
||||
}
|
||||
|
||||
TEST(ColumnLowCardinality, Insert)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user