mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-12 09:22:05 +00:00
Merge branch 'master' into cancellable-mutex
This commit is contained in:
commit
c65573dd7e
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -284,6 +284,9 @@
|
||||
[submodule "contrib/xxHash"]
|
||||
path = contrib/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
[submodule "contrib/crc32-s390x"]
|
||||
path = contrib/crc32-s390x
|
||||
url = https://github.com/linux-on-ibm-z/crc32-s390x.git
|
||||
[submodule "contrib/openssl"]
|
||||
path = contrib/openssl
|
||||
url = https://github.com/openssl/openssl
|
||||
@ -323,4 +326,4 @@
|
||||
url = https://github.com/awslabs/aws-c-compression.git
|
||||
[submodule "contrib/aws-s2n-tls"]
|
||||
path = contrib/aws-s2n-tls
|
||||
url = https://github.com/aws/s2n-tls.git
|
||||
url = https://github.com/ClickHouse/s2n-tls.git
|
||||
|
4
contrib/CMakeLists.txt
vendored
4
contrib/CMakeLists.txt
vendored
@ -179,6 +179,10 @@ add_contrib (c-ares-cmake c-ares)
|
||||
add_contrib (qpl-cmake qpl)
|
||||
add_contrib (morton-nd-cmake morton-nd)
|
||||
|
||||
if (ARCH_S390X)
|
||||
add_contrib(crc32-s390x-cmake crc32-s390x)
|
||||
endif()
|
||||
|
||||
add_contrib (annoy-cmake annoy)
|
||||
|
||||
add_contrib (xxHash-cmake xxHash)
|
||||
|
2
contrib/aws-s2n-tls
vendored
2
contrib/aws-s2n-tls
vendored
@ -1 +1 @@
|
||||
Subproject commit 15d534e8a9ca1eda6bacee514e37d08b4f38a526
|
||||
Subproject commit 0f1ba9e5c4a67cb3898de0c0b4f911d4194dc8de
|
1
contrib/crc32-s390x
vendored
Submodule
1
contrib/crc32-s390x
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 30980583bf9ed3fa193abb83a1849705ff457f70
|
27
contrib/crc32-s390x-cmake/CMakeLists.txt
Normal file
27
contrib/crc32-s390x-cmake/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
if(ARCH_S390X)
|
||||
option (ENABLE_CRC32_S390X "Enable crc32 on s390x platform" ON)
|
||||
endif()
|
||||
|
||||
if (NOT ENABLE_CRC32_S390X)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(CRC32_S390X_SOURCE_DIR ${ClickHouse_SOURCE_DIR}/contrib/crc32-s390x)
|
||||
set(CRC32_S390X_INCLUDE_DIR ${ClickHouse_SOURCE_DIR}/contrib/crc32-s390x)
|
||||
|
||||
set(CRC32_SRCS
|
||||
"${CRC32_S390X_SOURCE_DIR}/crc32-s390x.c"
|
||||
"${CRC32_S390X_SOURCE_DIR}/crc32be-vx.S"
|
||||
"${CRC32_S390X_SOURCE_DIR}/crc32le-vx.S"
|
||||
)
|
||||
|
||||
set(CRC32_HDRS
|
||||
"${CRC32_S390X_INCLUDE_DIR}/crc32-s390x.h"
|
||||
)
|
||||
|
||||
add_library(_crc32_s390x ${CRC32_SRCS} ${CRC32_HDRS})
|
||||
|
||||
target_include_directories(_crc32_s390x SYSTEM PUBLIC "${CRC32_S390X_INCLUDE_DIR}")
|
||||
target_compile_definitions(_crc32_s390x PUBLIC)
|
||||
|
||||
add_library(ch_contrib::crc32_s390x ALIAS _crc32_s390x)
|
@ -57,14 +57,17 @@ RUN arch=${TARGETARCH:-amd64} \
|
||||
# ZooKeeper is not started by default, but consumes some space in containers.
|
||||
# 777 perms used to allow anybody to start/stop ZooKeeper
|
||||
ENV ZOOKEEPER_VERSION='3.6.3'
|
||||
RUN curl -O "https://dlcdn.apache.org/zookeeper/zookeeper-${ZOOKEEPER_VERSION}/apache-zookeeper-${ZOOKEEPER_VERSION}-bin.tar.gz"
|
||||
RUN tar -zxvf apache-zookeeper-${ZOOKEEPER_VERSION}-bin.tar.gz && mv apache-zookeeper-${ZOOKEEPER_VERSION}-bin /opt/zookeeper && chmod -R 777 /opt/zookeeper && rm apache-zookeeper-${ZOOKEEPER_VERSION}-bin.tar.gz
|
||||
RUN echo $'tickTime=2500 \n\
|
||||
RUN curl "https://archive.apache.org/dist/zookeeper/zookeeper-${ZOOKEEPER_VERSION}/apache-zookeeper-${ZOOKEEPER_VERSION}-bin.tar.gz" | \
|
||||
tar -C opt -zxv && \
|
||||
mv /opt/apache-zookeeper-${ZOOKEEPER_VERSION}-bin /opt/zookeeper && \
|
||||
chmod -R 777 /opt/zookeeper && \
|
||||
echo $'tickTime=2500 \n\
|
||||
tickTime=2500 \n\
|
||||
dataDir=/zookeeper \n\
|
||||
clientPort=2181 \n\
|
||||
maxClientCnxns=80' > /opt/zookeeper/conf/zoo.cfg
|
||||
RUN mkdir /zookeeper && chmod -R 777 /zookeeper
|
||||
maxClientCnxns=80' > /opt/zookeeper/conf/zoo.cfg && \
|
||||
mkdir /zookeeper && \
|
||||
chmod -R 777 /zookeeper
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
@ -0,0 +1,5 @@
|
||||
version: '2.3'
|
||||
# Used to pre-pull images with docker-compose
|
||||
services:
|
||||
clickhouse1:
|
||||
image: clickhouse/integration-test
|
@ -5,10 +5,10 @@ services:
|
||||
hostname: hdfs1
|
||||
restart: always
|
||||
expose:
|
||||
- ${HDFS_NAME_PORT}
|
||||
- ${HDFS_DATA_PORT}
|
||||
- ${HDFS_NAME_PORT:-50070}
|
||||
- ${HDFS_DATA_PORT:-50075}
|
||||
entrypoint: /etc/bootstrap.sh -d
|
||||
volumes:
|
||||
- type: ${HDFS_FS:-tmpfs}
|
||||
source: ${HDFS_LOGS:-}
|
||||
target: /usr/local/hadoop/logs
|
||||
target: /usr/local/hadoop/logs
|
||||
|
@ -15,7 +15,7 @@ services:
|
||||
image: confluentinc/cp-kafka:5.2.0
|
||||
hostname: kafka1
|
||||
ports:
|
||||
- ${KAFKA_EXTERNAL_PORT}:${KAFKA_EXTERNAL_PORT}
|
||||
- ${KAFKA_EXTERNAL_PORT:-8081}:${KAFKA_EXTERNAL_PORT:-8081}
|
||||
environment:
|
||||
KAFKA_ADVERTISED_LISTENERS: INSIDE://localhost:${KAFKA_EXTERNAL_PORT},OUTSIDE://kafka1:19092
|
||||
KAFKA_ADVERTISED_HOST_NAME: kafka1
|
||||
@ -35,7 +35,7 @@ services:
|
||||
image: confluentinc/cp-schema-registry:5.2.0
|
||||
hostname: schema-registry
|
||||
ports:
|
||||
- ${SCHEMA_REGISTRY_EXTERNAL_PORT}:${SCHEMA_REGISTRY_INTERNAL_PORT}
|
||||
- ${SCHEMA_REGISTRY_EXTERNAL_PORT:-12313}:${SCHEMA_REGISTRY_INTERNAL_PORT:-12313}
|
||||
environment:
|
||||
SCHEMA_REGISTRY_HOST_NAME: schema-registry
|
||||
SCHEMA_REGISTRY_KAFKASTORE_SECURITY_PROTOCOL: PLAINTEXT
|
||||
|
@ -15,8 +15,8 @@ services:
|
||||
source: ${KERBERIZED_HDFS_LOGS:-}
|
||||
target: /var/log/hadoop-hdfs
|
||||
expose:
|
||||
- ${KERBERIZED_HDFS_NAME_PORT}
|
||||
- ${KERBERIZED_HDFS_DATA_PORT}
|
||||
- ${KERBERIZED_HDFS_NAME_PORT:-50070}
|
||||
- ${KERBERIZED_HDFS_DATA_PORT:-1006}
|
||||
depends_on:
|
||||
- hdfskerberos
|
||||
entrypoint: /etc/bootstrap.sh -d
|
||||
|
@ -23,7 +23,7 @@ services:
|
||||
# restart: always
|
||||
hostname: kerberized_kafka1
|
||||
ports:
|
||||
- ${KERBERIZED_KAFKA_EXTERNAL_PORT}:${KERBERIZED_KAFKA_EXTERNAL_PORT}
|
||||
- ${KERBERIZED_KAFKA_EXTERNAL_PORT:-19092}:${KERBERIZED_KAFKA_EXTERNAL_PORT:-19092}
|
||||
environment:
|
||||
KAFKA_LISTENERS: OUTSIDE://:19092,UNSECURED_OUTSIDE://:19093,UNSECURED_INSIDE://0.0.0.0:${KERBERIZED_KAFKA_EXTERNAL_PORT}
|
||||
KAFKA_ADVERTISED_LISTENERS: OUTSIDE://kerberized_kafka1:19092,UNSECURED_OUTSIDE://kerberized_kafka1:19093,UNSECURED_INSIDE://localhost:${KERBERIZED_KAFKA_EXTERNAL_PORT}
|
||||
@ -41,7 +41,7 @@ services:
|
||||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
||||
KAFKA_OPTS: "-Djava.security.auth.login.config=/etc/kafka/secrets/broker_jaas.conf -Djava.security.krb5.conf=/etc/kafka/secrets/krb.conf -Dsun.security.krb5.debug=true"
|
||||
volumes:
|
||||
- ${KERBERIZED_KAFKA_DIR}/secrets:/etc/kafka/secrets
|
||||
- ${KERBERIZED_KAFKA_DIR:-}/secrets:/etc/kafka/secrets
|
||||
- /dev/urandom:/dev/random
|
||||
depends_on:
|
||||
- kafka_kerberized_zookeeper
|
||||
|
@ -4,13 +4,13 @@ services:
|
||||
image: getmeili/meilisearch:v0.27.0
|
||||
restart: always
|
||||
ports:
|
||||
- ${MEILI_EXTERNAL_PORT}:${MEILI_INTERNAL_PORT}
|
||||
- ${MEILI_EXTERNAL_PORT:-7700}:${MEILI_INTERNAL_PORT:-7700}
|
||||
|
||||
meili_secure:
|
||||
image: getmeili/meilisearch:v0.27.0
|
||||
restart: always
|
||||
ports:
|
||||
- ${MEILI_SECURE_EXTERNAL_PORT}:${MEILI_SECURE_INTERNAL_PORT}
|
||||
- ${MEILI_SECURE_EXTERNAL_PORT:-7700}:${MEILI_SECURE_INTERNAL_PORT:-7700}
|
||||
environment:
|
||||
MEILI_MASTER_KEY: "password"
|
||||
|
||||
|
@ -9,7 +9,7 @@ services:
|
||||
- data1-1:/data1
|
||||
- ${MINIO_CERTS_DIR:-}:/certs
|
||||
expose:
|
||||
- ${MINIO_PORT}
|
||||
- ${MINIO_PORT:-9001}
|
||||
environment:
|
||||
MINIO_ACCESS_KEY: minio
|
||||
MINIO_SECRET_KEY: minio123
|
||||
|
@ -7,11 +7,11 @@ services:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: clickhouse
|
||||
ports:
|
||||
- ${MONGO_EXTERNAL_PORT}:${MONGO_INTERNAL_PORT}
|
||||
- ${MONGO_EXTERNAL_PORT:-27017}:${MONGO_INTERNAL_PORT:-27017}
|
||||
command: --profile=2 --verbose
|
||||
|
||||
mongo2:
|
||||
image: mongo:5.0
|
||||
restart: always
|
||||
ports:
|
||||
- ${MONGO_NO_CRED_EXTERNAL_PORT}:${MONGO_NO_CRED_INTERNAL_PORT}
|
||||
- ${MONGO_NO_CRED_EXTERNAL_PORT:-27017}:${MONGO_NO_CRED_INTERNAL_PORT:-27017}
|
||||
|
@ -7,7 +7,7 @@ services:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: clickhouse
|
||||
volumes:
|
||||
- ${MONGO_CONFIG_PATH}:/mongo/
|
||||
- ${MONGO_CONFIG_PATH:-}:/mongo/
|
||||
ports:
|
||||
- ${MONGO_EXTERNAL_PORT}:${MONGO_INTERNAL_PORT}
|
||||
- ${MONGO_EXTERNAL_PORT:-27017}:${MONGO_INTERNAL_PORT:-27017}
|
||||
command: --config /mongo/mongo_secure.conf --profile=2 --verbose
|
||||
|
@ -8,7 +8,7 @@ services:
|
||||
MYSQL_ROOT_HOST: ${MYSQL_ROOT_HOST}
|
||||
DATADIR: /mysql/
|
||||
expose:
|
||||
- ${MYSQL_PORT}
|
||||
- ${MYSQL_PORT:-3306}
|
||||
command: --server_id=100
|
||||
--log-bin='mysql-bin-1.log'
|
||||
--default-time-zone='+3:00'
|
||||
|
@ -1,21 +0,0 @@
|
||||
version: '2.3'
|
||||
services:
|
||||
mysql1:
|
||||
image: mysql:5.7
|
||||
restart: 'no'
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: clickhouse
|
||||
ports:
|
||||
- 3308:3306
|
||||
command: --server_id=100 --log-bin='mysql-bin-1.log'
|
||||
--default-time-zone='+3:00'
|
||||
--gtid-mode="ON"
|
||||
--enforce-gtid-consistency
|
||||
--log-error-verbosity=3
|
||||
--log-error=/var/log/mysqld/error.log
|
||||
--general-log=ON
|
||||
--general-log-file=/var/log/mysqld/general.log
|
||||
volumes:
|
||||
- type: ${MYSQL_LOGS_FS:-tmpfs}
|
||||
source: ${MYSQL_LOGS:-}
|
||||
target: /var/log/mysqld/
|
@ -8,7 +8,7 @@ services:
|
||||
MYSQL_ROOT_HOST: ${MYSQL_ROOT_HOST}
|
||||
DATADIR: /mysql/
|
||||
expose:
|
||||
- ${MYSQL8_PORT}
|
||||
- ${MYSQL8_PORT:-3306}
|
||||
command: --server_id=100 --log-bin='mysql-bin-1.log'
|
||||
--default_authentication_plugin='mysql_native_password'
|
||||
--default-time-zone='+3:00' --gtid-mode="ON"
|
||||
|
@ -8,7 +8,7 @@ services:
|
||||
MYSQL_ROOT_HOST: ${MYSQL_CLUSTER_ROOT_HOST}
|
||||
DATADIR: /mysql/
|
||||
expose:
|
||||
- ${MYSQL_CLUSTER_PORT}
|
||||
- ${MYSQL_CLUSTER_PORT:-3306}
|
||||
command: --server_id=100
|
||||
--log-bin='mysql-bin-2.log'
|
||||
--default-time-zone='+3:00'
|
||||
@ -30,7 +30,7 @@ services:
|
||||
MYSQL_ROOT_HOST: ${MYSQL_CLUSTER_ROOT_HOST}
|
||||
DATADIR: /mysql/
|
||||
expose:
|
||||
- ${MYSQL_CLUSTER_PORT}
|
||||
- ${MYSQL_CLUSTER_PORT:-3306}
|
||||
command: --server_id=100
|
||||
--log-bin='mysql-bin-3.log'
|
||||
--default-time-zone='+3:00'
|
||||
@ -52,7 +52,7 @@ services:
|
||||
MYSQL_ROOT_HOST: ${MYSQL_CLUSTER_ROOT_HOST}
|
||||
DATADIR: /mysql/
|
||||
expose:
|
||||
- ${MYSQL_CLUSTER_PORT}
|
||||
- ${MYSQL_CLUSTER_PORT:-3306}
|
||||
command: --server_id=100
|
||||
--log-bin='mysql-bin-4.log'
|
||||
--default-time-zone='+3:00'
|
||||
|
@ -3,9 +3,9 @@ services:
|
||||
nats1:
|
||||
image: nats
|
||||
ports:
|
||||
- "${NATS_EXTERNAL_PORT}:${NATS_INTERNAL_PORT}"
|
||||
- "${NATS_EXTERNAL_PORT:-4444}:${NATS_INTERNAL_PORT:-4444}"
|
||||
command: "-p 4444 --user click --pass house --tls --tlscert=/etc/certs/server-cert.pem --tlskey=/etc/certs/server-key.pem"
|
||||
volumes:
|
||||
- type: bind
|
||||
source: "${NATS_CERT_DIR}/nats"
|
||||
source: "${NATS_CERT_DIR:-}/nats"
|
||||
target: /etc/certs
|
||||
|
@ -5,7 +5,7 @@ services:
|
||||
command: ["postgres", "-c", "wal_level=logical", "-c", "max_replication_slots=2", "-c", "logging_collector=on", "-c", "log_directory=/postgres/logs", "-c", "log_filename=postgresql.log", "-c", "log_statement=all", "-c", "max_connections=200"]
|
||||
restart: always
|
||||
expose:
|
||||
- ${POSTGRES_PORT}
|
||||
- ${POSTGRES_PORT:-5432}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
|
@ -9,7 +9,7 @@ services:
|
||||
POSTGRES_PASSWORD: mysecretpassword
|
||||
PGDATA: /postgres/data
|
||||
expose:
|
||||
- ${POSTGRES_PORT}
|
||||
- ${POSTGRES_PORT:-5432}
|
||||
volumes:
|
||||
- type: ${POSTGRES_LOGS_FS:-tmpfs}
|
||||
source: ${POSTGRES2_DIR:-}
|
||||
@ -23,7 +23,7 @@ services:
|
||||
POSTGRES_PASSWORD: mysecretpassword
|
||||
PGDATA: /postgres/data
|
||||
expose:
|
||||
- ${POSTGRES_PORT}
|
||||
- ${POSTGRES_PORT:-5432}
|
||||
volumes:
|
||||
- type: ${POSTGRES_LOGS_FS:-tmpfs}
|
||||
source: ${POSTGRES3_DIR:-}
|
||||
@ -37,7 +37,7 @@ services:
|
||||
POSTGRES_PASSWORD: mysecretpassword
|
||||
PGDATA: /postgres/data
|
||||
expose:
|
||||
- ${POSTGRES_PORT}
|
||||
- ${POSTGRES_PORT:-5432}
|
||||
volumes:
|
||||
- type: ${POSTGRES_LOGS_FS:-tmpfs}
|
||||
source: ${POSTGRES4_DIR:-}
|
||||
|
@ -5,7 +5,7 @@ services:
|
||||
image: rabbitmq:3.8-management-alpine
|
||||
hostname: rabbitmq1
|
||||
expose:
|
||||
- ${RABBITMQ_PORT}
|
||||
- ${RABBITMQ_PORT:-5672}
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: "root"
|
||||
RABBITMQ_DEFAULT_PASS: "clickhouse"
|
||||
|
@ -4,5 +4,5 @@ services:
|
||||
image: redis
|
||||
restart: always
|
||||
ports:
|
||||
- ${REDIS_EXTERNAL_PORT}:${REDIS_INTERNAL_PORT}
|
||||
- ${REDIS_EXTERNAL_PORT:-6379}:${REDIS_INTERNAL_PORT:-6379}
|
||||
command: redis-server --requirepass "clickhouse" --databases 32
|
||||
|
@ -202,7 +202,7 @@ Google OSS-Fuzz can be found at `docker/fuzz`.
|
||||
We also use simple fuzz test to generate random SQL queries and to check that the server does not die executing them.
|
||||
You can find it in `00746_sql_fuzzy.pl`. This test should be run continuously (overnight and longer).
|
||||
|
||||
We also use sophisticated AST-based query fuzzer that is able to find huge amount of corner cases. It does random permutations and substitutions in queries AST. It remembers AST nodes from previous tests to use them for fuzzing of subsequent tests while processing them in random order. You can learn more about this fuzzer in [this blog article](https://clickhouse.com/blog/en/2021/fuzzing-clickhouse/).
|
||||
We also use sophisticated AST-based query fuzzer that is able to find huge amount of corner cases. It does random permutations and substitutions in queries AST. It remembers AST nodes from previous tests to use them for fuzzing of subsequent tests while processing them in random order. You can learn more about this fuzzer in [this blog article](https://clickhouse.com/blog/fuzzing-click-house).
|
||||
|
||||
## Stress test
|
||||
|
||||
|
@ -6,6 +6,39 @@ slug: /en/operations/settings/settings
|
||||
|
||||
# Settings
|
||||
|
||||
## additional_table_filters
|
||||
|
||||
An additional filter expression that is applied after reading
|
||||
from the specified table.
|
||||
|
||||
Default value: 0.
|
||||
|
||||
**Example**
|
||||
|
||||
``` sql
|
||||
insert into table_1 values (1, 'a'), (2, 'bb'), (3, 'ccc'), (4, 'dddd');
|
||||
```
|
||||
```response
|
||||
┌─x─┬─y────┐
|
||||
│ 1 │ a │
|
||||
│ 2 │ bb │
|
||||
│ 3 │ ccc │
|
||||
│ 4 │ dddd │
|
||||
└───┴──────┘
|
||||
```
|
||||
```sql
|
||||
SELECT *
|
||||
FROM table_1
|
||||
SETTINGS additional_table_filters = (('table_1', 'x != 2'))
|
||||
```
|
||||
```response
|
||||
┌─x─┬─y────┐
|
||||
│ 1 │ a │
|
||||
│ 3 │ ccc │
|
||||
│ 4 │ dddd │
|
||||
└───┴──────┘
|
||||
```
|
||||
|
||||
## allow_nondeterministic_mutations {#allow_nondeterministic_mutations}
|
||||
|
||||
User-level setting that allows mutations on replicated tables to make use of non-deterministic functions such as `dictGet`.
|
||||
|
@ -11,6 +11,7 @@ Columns:
|
||||
- `table` ([String](../../sql-reference/data-types/string.md)) — Table name.
|
||||
- `name` ([String](../../sql-reference/data-types/string.md)) — Index name.
|
||||
- `type` ([String](../../sql-reference/data-types/string.md)) — Index type.
|
||||
- `type_full` ([String](../../sql-reference/data-types/string.md)) — Index type expression from create statement.
|
||||
- `expr` ([String](../../sql-reference/data-types/string.md)) — Expression for the index calculation.
|
||||
- `granularity` ([UInt64](../../sql-reference/data-types/int-uint.md)) — The number of granules in the block.
|
||||
- `data_compressed_bytes` ([UInt64](../../sql-reference/data-types/int-uint.md)) — The size of compressed data, in bytes.
|
||||
@ -30,6 +31,7 @@ database: default
|
||||
table: user_actions
|
||||
name: clicks_idx
|
||||
type: minmax
|
||||
type_full: minmax
|
||||
expr: clicks
|
||||
granularity: 1
|
||||
data_compressed_bytes: 58
|
||||
@ -42,6 +44,7 @@ database: default
|
||||
table: users
|
||||
name: contacts_null_idx
|
||||
type: minmax
|
||||
type_full: minmax
|
||||
expr: assumeNotNull(contacts_null)
|
||||
granularity: 1
|
||||
data_compressed_bytes: 58
|
||||
|
@ -65,10 +65,27 @@ An exception is thrown when dividing by zero or when dividing a minimal negative
|
||||
|
||||
Differs from [modulo](#modulo) in that it returns zero when the divisor is zero.
|
||||
|
||||
## positive_modulo(a, b)
|
||||
Calculates the remainder when dividing `a` by `b`. Similar to function `modulo` except that `positive_modulo` always return non-negative number.
|
||||
## positiveModulo(a, b), positive_modulo(a, b), pmod(a, b)
|
||||
Calculates the remainder when dividing `a` by `b`. Similar to the function `modulo` except that `positive_modulo` always returns a non-negative number.
|
||||
|
||||
Notice that `positive_modulo` is 4-5 times slower than `modulo`. You should not use `positive_modulo` unless you want to get positive result and don't care about performance too much.
|
||||
Notice that `positive_modulo` is 4-5 times slower than `modulo`. You should not use `positive_modulo` unless you want to get a positive result and don't care about performance too much.
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
```sql
|
||||
SELECT positiveModulo(-1, 10)
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
|
||||
┌─positiveModulo(-1, 10)─┐
|
||||
│ 9 │
|
||||
└────────────────────────┘
|
||||
```
|
||||
|
||||
## negate(a), -a operator
|
||||
|
||||
|
@ -302,16 +302,23 @@ Returns the date.
|
||||
The behavior of parsing incorrect dates is implementation specific. ClickHouse may return zero date, throw an exception or do “natural” overflow.
|
||||
:::
|
||||
|
||||
## toLastDayOfMonth
|
||||
|
||||
Rounds a date, or date with time, to the last day of the month.
|
||||
Returns the date.
|
||||
|
||||
Alias: `LAST_DAY`.
|
||||
|
||||
If `toLastDayOfMonth` is called with an argument of type `Date` greater then 2149-05-31, the result will be calculated from the argument 2149-05-31 instead.
|
||||
|
||||
## toMonday
|
||||
|
||||
Rounds down a date or date with time to the nearest Monday.
|
||||
Rounds down a date, or date with time, to the nearest Monday.
|
||||
Returns the date.
|
||||
|
||||
## toStartOfWeek(t\[,mode\])
|
||||
|
||||
Rounds down a date or date with time to the nearest Sunday or Monday by mode.
|
||||
Rounds down a date, or date with time, to the nearest Sunday or Monday by mode.
|
||||
Returns the date.
|
||||
The mode argument works exactly like the mode argument to toWeek(). For the single-argument syntax, a mode value of 0 is used.
|
||||
|
||||
@ -410,43 +417,43 @@ Converts a date with time to a certain fixed date, while preserving the time.
|
||||
|
||||
## toRelativeYearNum
|
||||
|
||||
Converts a date or date with time to the number of the year, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the year, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeQuarterNum
|
||||
|
||||
Converts a date or date with time to the number of the quarter, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the quarter, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeMonthNum
|
||||
|
||||
Converts a date or date with time to the number of the month, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the month, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeWeekNum
|
||||
|
||||
Converts a date or date with time to the number of the week, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the week, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeDayNum
|
||||
|
||||
Converts a date or date with time to the number of the day, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the day, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeHourNum
|
||||
|
||||
Converts a date or date with time to the number of the hour, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the hour, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeMinuteNum
|
||||
|
||||
Converts a date or date with time to the number of the minute, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the minute, starting from a certain fixed point in the past.
|
||||
|
||||
## toRelativeSecondNum
|
||||
|
||||
Converts a date or date with time to the number of the second, starting from a certain fixed point in the past.
|
||||
Converts a date, or date with time, to the number of the second, starting from a certain fixed point in the past.
|
||||
|
||||
## toISOYear
|
||||
|
||||
Converts a date or date with time to a UInt16 number containing the ISO Year number.
|
||||
Converts a date, or date with time, to a UInt16 number containing the ISO Year number.
|
||||
|
||||
## toISOWeek
|
||||
|
||||
Converts a date or date with time to a UInt8 number containing the ISO Week number.
|
||||
Converts a date, or date with time, to a UInt8 number containing the ISO Week number.
|
||||
|
||||
## toWeek(date\[,mode\])
|
||||
|
||||
|
@ -351,14 +351,16 @@ In all `multiSearch*` functions the number of needles should be less than 2<sup>
|
||||
|
||||
## match(haystack, pattern)
|
||||
|
||||
Checks whether the string matches the regular expression `pattern` in `re2` syntax. `Re2` has a more limited [syntax](https://github.com/google/re2/wiki/Syntax) than Perl regular expressions.
|
||||
Checks whether string `haystack` matches the regular expression `pattern`. The pattern is an [re2 regular expression](https://github.com/google/re2/wiki/Syntax) which has a more limited syntax than Perl regular expressions.
|
||||
|
||||
Returns 0 if it does not match, or 1 if it matches.
|
||||
Returns 1 in case of a match, and 0 otherwise.
|
||||
|
||||
Matching is based on UTF-8, e.g. `.` matches the Unicode code point `¥` which is represented in UTF-8 using two bytes. The regular expression must not contain null bytes.
|
||||
If the haystack or pattern contain a sequence of bytes that are not valid UTF-8, then the behavior is undefined.
|
||||
If the haystack or pattern contain a sequence of bytes that are not valid UTF-8, the behavior is undefined.
|
||||
No automatic Unicode normalization is performed, if you need it you can use the [normalizeUTF8*()](https://clickhouse.com/docs/en/sql-reference/functions/string-functions/) functions for that.
|
||||
|
||||
Unlike re2's default behavior, `.` matches line breaks. To disable this, prepend the pattern with `(?-s)`.
|
||||
|
||||
For patterns to search for substrings in a string, it is better to use LIKE or ‘position’, since they work much faster.
|
||||
|
||||
## multiMatchAny(haystack, \[pattern<sub>1</sub>, pattern<sub>2</sub>, …, pattern<sub>n</sub>\])
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <AggregateFunctions/registerAggregateFunctions.h>
|
||||
#include <TableFunctions/registerTableFunctions.h>
|
||||
#include <Storages/registerStorages.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Dictionaries/registerDictionaries.h>
|
||||
#include <Disks/registerDisks.h>
|
||||
#include <Formats/registerFormats.h>
|
||||
|
@ -60,7 +60,7 @@
|
||||
#include <Storages/System/attachInformationSchemaTables.h>
|
||||
#include <Storages/Cache/ExternalDataSourceCache.h>
|
||||
#include <Storages/Cache/registerRemoteFileMetadatas.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <AggregateFunctions/registerAggregateFunctions.h>
|
||||
#include <Functions/UserDefined/IUserDefinedSQLObjectsLoader.h>
|
||||
#include <Functions/registerFunctions.h>
|
||||
|
@ -116,13 +116,9 @@ public:
|
||||
|
||||
static DataTypePtr getKeyType(const DataTypes & types, const AggregateFunctionPtr & nested)
|
||||
{
|
||||
if (types.empty())
|
||||
if (types.size() != 1)
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"Aggregate function {}Map requires at least one argument", nested->getName());
|
||||
|
||||
if (types.size() > 1)
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"Aggregate function {}Map requires only one map argument", nested->getName());
|
||||
"Aggregate function {}Map requires one map argument, but {} found", nested->getName(), types.size());
|
||||
|
||||
const auto * map_type = checkAndGetDataType<DataTypeMap>(types[0].get());
|
||||
if (!map_type)
|
||||
|
@ -36,8 +36,8 @@ public:
|
||||
AggregateFunctionOrFill(AggregateFunctionPtr nested_function_, const DataTypes & arguments, const Array & params)
|
||||
: IAggregateFunctionHelper<AggregateFunctionOrFill>{arguments, params, createResultType(nested_function_->getResultType())}
|
||||
, nested_function{nested_function_}
|
||||
, size_of_data {nested_function->sizeOfData()}
|
||||
, inner_nullable {nested_function->getResultType()->isNullable()}
|
||||
, size_of_data{nested_function->sizeOfData()}
|
||||
, inner_nullable{nested_function->getResultType()->isNullable()}
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
@ -428,10 +428,7 @@ public:
|
||||
}
|
||||
|
||||
bool keepKey(const T & key) const { return static_cast<const Derived &>(*this).keepKey(key); }
|
||||
String getName() const override { return getNameImpl(); }
|
||||
|
||||
private:
|
||||
static String getNameImpl() { return Derived::getNameImpl(); }
|
||||
String getName() const override { return Derived::getNameImpl(); }
|
||||
};
|
||||
|
||||
template <typename T, bool overflow, bool tuple_argument>
|
||||
|
@ -65,9 +65,9 @@ class IAggregateFunction : public std::enable_shared_from_this<IAggregateFunctio
|
||||
{
|
||||
public:
|
||||
IAggregateFunction(const DataTypes & argument_types_, const Array & parameters_, const DataTypePtr & result_type_)
|
||||
: result_type(result_type_)
|
||||
, argument_types(argument_types_)
|
||||
: argument_types(argument_types_)
|
||||
, parameters(parameters_)
|
||||
, result_type(result_type_)
|
||||
{}
|
||||
|
||||
/// Get main function name.
|
||||
@ -409,9 +409,9 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
DataTypePtr result_type;
|
||||
DataTypes argument_types;
|
||||
Array parameters;
|
||||
DataTypePtr result_type;
|
||||
};
|
||||
|
||||
|
||||
|
@ -31,18 +31,21 @@ FunctionNode::FunctionNode(String function_name_)
|
||||
children[arguments_child_index] = std::make_shared<ListNode>();
|
||||
}
|
||||
|
||||
ColumnsWithTypeAndName FunctionNode::getArgumentTypes() const
|
||||
ColumnsWithTypeAndName FunctionNode::getArgumentColumns() const
|
||||
{
|
||||
ColumnsWithTypeAndName argument_types;
|
||||
for (const auto & arg : getArguments().getNodes())
|
||||
const auto & arguments = getArguments().getNodes();
|
||||
ColumnsWithTypeAndName argument_columns;
|
||||
argument_columns.reserve(arguments.size());
|
||||
|
||||
for (const auto & arg : arguments)
|
||||
{
|
||||
ColumnWithTypeAndName argument;
|
||||
argument.type = arg->getResultType();
|
||||
if (auto * constant = arg->as<ConstantNode>())
|
||||
argument.column = argument.type->createColumnConst(1, constant->getValue());
|
||||
argument_types.push_back(argument);
|
||||
argument_columns.push_back(std::move(argument));
|
||||
}
|
||||
return argument_types;
|
||||
return argument_columns;
|
||||
}
|
||||
|
||||
void FunctionNode::resolveAsFunction(FunctionBasePtr function_value)
|
||||
|
@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <Core/IResolvedFunction.h>
|
||||
#include <AggregateFunctions/IAggregateFunction.h>
|
||||
#include <Analyzer/ConstantValue.h>
|
||||
#include <Analyzer/IQueryTreeNode.h>
|
||||
#include <Analyzer/ListNode.h>
|
||||
#include <Analyzer/ConstantValue.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Core/ColumnsWithTypeAndName.h>
|
||||
#include <Core/IResolvedFunction.h>
|
||||
#include <Functions/IFunction.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -19,12 +21,6 @@ namespace ErrorCodes
|
||||
class IFunctionOverloadResolver;
|
||||
using FunctionOverloadResolverPtr = std::shared_ptr<IFunctionOverloadResolver>;
|
||||
|
||||
class IFunctionBase;
|
||||
using FunctionBasePtr = std::shared_ptr<const IFunctionBase>;
|
||||
|
||||
class IAggregateFunction;
|
||||
using AggregateFunctionPtr = std::shared_ptr<const IAggregateFunction>;
|
||||
|
||||
/** Function node represents function in query tree.
|
||||
* Function syntax: function_name(parameter_1, ...)(argument_1, ...).
|
||||
* If function does not have parameters its syntax is function_name(argument_1, ...).
|
||||
@ -63,66 +59,36 @@ public:
|
||||
explicit FunctionNode(String function_name_);
|
||||
|
||||
/// Get function name
|
||||
const String & getFunctionName() const
|
||||
{
|
||||
return function_name;
|
||||
}
|
||||
const String & getFunctionName() const { return function_name; }
|
||||
|
||||
/// Get parameters
|
||||
const ListNode & getParameters() const
|
||||
{
|
||||
return children[parameters_child_index]->as<const ListNode &>();
|
||||
}
|
||||
const ListNode & getParameters() const { return children[parameters_child_index]->as<const ListNode &>(); }
|
||||
|
||||
/// Get parameters
|
||||
ListNode & getParameters()
|
||||
{
|
||||
return children[parameters_child_index]->as<ListNode &>();
|
||||
}
|
||||
ListNode & getParameters() { return children[parameters_child_index]->as<ListNode &>(); }
|
||||
|
||||
/// Get parameters node
|
||||
const QueryTreeNodePtr & getParametersNode() const
|
||||
{
|
||||
return children[parameters_child_index];
|
||||
}
|
||||
const QueryTreeNodePtr & getParametersNode() const { return children[parameters_child_index]; }
|
||||
|
||||
/// Get parameters node
|
||||
QueryTreeNodePtr & getParametersNode()
|
||||
{
|
||||
return children[parameters_child_index];
|
||||
}
|
||||
QueryTreeNodePtr & getParametersNode() { return children[parameters_child_index]; }
|
||||
|
||||
/// Get arguments
|
||||
const ListNode & getArguments() const
|
||||
{
|
||||
return children[arguments_child_index]->as<const ListNode &>();
|
||||
}
|
||||
const ListNode & getArguments() const { return children[arguments_child_index]->as<const ListNode &>(); }
|
||||
|
||||
/// Get arguments
|
||||
ListNode & getArguments()
|
||||
{
|
||||
return children[arguments_child_index]->as<ListNode &>();
|
||||
}
|
||||
ListNode & getArguments() { return children[arguments_child_index]->as<ListNode &>(); }
|
||||
|
||||
/// Get arguments node
|
||||
const QueryTreeNodePtr & getArgumentsNode() const
|
||||
{
|
||||
return children[arguments_child_index];
|
||||
}
|
||||
const QueryTreeNodePtr & getArgumentsNode() const { return children[arguments_child_index]; }
|
||||
|
||||
/// Get arguments node
|
||||
QueryTreeNodePtr & getArgumentsNode()
|
||||
{
|
||||
return children[arguments_child_index];
|
||||
}
|
||||
QueryTreeNodePtr & getArgumentsNode() { return children[arguments_child_index]; }
|
||||
|
||||
ColumnsWithTypeAndName getArgumentTypes() const;
|
||||
ColumnsWithTypeAndName getArgumentColumns() const;
|
||||
|
||||
/// Returns true if function node has window, false otherwise
|
||||
bool hasWindow() const
|
||||
{
|
||||
return children[window_child_index] != nullptr;
|
||||
}
|
||||
bool hasWindow() const { return children[window_child_index] != nullptr; }
|
||||
|
||||
/** Get window node.
|
||||
* Valid only for window function node.
|
||||
@ -130,18 +96,12 @@ public:
|
||||
* 1. It can be identifier node if window function is defined as expr OVER window_name.
|
||||
* 2. It can be window node if window function is defined as expr OVER (window_name ...).
|
||||
*/
|
||||
const QueryTreeNodePtr & getWindowNode() const
|
||||
{
|
||||
return children[window_child_index];
|
||||
}
|
||||
const QueryTreeNodePtr & getWindowNode() const { return children[window_child_index]; }
|
||||
|
||||
/** Get window node.
|
||||
* Valid only for window function node.
|
||||
*/
|
||||
QueryTreeNodePtr & getWindowNode()
|
||||
{
|
||||
return children[window_child_index];
|
||||
}
|
||||
QueryTreeNodePtr & getWindowNode() { return children[window_child_index]; }
|
||||
|
||||
/** Get non aggregate function.
|
||||
* If function is not resolved nullptr returned.
|
||||
@ -150,7 +110,7 @@ public:
|
||||
{
|
||||
if (kind != FunctionKind::ORDINARY)
|
||||
return {};
|
||||
return std::reinterpret_pointer_cast<const IFunctionBase>(function);
|
||||
return std::static_pointer_cast<const IFunctionBase>(function);
|
||||
}
|
||||
|
||||
/** Get aggregate function.
|
||||
@ -161,32 +121,20 @@ public:
|
||||
{
|
||||
if (kind == FunctionKind::UNKNOWN || kind == FunctionKind::ORDINARY)
|
||||
return {};
|
||||
return std::reinterpret_pointer_cast<const IAggregateFunction>(function);
|
||||
return std::static_pointer_cast<const IAggregateFunction>(function);
|
||||
}
|
||||
|
||||
/// Is function node resolved
|
||||
bool isResolved() const
|
||||
{
|
||||
return function != nullptr;
|
||||
}
|
||||
bool isResolved() const { return function != nullptr; }
|
||||
|
||||
/// Is function node window function
|
||||
bool isWindowFunction() const
|
||||
{
|
||||
return hasWindow();
|
||||
}
|
||||
bool isWindowFunction() const { return hasWindow(); }
|
||||
|
||||
/// Is function node aggregate function
|
||||
bool isAggregateFunction() const
|
||||
{
|
||||
return kind == FunctionKind::AGGREGATE;
|
||||
}
|
||||
bool isAggregateFunction() const { return kind == FunctionKind::AGGREGATE; }
|
||||
|
||||
/// Is function node ordinary function
|
||||
bool isOrdinaryFunction() const
|
||||
{
|
||||
return kind == FunctionKind::ORDINARY;
|
||||
}
|
||||
bool isOrdinaryFunction() const { return kind == FunctionKind::ORDINARY; }
|
||||
|
||||
/** Resolve function node as non aggregate function.
|
||||
* It is important that function name is updated with resolved function name.
|
||||
@ -208,10 +156,7 @@ public:
|
||||
*/
|
||||
void resolveAsWindowFunction(AggregateFunctionPtr window_function_value);
|
||||
|
||||
QueryTreeNodeType getNodeType() const override
|
||||
{
|
||||
return QueryTreeNodeType::FUNCTION;
|
||||
}
|
||||
QueryTreeNodeType getNodeType() const override { return QueryTreeNodeType::FUNCTION; }
|
||||
|
||||
DataTypePtr getResultType() const override
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ public:
|
||||
inline void resolveOrdinaryFunctionNode(FunctionNode & function_node, const String & function_name) const
|
||||
{
|
||||
auto function = FunctionFactory::instance().get(function_name, context);
|
||||
function_node.resolveAsFunction(function->build(function_node.getArgumentTypes()));
|
||||
function_node.resolveAsFunction(function->build(function_node.getArgumentColumns()));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -193,7 +193,7 @@ private:
|
||||
inline void resolveOrdinaryFunctionNode(FunctionNode & function_node, const String & function_name) const
|
||||
{
|
||||
auto function = FunctionFactory::instance().get(function_name, context);
|
||||
function_node.resolveAsFunction(function->build(function_node.getArgumentTypes()));
|
||||
function_node.resolveAsFunction(function->build(function_node.getArgumentColumns()));
|
||||
}
|
||||
|
||||
ContextPtr & context;
|
||||
|
@ -65,7 +65,7 @@ QueryTreeNodePtr createResolvedFunction(const ContextPtr & context, const String
|
||||
|
||||
auto function = FunctionFactory::instance().get(name, context);
|
||||
function_node->getArguments().getNodes() = std::move(arguments);
|
||||
function_node->resolveAsFunction(function->build(function_node->getArgumentTypes()));
|
||||
function_node->resolveAsFunction(function->build(function_node->getArgumentColumns()));
|
||||
return function_node;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ FunctionNodePtr createResolvedAggregateFunction(const String & name, const Query
|
||||
{ argument->getResultType() },
|
||||
parameters,
|
||||
properties);
|
||||
function_node->resolveAsAggregateFunction(aggregate_function);
|
||||
function_node->resolveAsAggregateFunction(std::move(aggregate_function));
|
||||
|
||||
return function_node;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
|
||||
auto multi_if_function = std::make_shared<FunctionNode>("multiIf");
|
||||
multi_if_function->getArguments().getNodes() = std::move(multi_if_arguments);
|
||||
multi_if_function->resolveAsFunction(multi_if_function_ptr->build(multi_if_function->getArgumentTypes()));
|
||||
multi_if_function->resolveAsFunction(multi_if_function_ptr->build(multi_if_function->getArgumentColumns()));
|
||||
node = std::move(multi_if_function);
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ QueryTreeNodePtr createCastFunction(QueryTreeNodePtr from, DataTypePtr result_ty
|
||||
auto function_node = std::make_shared<FunctionNode>("_CAST");
|
||||
function_node->getArguments().getNodes() = std::move(arguments);
|
||||
|
||||
function_node->resolveAsFunction(cast_function->build(function_node->getArgumentTypes()));
|
||||
function_node->resolveAsFunction(cast_function->build(function_node->getArgumentColumns()));
|
||||
|
||||
return function_node;
|
||||
}
|
||||
@ -71,7 +71,7 @@ void changeIfArguments(
|
||||
|
||||
auto if_resolver = FunctionFactory::instance().get("if", context);
|
||||
|
||||
if_node.resolveAsFunction(if_resolver->build(if_node.getArgumentTypes()));
|
||||
if_node.resolveAsFunction(if_resolver->build(if_node.getArgumentColumns()));
|
||||
}
|
||||
|
||||
/// transform(value, array_from, array_to, default_value) will be transformed to transform(value, array_from, _CAST(array_to, Array(Enum...)), _CAST(default_value, Enum...))
|
||||
@ -93,7 +93,7 @@ void changeTransformArguments(
|
||||
|
||||
auto transform_resolver = FunctionFactory::instance().get("transform", context);
|
||||
|
||||
transform_node.resolveAsFunction(transform_resolver->build(transform_node.getArgumentTypes()));
|
||||
transform_node.resolveAsFunction(transform_resolver->build(transform_node.getArgumentColumns()));
|
||||
}
|
||||
|
||||
void wrapIntoToString(FunctionNode & function_node, QueryTreeNodePtr arg, ContextPtr context)
|
||||
@ -102,7 +102,7 @@ void wrapIntoToString(FunctionNode & function_node, QueryTreeNodePtr arg, Contex
|
||||
QueryTreeNodes arguments{ std::move(arg) };
|
||||
function_node.getArguments().getNodes() = std::move(arguments);
|
||||
|
||||
function_node.resolveAsFunction(to_string_function->build(function_node.getArgumentTypes()));
|
||||
function_node.resolveAsFunction(to_string_function->build(function_node.getArgumentColumns()));
|
||||
|
||||
assert(isString(function_node.getResultType()));
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
return;
|
||||
|
||||
auto result_type = function_node->getResultType();
|
||||
function_node->resolveAsFunction(if_function_ptr->build(function_node->getArgumentTypes()));
|
||||
function_node->resolveAsFunction(if_function_ptr->build(function_node->getArgumentColumns()));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -4333,7 +4333,7 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
|
||||
? AggregateFunctionFactory::instance().get(function_name + "OrNull", argument_types, parameters, properties)
|
||||
: AggregateFunctionFactory::instance().get(function_name, argument_types, parameters, properties);
|
||||
|
||||
function_node.resolveAsWindowFunction(aggregate_function);
|
||||
function_node.resolveAsWindowFunction(std::move(aggregate_function));
|
||||
|
||||
bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER;
|
||||
ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope);
|
||||
@ -4396,7 +4396,7 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
|
||||
auto aggregate_function = need_add_or_null
|
||||
? AggregateFunctionFactory::instance().get(function_name + "OrNull", argument_types, parameters, properties)
|
||||
: AggregateFunctionFactory::instance().get(function_name, argument_types, parameters, properties);
|
||||
function_node.resolveAsAggregateFunction(aggregate_function);
|
||||
function_node.resolveAsAggregateFunction(std::move(aggregate_function));
|
||||
return result_projection_names;
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
auto & not_function_arguments = not_function->getArguments().getNodes();
|
||||
not_function_arguments.push_back(std::move(nested_if_function_arguments_nodes[0]));
|
||||
|
||||
not_function->resolveAsFunction(FunctionFactory::instance().get("not", context)->build(not_function->getArgumentTypes()));
|
||||
not_function->resolveAsFunction(FunctionFactory::instance().get("not", context)->build(not_function->getArgumentColumns()));
|
||||
|
||||
function_node_arguments_nodes[0] = std::move(not_function);
|
||||
function_node_arguments_nodes.resize(1);
|
||||
|
@ -75,7 +75,6 @@ public:
|
||||
function_node->getAggregateFunction()->getParameters(),
|
||||
properties);
|
||||
|
||||
auto function_result_type = function_node->getResultType();
|
||||
function_node->resolveAsAggregateFunction(std::move(aggregate_function));
|
||||
}
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ class ValidationChecker : public InDepthQueryTreeVisitor<ValidationChecker>
|
||||
if (!function->isResolved())
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||
"Function {} is not resolved after running {} pass",
|
||||
function->dumpTree(), pass_name);
|
||||
function->toAST()->formatForErrorMessage(), pass_name);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <IO/IOThreadPool.h>
|
||||
#include <IO/ReadBufferFromS3.h>
|
||||
#include <IO/WriteBufferFromS3.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/s3/S3Client.h>
|
||||
@ -35,7 +36,7 @@ namespace
|
||||
auto settings = context->getStorageS3Settings().getSettings(s3_uri.uri.toString());
|
||||
|
||||
Aws::Auth::AWSCredentials credentials(access_key_id, secret_access_key);
|
||||
HeaderCollection headers;
|
||||
HTTPHeaderEntries headers;
|
||||
if (access_key_id.empty())
|
||||
{
|
||||
credentials = Aws::Auth::AWSCredentials(settings.auth_settings.access_key_id, settings.auth_settings.secret_access_key);
|
||||
|
@ -263,7 +263,7 @@ QueryPipeline ExternalDictionaryLibraryBridgeHelper::loadBase(const Poco::URI &
|
||||
0,
|
||||
DBMS_DEFAULT_BUFFER_SIZE,
|
||||
getContext()->getReadSettings(),
|
||||
ReadWriteBufferFromHTTP::HTTPHeaderEntries{});
|
||||
HTTPHeaderEntries{});
|
||||
|
||||
auto source = FormatFactory::instance().getInput(ExternalDictionaryLibraryBridgeHelper::DEFAULT_FORMAT, *read_buf_ptr, sample_block, getContext(), DEFAULT_BLOCK_SIZE);
|
||||
source->addBuffer(std::move(read_buf_ptr));
|
||||
|
@ -103,7 +103,7 @@ if (TARGET ch_contrib::nats_io)
|
||||
endif()
|
||||
|
||||
add_headers_and_sources(dbms Storages/MeiliSearch)
|
||||
add_headers_and_sources(dbms Storages/NamedCollections)
|
||||
add_headers_and_sources(dbms Common/NamedCollections)
|
||||
|
||||
if (TARGET ch_contrib::amqp_cpp)
|
||||
add_headers_and_sources(dbms Storages/RabbitMQ)
|
||||
@ -360,6 +360,10 @@ if (TARGET ch_contrib::cpuid)
|
||||
target_link_libraries(clickhouse_common_io PRIVATE ch_contrib::cpuid)
|
||||
endif()
|
||||
|
||||
if (TARGET ch_contrib::crc32_s390x)
|
||||
target_link_libraries(clickhouse_common_io PUBLIC ch_contrib::crc32_s390x)
|
||||
endif()
|
||||
|
||||
dbms_target_link_libraries(PUBLIC ch_contrib::abseil_swiss_tables)
|
||||
target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::abseil_swiss_tables)
|
||||
|
||||
|
@ -213,18 +213,18 @@ void AsynchronousMetrics::openSensorsChips()
|
||||
if (!file)
|
||||
continue;
|
||||
|
||||
String sensor_name;
|
||||
if (sensor_name_file_exists)
|
||||
{
|
||||
ReadBufferFromFilePRead sensor_name_in(sensor_name_file, small_buffer_size);
|
||||
readText(sensor_name, sensor_name_in);
|
||||
std::replace(sensor_name.begin(), sensor_name.end(), ' ', '_');
|
||||
}
|
||||
|
||||
file->rewind();
|
||||
Int64 temperature = 0;
|
||||
String sensor_name{};
|
||||
try
|
||||
{
|
||||
if (sensor_name_file_exists)
|
||||
{
|
||||
ReadBufferFromFilePRead sensor_name_in(sensor_name_file, small_buffer_size);
|
||||
readText(sensor_name, sensor_name_in);
|
||||
std::replace(sensor_name.begin(), sensor_name.end(), ' ', '_');
|
||||
}
|
||||
|
||||
file->rewind();
|
||||
Int64 temperature = 0;
|
||||
readText(temperature, *file);
|
||||
}
|
||||
catch (const ErrnoException & e)
|
||||
@ -233,7 +233,7 @@ void AsynchronousMetrics::openSensorsChips()
|
||||
&Poco::Logger::get("AsynchronousMetrics"),
|
||||
"Hardware monitor '{}', sensor '{}' exists but could not be read: {}.",
|
||||
hwmon_name,
|
||||
sensor_name,
|
||||
sensor_index,
|
||||
errnoToString(e.getErrno()));
|
||||
continue;
|
||||
}
|
||||
|
@ -48,6 +48,36 @@ inline DB::UInt64 intHash64(DB::UInt64 x)
|
||||
#include <arm_acle.h>
|
||||
#endif
|
||||
|
||||
#if defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
#include <crc32-s390x.h>
|
||||
|
||||
inline uint32_t s390x_crc32_u8(uint32_t crc, uint8_t v)
|
||||
{
|
||||
return crc32_be(crc, reinterpret_cast<unsigned char *>(&v), sizeof(v));
|
||||
}
|
||||
|
||||
inline uint32_t s390x_crc32_u16(uint32_t crc, uint16_t v)
|
||||
{
|
||||
return crc32_be(crc, reinterpret_cast<unsigned char *>(&v), sizeof(v));
|
||||
}
|
||||
|
||||
inline uint32_t s390x_crc32_u32(uint32_t crc, uint32_t v)
|
||||
{
|
||||
return crc32_be(crc, reinterpret_cast<unsigned char *>(&v), sizeof(v));
|
||||
}
|
||||
|
||||
inline uint64_t s390x_crc32(uint64_t crc, uint64_t v)
|
||||
{
|
||||
uint64_t _crc = crc;
|
||||
uint32_t value_h, value_l;
|
||||
value_h = (v >> 32) & 0xffffffff;
|
||||
value_l = v & 0xffffffff;
|
||||
_crc = crc32_be(static_cast<uint32_t>(_crc), reinterpret_cast<unsigned char *>(&value_h), sizeof(uint32_t));
|
||||
_crc = crc32_be(static_cast<uint32_t>(_crc), reinterpret_cast<unsigned char *>(&value_l), sizeof(uint32_t));
|
||||
return _crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// NOTE: Intel intrinsic can be confusing.
|
||||
/// - https://code.google.com/archive/p/sse-intrinsics/wikis/PmovIntrinsicBug.wiki
|
||||
/// - https://stackoverflow.com/questions/15752770/mm-crc32-u64-poorly-defined
|
||||
@ -57,6 +87,8 @@ inline DB::UInt64 intHashCRC32(DB::UInt64 x)
|
||||
return _mm_crc32_u64(-1ULL, x);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cd(-1U, x);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32(-1U, x)
|
||||
#else
|
||||
/// On other platforms we do not have CRC32. NOTE This can be confusing.
|
||||
/// NOTE: consider using intHash32()
|
||||
@ -69,6 +101,8 @@ inline DB::UInt64 intHashCRC32(DB::UInt64 x, DB::UInt64 updated_value)
|
||||
return _mm_crc32_u64(updated_value, x);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cd(static_cast<UInt32>(updated_value), x);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32(updated_value, x);
|
||||
#else
|
||||
/// On other platforms we do not have CRC32. NOTE This can be confusing.
|
||||
return intHash64(x) ^ updated_value;
|
||||
@ -120,25 +154,53 @@ inline UInt32 updateWeakHash32(const DB::UInt8 * pos, size_t size, DB::UInt32 up
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 1);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 1);
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 2);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 2);
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 3);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 3);
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 4);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 4);
|
||||
#endif
|
||||
break;
|
||||
case 5:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 5);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 5);
|
||||
#endif
|
||||
break;
|
||||
case 6:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 6);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 6);
|
||||
#endif
|
||||
break;
|
||||
case 7:
|
||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
__builtin_memcpy(&value, pos, 7);
|
||||
#else
|
||||
reverseMemcpy(&value, pos, 7);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -151,7 +213,7 @@ inline UInt32 updateWeakHash32(const DB::UInt8 * pos, size_t size, DB::UInt32 up
|
||||
const auto * end = pos + size;
|
||||
while (pos + 8 <= end)
|
||||
{
|
||||
auto word = unalignedLoad<UInt64>(pos);
|
||||
auto word = unalignedLoadLE<UInt64>(pos);
|
||||
updated_value = static_cast<UInt32>(intHashCRC32(word, updated_value));
|
||||
|
||||
pos += 8;
|
||||
@ -163,7 +225,7 @@ inline UInt32 updateWeakHash32(const DB::UInt8 * pos, size_t size, DB::UInt32 up
|
||||
/// Lets' assume the string was 'abcdefghXYZ', so it's tail is 'XYZ'.
|
||||
DB::UInt8 tail_size = end - pos;
|
||||
/// Load tailing 8 bytes. Word is 'defghXYZ'.
|
||||
auto word = unalignedLoad<UInt64>(end - 8);
|
||||
auto word = unalignedLoadLE<UInt64>(end - 8);
|
||||
/// Prepare mask which will set other 5 bytes to 0. It is 0xFFFFFFFFFFFFFFFF << 5 = 0xFFFFFF0000000000.
|
||||
/// word & mask = '\0\0\0\0\0XYZ' (bytes are reversed because of little ending)
|
||||
word &= (~UInt64(0)) << DB::UInt8(8 * (8 - tail_size));
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <Storages/NamedCollections/NamedCollectionConfiguration.h>
|
||||
#include <Common/NamedCollections/NamedCollectionConfiguration.h>
|
||||
#include <Poco/Util/XMLConfiguration.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/SettingsChanges.h>
|
||||
@ -16,6 +16,13 @@ namespace ErrorCodes
|
||||
namespace NamedCollectionConfiguration
|
||||
{
|
||||
|
||||
bool hasConfigValue(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
const std::string & path)
|
||||
{
|
||||
return config.has(path);
|
||||
}
|
||||
|
||||
template <typename T> T getConfigValue(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
const std::string & path)
|
||||
@ -145,6 +152,52 @@ ConfigurationPtr createConfiguration(const std::string & root_name, const Settin
|
||||
return config;
|
||||
}
|
||||
|
||||
void listKeys(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
std::queue<std::string> enumerate_paths,
|
||||
std::set<std::string, std::less<>> & result,
|
||||
ssize_t depth)
|
||||
{
|
||||
if (enumerate_paths.empty())
|
||||
enumerate_paths.push("");
|
||||
|
||||
const bool do_finish = depth >= 0 && --depth < 0;
|
||||
|
||||
auto initial_paths = std::move(enumerate_paths);
|
||||
enumerate_paths = {};
|
||||
while (!initial_paths.empty())
|
||||
{
|
||||
auto path = initial_paths.front();
|
||||
initial_paths.pop();
|
||||
|
||||
Poco::Util::AbstractConfiguration::Keys keys;
|
||||
if (path.empty())
|
||||
config.keys(keys);
|
||||
else
|
||||
config.keys(path, keys);
|
||||
|
||||
if (keys.empty())
|
||||
{
|
||||
result.insert(path);
|
||||
}
|
||||
else if (do_finish)
|
||||
{
|
||||
for (const auto & key : keys)
|
||||
result.emplace(path.empty() ? key : path + '.' + key);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto & key : keys)
|
||||
enumerate_paths.emplace(path.empty() ? key : path + '.' + key);
|
||||
}
|
||||
}
|
||||
|
||||
if (enumerate_paths.empty())
|
||||
return;
|
||||
|
||||
listKeys(config, enumerate_paths, result, depth);
|
||||
}
|
||||
|
||||
template String getConfigValue<String>(const Poco::Util::AbstractConfiguration & config,
|
||||
const std::string & path);
|
||||
template UInt64 getConfigValue<UInt64>(const Poco::Util::AbstractConfiguration & config,
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -12,6 +14,10 @@ namespace NamedCollectionConfiguration
|
||||
|
||||
ConfigurationPtr createEmptyConfiguration(const std::string & root_name);
|
||||
|
||||
bool hasConfigValue(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
const std::string & path);
|
||||
|
||||
template <typename T> T getConfigValue(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
const std::string & path);
|
||||
@ -39,6 +45,28 @@ void removeConfigValue(
|
||||
|
||||
ConfigurationPtr createConfiguration(const std::string & root_name, const SettingsChanges & settings);
|
||||
|
||||
/// Enumerate keys paths of the config recursively.
|
||||
/// E.g. if `enumerate_paths` = {"root.key1"} and config like
|
||||
/// <root>
|
||||
/// <key0></key0>
|
||||
/// <key1>
|
||||
/// <key2></key2>
|
||||
/// <key3>
|
||||
/// <key4></key4>
|
||||
/// </key3>
|
||||
/// </key1>
|
||||
/// </root>
|
||||
/// the `result` will contain: "root.key0", "root.key1.key2" and "root.key1.key3.key4"
|
||||
///
|
||||
/// depth == -1 means to return all keys with full path: "root.key0", "root.key1.key2", "root.key1.key3.key4".
|
||||
/// depth == 0 means: "root.key0" and "root.key1"
|
||||
/// depth == 1 means: "root.key0", "root.key1.key2" and "root.key1.key3"
|
||||
/// and so on.
|
||||
void listKeys(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
std::queue<std::string> enumerate_paths,
|
||||
std::set<std::string, std::less<>> & result,
|
||||
ssize_t depth);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/escapeForFileName.h>
|
||||
#include <Common/FieldVisitorToString.h>
|
||||
#include <Common/logger_useful.h>
|
||||
@ -13,8 +13,8 @@
|
||||
#include <Parsers/parseQuery.h>
|
||||
#include <Parsers/ParserCreateQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Storages/NamedCollections/NamedCollections.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionConfiguration.h>
|
||||
#include <Common/NamedCollections/NamedCollections.h>
|
||||
#include <Common/NamedCollections/NamedCollectionConfiguration.h>
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@ -69,10 +69,10 @@ public:
|
||||
{
|
||||
const auto collection_prefix = getCollectionPrefix(collection_name);
|
||||
std::queue<std::string> enumerate_input;
|
||||
std::set<std::string> enumerate_result;
|
||||
std::set<std::string, std::less<>> enumerate_result;
|
||||
|
||||
enumerate_input.push(collection_prefix);
|
||||
collectKeys(config, std::move(enumerate_input), enumerate_result);
|
||||
NamedCollectionConfiguration::listKeys(config, std::move(enumerate_input), enumerate_result, -1);
|
||||
|
||||
/// Collection does not have any keys.
|
||||
/// (`enumerate_result` == <collection_path>).
|
||||
@ -97,50 +97,6 @@ private:
|
||||
{
|
||||
return fmt::format("{}.{}", NAMED_COLLECTIONS_CONFIG_PREFIX, collection_name);
|
||||
}
|
||||
|
||||
/// Enumerate keys paths of the config recursively.
|
||||
/// E.g. if `enumerate_paths` = {"root.key1"} and config like
|
||||
/// <root>
|
||||
/// <key0></key0>
|
||||
/// <key1>
|
||||
/// <key2></key2>
|
||||
/// <key3>
|
||||
/// <key4></key4>
|
||||
/// </key3>
|
||||
/// </key1>
|
||||
/// </root>
|
||||
/// the `result` will contain two strings: "root.key1.key2" and "root.key1.key3.key4"
|
||||
static void collectKeys(
|
||||
const Poco::Util::AbstractConfiguration & config,
|
||||
std::queue<std::string> enumerate_paths,
|
||||
std::set<std::string> & result)
|
||||
{
|
||||
if (enumerate_paths.empty())
|
||||
return;
|
||||
|
||||
auto initial_paths = std::move(enumerate_paths);
|
||||
enumerate_paths = {};
|
||||
while (!initial_paths.empty())
|
||||
{
|
||||
auto path = initial_paths.front();
|
||||
initial_paths.pop();
|
||||
|
||||
Poco::Util::AbstractConfiguration::Keys keys;
|
||||
config.keys(path, keys);
|
||||
|
||||
if (keys.empty())
|
||||
{
|
||||
result.insert(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto & key : keys)
|
||||
enumerate_paths.emplace(path + '.' + key);
|
||||
}
|
||||
}
|
||||
|
||||
collectKeys(config, enumerate_paths, result);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include <Interpreters/Context.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/Operators.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionConfiguration.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionConfiguration.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <ranges>
|
||||
|
||||
@ -229,9 +229,29 @@ public:
|
||||
assert(removed);
|
||||
}
|
||||
|
||||
Keys getKeys() const
|
||||
Keys getKeys(ssize_t depth, const std::string & prefix) const
|
||||
{
|
||||
return keys;
|
||||
std::queue<std::string> enumerate_input;
|
||||
|
||||
if (prefix.empty())
|
||||
{
|
||||
if (depth == -1)
|
||||
{
|
||||
/// Return all keys with full depth.
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Configuration::hasConfigValue(*config, prefix))
|
||||
return {};
|
||||
|
||||
enumerate_input.push(prefix);
|
||||
}
|
||||
|
||||
Keys result;
|
||||
Configuration::listKeys(*config, enumerate_input, result, depth);
|
||||
return result;
|
||||
}
|
||||
|
||||
Keys::const_iterator begin() const
|
||||
@ -379,10 +399,10 @@ MutableNamedCollectionPtr NamedCollection::duplicate() const
|
||||
std::move(impl), collection_name, NamedCollectionUtils::SourceId::NONE, true));
|
||||
}
|
||||
|
||||
NamedCollection::Keys NamedCollection::getKeys() const
|
||||
NamedCollection::Keys NamedCollection::getKeys(ssize_t depth, const std::string & prefix) const
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
return pimpl->getKeys();
|
||||
return pimpl->getKeys(depth, prefix);
|
||||
}
|
||||
|
||||
template <bool Locked> NamedCollection::const_iterator NamedCollection::begin() const
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Storages/NamedCollections/NamedCollections_fwd.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollections_fwd.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
|
||||
namespace Poco { namespace Util { class AbstractConfiguration; } }
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
|
||||
MutableNamedCollectionPtr duplicate() const;
|
||||
|
||||
Keys getKeys() const;
|
||||
Keys getKeys(ssize_t depth = -1, const std::string & prefix = "") const;
|
||||
|
||||
using iterator = typename Keys::iterator;
|
||||
using const_iterator = typename Keys::const_iterator;
|
@ -1,6 +1,6 @@
|
||||
#include <Common/tests/gtest_global_context.h>
|
||||
#include <Storages/NamedCollections/NamedCollections.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollections.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Poco/Util/XMLConfiguration.h>
|
||||
#include <Poco/DOM/DOMParser.h>
|
||||
#include <gtest/gtest.h>
|
||||
@ -143,3 +143,82 @@ key2:
|
||||
ASSERT_EQ(collection->get<Int64>("key2.key2_2.key2_3.key2_5"), 5);
|
||||
|
||||
}
|
||||
|
||||
TEST(NamedCollections, NestedConfigDuplicateKeys)
|
||||
{
|
||||
std::string xml(R"CONFIG(<clickhouse>
|
||||
<named_collections>
|
||||
<collection>
|
||||
<headers>
|
||||
<header>
|
||||
<name>key1</name>
|
||||
<value>value1</value>
|
||||
</header>
|
||||
<header>
|
||||
<name>key2</name>
|
||||
<value>value2</value>
|
||||
</header>
|
||||
<header>
|
||||
<name>key3</name>
|
||||
<value>value3</value>
|
||||
</header>
|
||||
</headers>
|
||||
</collection>
|
||||
</named_collections>
|
||||
</clickhouse>)CONFIG");
|
||||
|
||||
Poco::XML::DOMParser dom_parser;
|
||||
Poco::AutoPtr<Poco::XML::Document> document = dom_parser.parseString(xml);
|
||||
Poco::AutoPtr<Poco::Util::XMLConfiguration> config = new Poco::Util::XMLConfiguration(document);
|
||||
|
||||
NamedCollectionUtils::loadFromConfig(*config);
|
||||
auto collection = NamedCollectionFactory::instance().get("collection");
|
||||
|
||||
auto keys = collection->getKeys();
|
||||
ASSERT_EQ(keys.size(), 6);
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header.name"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1].name"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2].name"));
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header.value"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1].value"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2].value"));
|
||||
|
||||
ASSERT_EQ(collection->get<String>("headers.header.name"), "key1");
|
||||
ASSERT_EQ(collection->get<String>("headers.header[1].name"), "key2");
|
||||
ASSERT_EQ(collection->get<String>("headers.header[2].name"), "key3");
|
||||
|
||||
ASSERT_EQ(collection->get<String>("headers.header.value"), "value1");
|
||||
ASSERT_EQ(collection->get<String>("headers.header[1].value"), "value2");
|
||||
ASSERT_EQ(collection->get<String>("headers.header[2].value"), "value3");
|
||||
|
||||
keys = collection->getKeys(0);
|
||||
ASSERT_EQ(keys.size(), 1);
|
||||
ASSERT_TRUE(keys.contains("headers"));
|
||||
|
||||
keys = collection->getKeys(0, "headers");
|
||||
ASSERT_EQ(keys.size(), 3);
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1]"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2]"));
|
||||
|
||||
keys = collection->getKeys(1);
|
||||
ASSERT_EQ(keys.size(), 3);
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1]"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2]"));
|
||||
|
||||
keys = collection->getKeys(2);
|
||||
ASSERT_EQ(keys.size(), 6);
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header.name"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1].name"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2].name"));
|
||||
|
||||
ASSERT_TRUE(keys.contains("headers.header.value"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[1].value"));
|
||||
ASSERT_TRUE(keys.contains("headers.header[2].value"));
|
||||
}
|
@ -79,7 +79,7 @@ void KeeperSnapshotManagerS3::updateS3Configuration(const Poco::Util::AbstractCo
|
||||
LOG_INFO(log, "S3 configuration was updated");
|
||||
|
||||
auto credentials = Aws::Auth::AWSCredentials(auth_settings.access_key_id, auth_settings.secret_access_key);
|
||||
HeaderCollection headers = auth_settings.headers;
|
||||
auto headers = auth_settings.headers;
|
||||
|
||||
static constexpr size_t s3_max_redirects = 10;
|
||||
static constexpr bool enable_s3_requests_logging = false;
|
||||
|
@ -248,7 +248,7 @@ nuraft::ptr<nuraft::buffer> KeeperStateMachine::commit(const uint64_t log_idx, n
|
||||
session_id = storage->getSessionID(session_id_request.session_timeout_ms);
|
||||
LOG_DEBUG(log, "Session ID response {} with timeout {}", session_id, session_id_request.session_timeout_ms);
|
||||
response->session_id = session_id;
|
||||
if (!responses_queue.push(response_for_session))
|
||||
if (!responses_queue.push(response_for_session) && !responses_queue.isFinished())
|
||||
{
|
||||
ProfileEvents::increment(ProfileEvents::KeeperCommitsFailed);
|
||||
throw Exception(ErrorCodes::SYSTEM_ERROR, "Could not push response with session id {} into responses queue", session_id);
|
||||
@ -261,7 +261,7 @@ nuraft::ptr<nuraft::buffer> KeeperStateMachine::commit(const uint64_t log_idx, n
|
||||
KeeperStorage::ResponsesForSessions responses_for_sessions = storage->processRequest(
|
||||
request_for_session.request, request_for_session.session_id, request_for_session.zxid);
|
||||
for (auto & response_for_session : responses_for_sessions)
|
||||
if (!responses_queue.push(response_for_session))
|
||||
if (!responses_queue.push(response_for_session) && !responses_queue.isFinished())
|
||||
{
|
||||
ProfileEvents::increment(ProfileEvents::KeeperCommitsFailed);
|
||||
throw Exception(
|
||||
@ -523,7 +523,7 @@ void KeeperStateMachine::processReadRequest(const KeeperStorage::RequestForSessi
|
||||
true /*check_acl*/,
|
||||
true /*is_local*/);
|
||||
for (const auto & response : responses)
|
||||
if (!responses_queue.push(response))
|
||||
if (!responses_queue.push(response) && !responses_queue.isFinished())
|
||||
throw Exception(
|
||||
ErrorCodes::SYSTEM_ERROR, "Could not push response with session id {} into responses queue", response.session_id);
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ using DataTypes = std::vector<DataTypePtr>;
|
||||
|
||||
struct Array;
|
||||
|
||||
/* Generic class for all functions.
|
||||
* Represents interface for function signature.
|
||||
*/
|
||||
class IResolvedFunction
|
||||
{
|
||||
public:
|
||||
|
@ -14,6 +14,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int POSTGRESQL_CONNECTION_FAILURE;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +46,7 @@ PoolWithFailover::PoolWithFailover(
|
||||
}
|
||||
|
||||
PoolWithFailover::PoolWithFailover(
|
||||
const DB::StoragePostgreSQLConfiguration & configuration,
|
||||
const DB::StoragePostgreSQL::Configuration & configuration,
|
||||
size_t pool_size,
|
||||
size_t pool_wait_timeout_,
|
||||
size_t max_tries_,
|
||||
@ -70,6 +71,9 @@ ConnectionHolderPtr PoolWithFailover::get()
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (replicas_with_priority.empty())
|
||||
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "No address specified");
|
||||
|
||||
DB::WriteBufferFromOwnString error_message;
|
||||
for (size_t try_idx = 0; try_idx < max_tries; ++try_idx)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Storages/ExternalDataSourceConfiguration.h>
|
||||
#include <Storages/StoragePostgreSQL.h>
|
||||
|
||||
|
||||
static constexpr inline auto POSTGRESQL_POOL_DEFAULT_SIZE = 16;
|
||||
@ -33,7 +34,7 @@ public:
|
||||
bool auto_close_connection_);
|
||||
|
||||
explicit PoolWithFailover(
|
||||
const DB::StoragePostgreSQLConfiguration & configuration,
|
||||
const DB::StoragePostgreSQL::Configuration & configuration,
|
||||
size_t pool_size,
|
||||
size_t pool_wait_timeout,
|
||||
size_t max_tries_,
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/queryToString.h>
|
||||
#include <Storages/ExternalDataSourceConfiguration.h>
|
||||
#include <Storages/NamedCollectionsHelpers.h>
|
||||
#include <Common/NamedCollections/NamedCollections.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Common/Macros.h>
|
||||
#include <Common/filesystemHelpers.h>
|
||||
@ -322,25 +324,24 @@ DatabasePtr DatabaseFactory::getImpl(const ASTCreateQuery & create, const String
|
||||
|
||||
ASTs & engine_args = engine->arguments->children;
|
||||
auto use_table_cache = false;
|
||||
StoragePostgreSQLConfiguration configuration;
|
||||
StoragePostgreSQL::Configuration configuration;
|
||||
|
||||
if (auto named_collection = getExternalDataSourceConfiguration(engine_args, context, true))
|
||||
if (auto named_collection = tryGetNamedCollectionWithOverrides(engine_args))
|
||||
{
|
||||
auto [common_configuration, storage_specific_args, _] = named_collection.value();
|
||||
validateNamedCollection(
|
||||
*named_collection,
|
||||
{"host", "port", "user", "password", "database"},
|
||||
{"schema", "on_conflict", "use_table_cache"});
|
||||
|
||||
configuration.set(common_configuration);
|
||||
configuration.host = named_collection->get<String>("host");
|
||||
configuration.port = static_cast<UInt16>(named_collection->get<UInt64>("port"));
|
||||
configuration.addresses = {std::make_pair(configuration.host, configuration.port)};
|
||||
|
||||
for (const auto & [arg_name, arg_value] : storage_specific_args)
|
||||
{
|
||||
if (arg_name == "use_table_cache")
|
||||
use_table_cache = true;
|
||||
else
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||
"Unexpected key-value argument."
|
||||
"Got: {}, but expected one of:"
|
||||
"host, port, username, password, database, schema, use_table_cache.", arg_name);
|
||||
}
|
||||
configuration.username = named_collection->get<String>("user");
|
||||
configuration.password = named_collection->get<String>("password");
|
||||
configuration.database = named_collection->get<String>("database");
|
||||
configuration.schema = named_collection->getOrDefault<String>("schema", "");
|
||||
configuration.on_conflict = named_collection->getOrDefault<String>("on_conflict", "");
|
||||
use_table_cache = named_collection->getOrDefault<UInt64>("use_tables_cache", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -398,16 +399,22 @@ DatabasePtr DatabaseFactory::getImpl(const ASTCreateQuery & create, const String
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Engine `{}` must have arguments", engine_name);
|
||||
|
||||
ASTs & engine_args = engine->arguments->children;
|
||||
StoragePostgreSQLConfiguration configuration;
|
||||
StoragePostgreSQL::Configuration configuration;
|
||||
|
||||
if (auto named_collection = getExternalDataSourceConfiguration(engine_args, context, true))
|
||||
if (auto named_collection = tryGetNamedCollectionWithOverrides(engine_args))
|
||||
{
|
||||
auto [common_configuration, storage_specific_args, _] = named_collection.value();
|
||||
configuration.set(common_configuration);
|
||||
validateNamedCollection(
|
||||
*named_collection,
|
||||
{"host", "port", "user", "password", "database"},
|
||||
{"schema"});
|
||||
|
||||
if (!storage_specific_args.empty())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||
"MaterializedPostgreSQL Database requires only `host`, `port`, `database_name`, `username`, `password`.");
|
||||
configuration.host = named_collection->get<String>("host");
|
||||
configuration.port = static_cast<UInt16>(named_collection->get<UInt64>("port"));
|
||||
configuration.addresses = {std::make_pair(configuration.host, configuration.port)};
|
||||
configuration.username = named_collection->get<String>("user");
|
||||
configuration.password = named_collection->get<String>("password");
|
||||
configuration.database = named_collection->get<String>("database");
|
||||
configuration.schema = named_collection->getOrDefault<String>("schema", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ DatabasePostgreSQL::DatabasePostgreSQL(
|
||||
const String & metadata_path_,
|
||||
const ASTStorage * database_engine_define_,
|
||||
const String & dbname_,
|
||||
const StoragePostgreSQLConfiguration & configuration_,
|
||||
const StoragePostgreSQL::Configuration & configuration_,
|
||||
postgres::PoolWithFailoverPtr pool_,
|
||||
bool cache_tables_)
|
||||
: IDatabase(dbname_)
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
const String & metadata_path_,
|
||||
const ASTStorage * database_engine_define,
|
||||
const String & dbname_,
|
||||
const StoragePostgreSQLConfiguration & configuration,
|
||||
const StoragePostgreSQL::Configuration & configuration,
|
||||
postgres::PoolWithFailoverPtr pool_,
|
||||
bool cache_tables_);
|
||||
|
||||
@ -67,7 +67,7 @@ protected:
|
||||
private:
|
||||
String metadata_path;
|
||||
ASTPtr database_engine_define;
|
||||
StoragePostgreSQLConfiguration configuration;
|
||||
StoragePostgreSQL::Configuration configuration;
|
||||
postgres::PoolWithFailoverPtr pool;
|
||||
const bool cache_tables;
|
||||
|
||||
|
@ -715,7 +715,7 @@ void TablesDependencyGraph::log() const
|
||||
{
|
||||
if (nodes.empty())
|
||||
{
|
||||
LOG_TEST(getLogger(), "No tables");
|
||||
LOG_TRACE(getLogger(), "No tables");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -727,7 +727,7 @@ void TablesDependencyGraph::log() const
|
||||
|
||||
String level_desc = (node->level == CYCLIC_LEVEL) ? "cyclic" : fmt::format("level {}", node->level);
|
||||
|
||||
LOG_TEST(getLogger(), "Table {} has {} ({})", node->storage_id, dependencies_desc, level_desc);
|
||||
LOG_TRACE(getLogger(), "Table {} has {} ({})", node->storage_id, dependencies_desc, level_desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ void registerDictionarySourceHTTP(DictionarySourceFactory & factory)
|
||||
|
||||
auto settings_config_prefix = config_prefix + ".http";
|
||||
Poco::Net::HTTPBasicCredentials credentials;
|
||||
ReadWriteBufferFromHTTP::HTTPHeaderEntries header_entries;
|
||||
HTTPHeaderEntries header_entries;
|
||||
String url;
|
||||
String endpoint;
|
||||
String format;
|
||||
@ -246,7 +246,7 @@ void registerDictionarySourceHTTP(DictionarySourceFactory & factory)
|
||||
|
||||
header_entries.reserve(named_collection->configuration.headers.size());
|
||||
for (const auto & [key, value] : named_collection->configuration.headers)
|
||||
header_entries.emplace_back(std::make_tuple(key, value));
|
||||
header_entries.emplace_back(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -271,7 +271,7 @@ void registerDictionarySourceHTTP(DictionarySourceFactory & factory)
|
||||
{
|
||||
const auto header_key = config.getString(headers_prefix + "." + key + ".name", "");
|
||||
const auto header_value = config.getString(headers_prefix + "." + key + ".value", "");
|
||||
header_entries.emplace_back(std::make_tuple(header_key, header_value));
|
||||
header_entries.emplace_back(header_key, header_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
const std::string format;
|
||||
const std::string update_field;
|
||||
const UInt64 update_lag;
|
||||
const ReadWriteBufferFromHTTP::HTTPHeaderEntries header_entries;
|
||||
const HTTPHeaderEntries header_entries;
|
||||
};
|
||||
|
||||
HTTPDictionarySource(
|
||||
|
@ -74,7 +74,7 @@ std::unique_ptr<ReadBuffer> ReadBufferFromWebServer::initialize()
|
||||
0,
|
||||
buf_size,
|
||||
read_settings,
|
||||
ReadWriteBufferFromHTTP::HTTPHeaderEntries{},
|
||||
HTTPHeaderEntries{},
|
||||
range,
|
||||
&context->getRemoteHostFilter(),
|
||||
/* delay_initialization */true,
|
||||
|
@ -28,6 +28,11 @@ struct MarkInCompressedFile
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
auto asTuple() const
|
||||
{
|
||||
return std::make_tuple(offset_in_compressed_file, offset_in_decompressed_block);
|
||||
}
|
||||
|
||||
String toString() const
|
||||
{
|
||||
return "(" + DB::toString(offset_in_compressed_file) + "," + DB::toString(offset_in_decompressed_block) + ")";
|
||||
|
@ -36,6 +36,8 @@ struct Hash
|
||||
return _mm_crc32_u64(crc, val);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cd(static_cast<UInt32>(crc), val);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32(crc, val);
|
||||
#else
|
||||
throw Exception("String hash is not implemented without sse4.2 support", ErrorCodes::NOT_IMPLEMENTED);
|
||||
#endif
|
||||
@ -47,6 +49,8 @@ struct Hash
|
||||
return _mm_crc32_u32(crc, val);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cw(crc, val);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32_u32(crc, val);
|
||||
#else
|
||||
throw Exception("String hash is not implemented without sse4.2 support", ErrorCodes::NOT_IMPLEMENTED);
|
||||
#endif
|
||||
@ -58,6 +62,8 @@ struct Hash
|
||||
return _mm_crc32_u16(crc, val);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32ch(crc, val);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32_u16(crc, val);
|
||||
#else
|
||||
throw Exception("String hash is not implemented without sse4.2 support", ErrorCodes::NOT_IMPLEMENTED);
|
||||
#endif
|
||||
@ -69,6 +75,8 @@ struct Hash
|
||||
return _mm_crc32_u8(crc, val);
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cb(crc, val);
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32_u8(crc, val);
|
||||
#else
|
||||
throw Exception("String hash is not implemented without sse4.2 support", ErrorCodes::NOT_IMPLEMENTED);
|
||||
#endif
|
||||
|
@ -70,6 +70,8 @@ struct NgramDistanceImpl
|
||||
return _mm_crc32_u64(code_points[2], combined) & 0xFFFFu;
|
||||
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
|
||||
return __crc32cd(code_points[2], combined) & 0xFFFFu;
|
||||
#elif defined(__s390x__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
return s390x_crc32(code_points[2], combined) & 0xFFFFu;
|
||||
#else
|
||||
return (intHashCRC32(combined) ^ intHashCRC32(code_points[2])) & 0xFFFFu;
|
||||
#endif
|
||||
|
18
src/IO/HTTPHeaderEntries.h
Normal file
18
src/IO/HTTPHeaderEntries.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
struct HTTPHeaderEntry
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
HTTPHeaderEntry(const std::string & name_, const std::string & value_) : name(name_), value(value_) {}
|
||||
inline bool operator==(const HTTPHeaderEntry & other) const { return name == other.name && value == other.value; }
|
||||
};
|
||||
|
||||
using HTTPHeaderEntries = std::vector<HTTPHeaderEntry>;
|
||||
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/ReadSettings.h>
|
||||
#include <IO/WithFileName.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/types.h>
|
||||
@ -91,9 +92,6 @@ namespace detail
|
||||
class ReadWriteBufferFromHTTPBase : public SeekableReadBuffer, public WithFileName, public WithFileSize
|
||||
{
|
||||
public:
|
||||
using HTTPHeaderEntry = std::tuple<std::string, std::string>;
|
||||
using HTTPHeaderEntries = std::vector<HTTPHeaderEntry>;
|
||||
|
||||
/// HTTP range, including right bound [begin, end].
|
||||
struct Range
|
||||
{
|
||||
@ -159,8 +157,8 @@ namespace detail
|
||||
if (out_stream_callback)
|
||||
request.setChunkedTransferEncoding(true);
|
||||
|
||||
for (auto & http_header_entry : http_header_entries)
|
||||
request.set(std::get<0>(http_header_entry), std::get<1>(http_header_entry));
|
||||
for (auto & [header, value] : http_header_entries)
|
||||
request.set(header, value);
|
||||
|
||||
if (withPartialContent())
|
||||
{
|
||||
@ -319,11 +317,11 @@ namespace detail
|
||||
auto iter = std::find_if(
|
||||
http_header_entries.begin(),
|
||||
http_header_entries.end(),
|
||||
[&user_agent](const HTTPHeaderEntry & entry) { return std::get<0>(entry) == user_agent; });
|
||||
[&user_agent](const HTTPHeaderEntry & entry) { return entry.name == user_agent; });
|
||||
|
||||
if (iter == http_header_entries.end())
|
||||
{
|
||||
http_header_entries.emplace_back(std::make_pair("User-Agent", fmt::format("ClickHouse/{}", VERSION_STRING)));
|
||||
http_header_entries.emplace_back("User-Agent", fmt::format("ClickHouse/{}", VERSION_STRING));
|
||||
}
|
||||
|
||||
if (!delay_initialization)
|
||||
@ -779,7 +777,7 @@ public:
|
||||
UInt64 max_redirects_ = 0,
|
||||
size_t buffer_size_ = DBMS_DEFAULT_BUFFER_SIZE,
|
||||
ReadSettings settings_ = {},
|
||||
ReadWriteBufferFromHTTP::HTTPHeaderEntries http_header_entries_ = {},
|
||||
HTTPHeaderEntries http_header_entries_ = {},
|
||||
const RemoteHostFilter * remote_host_filter_ = nullptr,
|
||||
bool delay_initialization_ = true,
|
||||
bool use_external_buffer_ = false,
|
||||
@ -851,7 +849,7 @@ private:
|
||||
UInt64 max_redirects;
|
||||
size_t buffer_size;
|
||||
ReadSettings settings;
|
||||
ReadWriteBufferFromHTTP::HTTPHeaderEntries http_header_entries;
|
||||
HTTPHeaderEntries http_header_entries;
|
||||
const RemoteHostFilter * remote_host_filter;
|
||||
bool delay_initialization;
|
||||
bool use_external_buffer;
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include <Common/Throttler_fwd.h>
|
||||
#include <IO/ConnectionTimeouts.h>
|
||||
#include <IO/HTTPCommon.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
#include <IO/S3/SessionAwareIOStream.h>
|
||||
#include <Storages/HeaderCollection.h>
|
||||
|
||||
#include <aws/core/client/ClientConfiguration.h>
|
||||
#include <aws/core/http/HttpClient.h>
|
||||
@ -51,7 +51,7 @@ struct PocoHTTPClientConfiguration : public Aws::Client::ClientConfiguration
|
||||
bool for_disk_s3;
|
||||
ThrottlerPtr get_request_throttler;
|
||||
ThrottlerPtr put_request_throttler;
|
||||
HeaderCollection extra_headers;
|
||||
HTTPHeaderEntries extra_headers;
|
||||
|
||||
void updateSchemeAndRegion();
|
||||
|
||||
@ -169,7 +169,7 @@ private:
|
||||
/// NOTE: DELETE and CANCEL requests are not throttled by either put or get throttler
|
||||
ThrottlerPtr put_request_throttler;
|
||||
|
||||
const HeaderCollection extra_headers;
|
||||
const HTTPHeaderEntries extra_headers;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/ReadSettings.h>
|
||||
#include <IO/S3Common.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
#include <Storages/StorageS3Settings.h>
|
||||
|
||||
#include "TestPocoHTTPServer.h"
|
||||
@ -97,7 +98,7 @@ TEST(IOTestAwsS3Client, AppendExtraSSECHeaders)
|
||||
client_configuration.retryStrategy = std::make_shared<NoRetryStrategy>();
|
||||
|
||||
String server_side_encryption_customer_key_base64 = "Kv/gDqdWVGIT4iDqg+btQvV3lc1idlm4WI+MMOyHOAw=";
|
||||
DB::HeaderCollection headers;
|
||||
DB::HTTPHeaderEntries headers;
|
||||
bool use_environment_credentials = false;
|
||||
bool use_insecure_imds_request = false;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
# include <Common/quoteString.h>
|
||||
|
||||
# include <IO/WriteBufferFromString.h>
|
||||
# include <IO/HTTPHeaderEntries.h>
|
||||
# include <Storages/StorageS3Settings.h>
|
||||
|
||||
# include <aws/core/Version.h>
|
||||
@ -737,7 +738,7 @@ namespace S3
|
||||
const String & access_key_id,
|
||||
const String & secret_access_key,
|
||||
const String & server_side_encryption_customer_key_base64,
|
||||
HeaderCollection headers,
|
||||
HTTPHeaderEntries headers,
|
||||
bool use_environment_credentials,
|
||||
bool use_insecure_imds_request)
|
||||
{
|
||||
@ -980,7 +981,7 @@ AuthSettings AuthSettings::loadFromConfig(const std::string & config_elem, const
|
||||
if (config.has(config_elem + ".use_insecure_imds_request"))
|
||||
use_insecure_imds_request = config.getBool(config_elem + ".use_insecure_imds_request");
|
||||
|
||||
HeaderCollection headers;
|
||||
HTTPHeaderEntries headers;
|
||||
Poco::Util::AbstractConfiguration::Keys subconfig_keys;
|
||||
config.keys(config_elem, subconfig_keys);
|
||||
for (const std::string & subkey : subconfig_keys)
|
||||
@ -991,7 +992,7 @@ AuthSettings AuthSettings::loadFromConfig(const std::string & config_elem, const
|
||||
auto delimiter = header_str.find(':');
|
||||
if (delimiter == std::string::npos)
|
||||
throw Exception("Malformed s3 header value", ErrorCodes::INVALID_CONFIG_PARAMETER);
|
||||
headers.emplace_back(HttpHeader{header_str.substr(0, delimiter), header_str.substr(delimiter + 1, String::npos)});
|
||||
headers.emplace_back(header_str.substr(0, delimiter), header_str.substr(delimiter + 1, String::npos));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Storages/HeaderCollection.h>
|
||||
#include <IO/S3/PocoHTTPClient.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
@ -77,7 +77,7 @@ public:
|
||||
const String & access_key_id,
|
||||
const String & secret_access_key,
|
||||
const String & server_side_encryption_customer_key_base64,
|
||||
HeaderCollection headers,
|
||||
HTTPHeaderEntries headers,
|
||||
bool use_environment_credentials,
|
||||
bool use_insecure_imds_request);
|
||||
|
||||
@ -157,7 +157,7 @@ struct AuthSettings
|
||||
std::string region;
|
||||
std::string server_side_encryption_customer_key_base64;
|
||||
|
||||
HeaderCollection headers;
|
||||
HTTPHeaderEntries headers;
|
||||
|
||||
std::optional<bool> use_environment_credentials;
|
||||
std::optional<bool> use_insecure_imds_request;
|
||||
|
@ -33,6 +33,35 @@ namespace ErrorCodes
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::pair<ColumnsWithTypeAndName, bool> getFunctionArguments(const ActionsDAG::NodeRawConstPtrs & children)
|
||||
{
|
||||
size_t num_arguments = children.size();
|
||||
|
||||
bool all_const = true;
|
||||
ColumnsWithTypeAndName arguments(num_arguments);
|
||||
|
||||
for (size_t i = 0; i < num_arguments; ++i)
|
||||
{
|
||||
const auto & child = *children[i];
|
||||
|
||||
ColumnWithTypeAndName argument;
|
||||
argument.column = child.column;
|
||||
argument.type = child.result_type;
|
||||
argument.name = child.result_name;
|
||||
|
||||
if (!argument.column || !isColumnConst(*argument.column))
|
||||
all_const = false;
|
||||
|
||||
arguments[i] = std::move(argument);
|
||||
}
|
||||
return { std::move(arguments), all_const };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ActionsDAG::Node::toTree(JSONBuilder::JSONMap & map) const
|
||||
{
|
||||
map.add("Node Type", magic_enum::enum_name(type));
|
||||
@ -161,85 +190,38 @@ const ActionsDAG::Node & ActionsDAG::addFunction(
|
||||
NodeRawConstPtrs children,
|
||||
std::string result_name)
|
||||
{
|
||||
size_t num_arguments = children.size();
|
||||
auto [arguments, all_const] = getFunctionArguments(children);
|
||||
|
||||
Node node;
|
||||
node.type = ActionType::FUNCTION;
|
||||
node.children = std::move(children);
|
||||
|
||||
bool all_const = true;
|
||||
ColumnsWithTypeAndName arguments(num_arguments);
|
||||
|
||||
for (size_t i = 0; i < num_arguments; ++i)
|
||||
{
|
||||
const auto & child = *node.children[i];
|
||||
|
||||
ColumnWithTypeAndName argument;
|
||||
argument.column = child.column;
|
||||
argument.type = child.result_type;
|
||||
argument.name = child.result_name;
|
||||
|
||||
if (!argument.column || !isColumnConst(*argument.column))
|
||||
all_const = false;
|
||||
|
||||
arguments[i] = std::move(argument);
|
||||
}
|
||||
|
||||
node.function_base = function->build(arguments);
|
||||
node.result_type = node.function_base->getResultType();
|
||||
node.function = node.function_base->prepare(arguments);
|
||||
node.is_deterministic = node.function_base->isDeterministic();
|
||||
|
||||
/// If all arguments are constants, and function is suitable to be executed in 'prepare' stage - execute function.
|
||||
if (node.function_base->isSuitableForConstantFolding())
|
||||
{
|
||||
ColumnPtr column;
|
||||
|
||||
if (all_const)
|
||||
{
|
||||
size_t num_rows = arguments.empty() ? 0 : arguments.front().column->size();
|
||||
column = node.function->execute(arguments, node.result_type, num_rows, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
column = node.function_base->getConstantResultForNonConstArguments(arguments, node.result_type);
|
||||
}
|
||||
|
||||
/// If the result is not a constant, just in case, we will consider the result as unknown.
|
||||
if (column && isColumnConst(*column))
|
||||
{
|
||||
/// All constant (literal) columns in block are added with size 1.
|
||||
/// But if there was no columns in block before executing a function, the result has size 0.
|
||||
/// Change the size to 1.
|
||||
|
||||
if (column->empty())
|
||||
column = column->cloneResized(1);
|
||||
|
||||
node.column = std::move(column);
|
||||
}
|
||||
}
|
||||
|
||||
if (result_name.empty())
|
||||
{
|
||||
result_name = function->getName() + "(";
|
||||
for (size_t i = 0; i < num_arguments; ++i)
|
||||
{
|
||||
if (i)
|
||||
result_name += ", ";
|
||||
result_name += node.children[i]->result_name;
|
||||
}
|
||||
result_name += ")";
|
||||
}
|
||||
|
||||
node.result_name = std::move(result_name);
|
||||
|
||||
return addNode(std::move(node));
|
||||
auto function_base = function->build(arguments);
|
||||
return addFunctionImpl(
|
||||
function_base,
|
||||
std::move(children),
|
||||
std::move(arguments),
|
||||
std::move(result_name),
|
||||
all_const);
|
||||
}
|
||||
|
||||
const ActionsDAG::Node & ActionsDAG::addFunction(
|
||||
const FunctionBasePtr & function_base,
|
||||
NodeRawConstPtrs children,
|
||||
std::string result_name)
|
||||
{
|
||||
auto [arguments, all_const] = getFunctionArguments(children);
|
||||
|
||||
return addFunctionImpl(
|
||||
function_base,
|
||||
std::move(children),
|
||||
std::move(arguments),
|
||||
std::move(result_name),
|
||||
all_const);
|
||||
}
|
||||
|
||||
const ActionsDAG::Node & ActionsDAG::addFunctionImpl(
|
||||
const FunctionBasePtr & function_base,
|
||||
NodeRawConstPtrs children,
|
||||
ColumnsWithTypeAndName arguments,
|
||||
std::string result_name,
|
||||
bool all_const)
|
||||
{
|
||||
size_t num_arguments = children.size();
|
||||
|
||||
@ -247,24 +229,6 @@ const ActionsDAG::Node & ActionsDAG::addFunction(
|
||||
node.type = ActionType::FUNCTION;
|
||||
node.children = std::move(children);
|
||||
|
||||
bool all_const = true;
|
||||
ColumnsWithTypeAndName arguments(num_arguments);
|
||||
|
||||
for (size_t i = 0; i < num_arguments; ++i)
|
||||
{
|
||||
const auto & child = *node.children[i];
|
||||
|
||||
ColumnWithTypeAndName argument;
|
||||
argument.column = child.column;
|
||||
argument.type = child.result_type;
|
||||
argument.name = child.result_name;
|
||||
|
||||
if (!argument.column || !isColumnConst(*argument.column))
|
||||
all_const = false;
|
||||
|
||||
arguments[i] = std::move(argument);
|
||||
}
|
||||
|
||||
node.function_base = function_base;
|
||||
node.result_type = node.function_base->getResultType();
|
||||
node.function = node.function_base->prepare(arguments);
|
||||
@ -640,9 +604,15 @@ Block ActionsDAG::updateHeader(Block header) const
|
||||
arguments[i] = node_to_column[node->children[i]];
|
||||
if (!arguments[i].column)
|
||||
throw Exception(ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK,
|
||||
"Not found column {} in block", node->children[i]->result_name);
|
||||
"Not found column {} in block {}", node->children[i]->result_name,
|
||||
header.dumpStructure());
|
||||
}
|
||||
|
||||
if (node->type == ActionsDAG::ActionType::INPUT)
|
||||
throw Exception(ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK,
|
||||
"Not found column {} in block {}",
|
||||
node->result_name, header.dumpStructure());
|
||||
|
||||
node_to_column[node] = executeActionForHeader(node, std::move(arguments));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <Core/ColumnsWithTypeAndName.h>
|
||||
#include <Core/NamesAndTypes.h>
|
||||
#include <Core/Names.h>
|
||||
@ -350,6 +351,13 @@ private:
|
||||
|
||||
Node & addNode(Node node);
|
||||
|
||||
const Node & addFunctionImpl(
|
||||
const FunctionBasePtr & function_base,
|
||||
NodeRawConstPtrs children,
|
||||
ColumnsWithTypeAndName arguments,
|
||||
std::string result_name,
|
||||
bool all_const);
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
void compileFunctions(size_t min_count_to_compile_expression, const std::unordered_set<const Node *> & lazy_executed_nodes = {});
|
||||
#endif
|
||||
|
@ -1668,12 +1668,14 @@ ActionsDAGPtr SelectQueryExpressionAnalyzer::appendProjectResult(ExpressionActio
|
||||
ExpressionActionsChain::Step & step = chain.lastStep(aggregated_columns);
|
||||
|
||||
NamesWithAliases result_columns;
|
||||
NameSet required_result_columns_set(required_result_columns.begin(), required_result_columns.end());
|
||||
|
||||
ASTs asts = select_query->select()->children;
|
||||
for (const auto & ast : asts)
|
||||
{
|
||||
String result_name = ast->getAliasOrColumnName();
|
||||
if (required_result_columns.empty() || required_result_columns.contains(result_name))
|
||||
|
||||
if (required_result_columns_set.empty() || required_result_columns_set.contains(result_name))
|
||||
{
|
||||
std::string source_name = ast->getColumnName();
|
||||
|
||||
@ -1709,6 +1711,15 @@ ActionsDAGPtr SelectQueryExpressionAnalyzer::appendProjectResult(ExpressionActio
|
||||
|
||||
auto actions = chain.getLastActions();
|
||||
actions->project(result_columns);
|
||||
|
||||
if (!required_result_columns.empty())
|
||||
{
|
||||
result_columns.clear();
|
||||
for (const auto & column : required_result_columns)
|
||||
result_columns.emplace_back(column, std::string{});
|
||||
actions->project(result_columns);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ public:
|
||||
const TreeRewriterResultPtr & syntax_analyzer_result_,
|
||||
ContextPtr context_,
|
||||
const StorageMetadataPtr & metadata_snapshot_,
|
||||
const NameSet & required_result_columns_ = {},
|
||||
const Names & required_result_columns_ = {},
|
||||
bool do_global_ = false,
|
||||
const SelectQueryOptions & options_ = {},
|
||||
PreparedSetsPtr prepared_sets_ = nullptr)
|
||||
@ -364,7 +364,7 @@ public:
|
||||
private:
|
||||
StorageMetadataPtr metadata_snapshot;
|
||||
/// If non-empty, ignore all expressions not from this list.
|
||||
NameSet required_result_columns;
|
||||
Names required_result_columns;
|
||||
SelectQueryOptions query_options;
|
||||
|
||||
JoinPtr makeJoin(
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/executeDDLQueryOnCluster.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/executeDDLQueryOnCluster.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/executeDDLQueryOnCluster.h>
|
||||
#include <Storages/NamedCollections/NamedCollectionUtils.h>
|
||||
#include <Common/NamedCollections/NamedCollectionUtils.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -568,7 +568,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(
|
||||
syntax_analyzer_result,
|
||||
context,
|
||||
metadata_snapshot,
|
||||
NameSet(required_result_column_names.begin(), required_result_column_names.end()),
|
||||
required_result_column_names,
|
||||
!options.only_analyze,
|
||||
options,
|
||||
prepared_sets);
|
||||
|
@ -165,7 +165,13 @@ InterpreterSelectWithUnionQuery::InterpreterSelectWithUnionQuery(
|
||||
for (size_t query_num = 0; query_num < num_children; ++query_num)
|
||||
{
|
||||
headers[query_num] = nested_interpreters[query_num]->getSampleBlock();
|
||||
const auto & current_required_result_column_names = required_result_column_names_for_other_selects[query_num];
|
||||
/// Here we check that, in case if required_result_column_names were specified,
|
||||
/// nested interpreter returns exactly it. Except if query requires full header.
|
||||
/// The code aboew is written in a way that for 0th query required_result_column_names_for_other_selects[0]
|
||||
/// is an empty list, and we should use required_result_column_names instead.
|
||||
const auto & current_required_result_column_names = (query_num == 0 && !require_full_header)
|
||||
? required_result_column_names
|
||||
: required_result_column_names_for_other_selects[query_num];
|
||||
if (!current_required_result_column_names.empty())
|
||||
{
|
||||
const auto & header_columns = headers[query_num].getNames();
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
struct Data
|
||||
{
|
||||
std::unordered_map<String, NamesAndTypesList> table_columns;
|
||||
std::unordered_map<String, String> table_name_alias;
|
||||
std::vector<String> tables_order;
|
||||
std::shared_ptr<ASTExpressionList> new_select_expression_list;
|
||||
|
||||
@ -71,6 +72,7 @@ public:
|
||||
String table_name = table.table.getQualifiedNamePrefix(false);
|
||||
NamesAndTypesList columns = table.columns;
|
||||
tables_order.push_back(table_name);
|
||||
table_name_alias.emplace(table.table.table /* table_name */, table_name /* alias_name */);
|
||||
table_columns.emplace(std::move(table_name), std::move(columns));
|
||||
}
|
||||
}
|
||||
@ -85,9 +87,21 @@ public:
|
||||
ASTs & columns,
|
||||
ShouldAddColumnPredicate should_add_column_predicate = [](const String &) { return true; })
|
||||
{
|
||||
auto it = table_columns.find(table_name);
|
||||
String name = table_name;
|
||||
auto it = table_columns.find(name);
|
||||
if (it == table_columns.end())
|
||||
throw Exception("Unknown qualified identifier: " + table_name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
{
|
||||
auto table_name_it = table_name_alias.find(table_name);
|
||||
if (table_name_it != table_name_alias.end())
|
||||
{
|
||||
name = table_name_it->second;
|
||||
it = table_columns.find(table_name_it->second);
|
||||
if (it == table_columns.end())
|
||||
throw Exception("Unknown qualified identifier: " + table_name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
else
|
||||
throw Exception("Unknown qualified identifier: " + table_name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
|
||||
for (const auto & column : it->second)
|
||||
{
|
||||
@ -146,8 +160,6 @@ private:
|
||||
{
|
||||
has_asterisks = true;
|
||||
|
||||
if (child->children.size() != 1)
|
||||
throw Exception("Logical error: qualified asterisk must have exactly one child", ErrorCodes::LOGICAL_ERROR);
|
||||
auto & identifier = child->children[0]->as<ASTTableIdentifier &>();
|
||||
|
||||
data.addTableColumns(identifier.name(), columns);
|
||||
@ -155,7 +167,10 @@ private:
|
||||
// QualifiedAsterisk's transformers start to appear at child 1
|
||||
for (const auto * it = qualified_asterisk->children.begin() + 1; it != qualified_asterisk->children.end(); ++it)
|
||||
{
|
||||
IASTColumnsTransformer::transform(*it, columns);
|
||||
if (it->get()->as<ASTColumnsApplyTransformer>() || it->get()->as<ASTColumnsExceptTransformer>() || it->get()->as<ASTColumnsReplaceTransformer>())
|
||||
IASTColumnsTransformer::transform(*it, columns);
|
||||
else
|
||||
throw Exception("Logical error: qualified asterisk must only have children of IASTColumnsTransformer type", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
}
|
||||
else if (const auto * columns_list_matcher = child->as<ASTColumnsListMatcher>())
|
||||
|
@ -43,6 +43,7 @@ namespace ErrorCodes
|
||||
extern const int UNKNOWN_MUTATION_COMMAND;
|
||||
extern const int NO_SUCH_COLUMN_IN_TABLE;
|
||||
extern const int CANNOT_UPDATE_COLUMN;
|
||||
extern const int UNEXPECTED_EXPRESSION;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -946,6 +947,8 @@ QueryPipelineBuilder MutationsInterpreter::addStreamsForLaterStages(const std::v
|
||||
for (size_t i = 0; i < stage.expressions_chain.steps.size(); ++i)
|
||||
{
|
||||
const auto & step = stage.expressions_chain.steps[i];
|
||||
if (step->actions()->hasArrayJoin())
|
||||
throw Exception("arrayJoin is not allowed in mutations", ErrorCodes::UNEXPECTED_EXPRESSION);
|
||||
if (i < stage.filter_column_names.size())
|
||||
{
|
||||
/// Execute DELETEs.
|
||||
|
@ -31,18 +31,20 @@ TraceCollector::TraceCollector(std::shared_ptr<TraceLog> trace_log_)
|
||||
|
||||
|
||||
TraceCollector::~TraceCollector()
|
||||
try
|
||||
{
|
||||
if (!thread.joinable())
|
||||
LOG_ERROR(&Poco::Logger::get("TraceCollector"), "TraceCollector thread is malformed and cannot be joined");
|
||||
else
|
||||
stop();
|
||||
try
|
||||
{
|
||||
if (!thread.joinable())
|
||||
LOG_ERROR(&Poco::Logger::get("TraceCollector"), "TraceCollector thread is malformed and cannot be joined");
|
||||
else
|
||||
stop();
|
||||
|
||||
TraceSender::pipe.close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException("TraceCollector");
|
||||
TraceSender::pipe.close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException("TraceCollector");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,7 +33,7 @@ bool replaceForPositionalArguments(ASTPtr & argument, const ASTSelectQuery * sel
|
||||
auto pos = ast_literal->value.get<UInt64>();
|
||||
if (!pos || pos > columns.size())
|
||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||
"Positional argument out of bounds: {} (exprected in range [1, {}]",
|
||||
"Positional argument out of bounds: {} (expected in range [1, {}]",
|
||||
pos, columns.size());
|
||||
|
||||
const auto & column = columns[--pos];
|
||||
|
@ -115,6 +115,8 @@ void ASTSelectQuery::formatImpl(const FormatSettings & s, FormatState & state, F
|
||||
|
||||
if (group_by_with_grouping_sets)
|
||||
{
|
||||
if (!groupBy()) /// sanity check, issue 43049
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Corrupt AST");
|
||||
auto nested_frame = frame;
|
||||
nested_frame.surround_each_list_element_with_parens = true;
|
||||
nested_frame.expression_list_prepend_whitespace = false;
|
||||
|
@ -350,7 +350,7 @@ void Planner::buildQueryPlanIfNeeded()
|
||||
auto function_node = std::make_shared<FunctionNode>("and");
|
||||
auto and_function = FunctionFactory::instance().get("and", query_context);
|
||||
function_node->getArguments().getNodes() = {query_node.getPrewhere(), query_node.getWhere()};
|
||||
function_node->resolveAsFunction(and_function->build(function_node->getArgumentTypes()));
|
||||
function_node->resolveAsFunction(and_function->build(function_node->getArgumentColumns()));
|
||||
query_node.getWhere() = std::move(function_node);
|
||||
query_node.getPrewhere() = {};
|
||||
}
|
||||
|
@ -399,110 +399,6 @@ void URLBasedDataSourceConfiguration::set(const URLBasedDataSourceConfiguration
|
||||
headers = conf.headers;
|
||||
}
|
||||
|
||||
|
||||
std::optional<URLBasedDataSourceConfig> getURLBasedDataSourceConfiguration(const ASTs & args, ContextPtr context)
|
||||
{
|
||||
if (args.empty())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "External data source must have arguments");
|
||||
|
||||
URLBasedDataSourceConfiguration configuration;
|
||||
StorageSpecificArgs non_common_args;
|
||||
|
||||
if (const auto * collection = typeid_cast<const ASTIdentifier *>(args[0].get()))
|
||||
{
|
||||
const auto & config = context->getConfigRef();
|
||||
auto config_prefix = fmt::format("named_collections.{}", collection->name());
|
||||
|
||||
if (!config.has(config_prefix))
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "There is no collection named `{}` in config", collection->name());
|
||||
|
||||
Poco::Util::AbstractConfiguration::Keys keys;
|
||||
config.keys(config_prefix, keys);
|
||||
for (const auto & key : keys)
|
||||
{
|
||||
if (key == "url")
|
||||
{
|
||||
configuration.url = config.getString(config_prefix + ".url", "");
|
||||
}
|
||||
else if (key == "method")
|
||||
{
|
||||
configuration.http_method = config.getString(config_prefix + ".method", "");
|
||||
}
|
||||
else if (key == "format")
|
||||
{
|
||||
configuration.format = config.getString(config_prefix + ".format", "");
|
||||
}
|
||||
else if (key == "structure")
|
||||
{
|
||||
configuration.structure = config.getString(config_prefix + ".structure", "");
|
||||
}
|
||||
else if (key == "compression_method")
|
||||
{
|
||||
configuration.compression_method = config.getString(config_prefix + ".compression_method", "");
|
||||
}
|
||||
else if (key == "headers")
|
||||
{
|
||||
Poco::Util::AbstractConfiguration::Keys header_keys;
|
||||
config.keys(config_prefix + ".headers", header_keys);
|
||||
for (const auto & header : header_keys)
|
||||
{
|
||||
const auto header_prefix = config_prefix + ".headers." + header;
|
||||
configuration.headers.emplace_back(
|
||||
config.getString(header_prefix + ".name"),
|
||||
config.getString(header_prefix + ".value"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto value = config.getString(config_prefix + '.' + key);
|
||||
non_common_args.emplace_back(std::make_pair(key, std::make_shared<ASTLiteral>(value)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Check key-value arguments.
|
||||
for (size_t i = 1; i < args.size(); ++i)
|
||||
{
|
||||
if (const auto * ast_function = typeid_cast<const ASTFunction *>(args[i].get()))
|
||||
{
|
||||
const auto * args_expr = assert_cast<const ASTExpressionList *>(ast_function->arguments.get());
|
||||
auto function_args = args_expr->children;
|
||||
if (function_args.size() != 2)
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected key-value defined argument");
|
||||
|
||||
auto arg_name = function_args[0]->as<ASTIdentifier>()->name();
|
||||
auto arg_value_ast = evaluateConstantExpressionOrIdentifierAsLiteral(function_args[1], context);
|
||||
auto arg_value = arg_value_ast->as<ASTLiteral>()->value;
|
||||
|
||||
if (arg_name == "url")
|
||||
configuration.url = arg_value.safeGet<String>();
|
||||
else if (arg_name == "method")
|
||||
configuration.http_method = arg_value.safeGet<String>();
|
||||
else if (arg_name == "format")
|
||||
configuration.format = arg_value.safeGet<String>();
|
||||
else if (arg_name == "compression_method")
|
||||
configuration.compression_method = arg_value.safeGet<String>();
|
||||
else if (arg_name == "structure")
|
||||
configuration.structure = arg_value.safeGet<String>();
|
||||
else
|
||||
non_common_args.emplace_back(std::make_pair(arg_name, arg_value_ast));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected key-value defined argument");
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.url.empty() || configuration.format.empty())
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||
"Storage requires {}", configuration.url.empty() ? "url" : "format");
|
||||
|
||||
URLBasedDataSourceConfig source_config{ .configuration = configuration, .specific_args = non_common_args };
|
||||
return source_config;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool getExternalDataSourceConfiguration(const ASTs & args, BaseSettings<T> & settings, ContextPtr context)
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <Storages/StorageS3Settings.h>
|
||||
#include <Storages/HeaderCollection.h>
|
||||
#include <IO/HTTPHeaderEntries.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -46,12 +46,6 @@ struct StorageMySQLConfiguration : ExternalDataSourceConfiguration
|
||||
String on_duplicate_clause;
|
||||
};
|
||||
|
||||
struct StorageMongoDBConfiguration : ExternalDataSourceConfiguration
|
||||
{
|
||||
String options;
|
||||
};
|
||||
|
||||
|
||||
using StorageSpecificArgs = std::vector<std::pair<String, ASTPtr>>;
|
||||
|
||||
struct ExternalDataSourceInfo
|
||||
@ -109,7 +103,7 @@ struct URLBasedDataSourceConfiguration
|
||||
String user;
|
||||
String password;
|
||||
|
||||
HeaderCollection headers;
|
||||
HTTPHeaderEntries headers;
|
||||
String http_method;
|
||||
|
||||
void set(const URLBasedDataSourceConfiguration & conf);
|
||||
@ -133,8 +127,6 @@ struct URLBasedDataSourceConfig
|
||||
StorageSpecificArgs specific_args;
|
||||
};
|
||||
|
||||
std::optional<URLBasedDataSourceConfig> getURLBasedDataSourceConfiguration(const ASTs & args, ContextPtr context);
|
||||
|
||||
std::optional<URLBasedDataSourceConfig> getURLBasedDataSourceConfiguration(
|
||||
const Poco::Util::AbstractConfiguration & dict_config, const String & dict_config_prefix, ContextPtr context);
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
struct HttpHeader
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
HttpHeader(const std::string & name_, const std::string & value_) : name(name_), value(value_) {}
|
||||
inline bool operator==(const HttpHeader & other) const { return name == other.name && value == other.value; }
|
||||
};
|
||||
|
||||
using HeaderCollection = std::vector<HttpHeader>;
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user