Merge branch 'master' into cancellable-mutex

This commit is contained in:
Sergei Trifonov 2023-01-06 23:52:35 +01:00 committed by GitHub
commit c65573dd7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
168 changed files with 1987 additions and 1172 deletions

5
.gitmodules vendored
View File

@ -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

View File

@ -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

@ -1 +1 @@
Subproject commit 15d534e8a9ca1eda6bacee514e37d08b4f38a526
Subproject commit 0f1ba9e5c4a67cb3898de0c0b4f911d4194dc8de

1
contrib/crc32-s390x vendored Submodule

@ -0,0 +1 @@
Subproject commit 30980583bf9ed3fa193abb83a1849705ff457f70

View 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)

View File

@ -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

View File

@ -0,0 +1,5 @@
version: '2.3'
# Used to pre-pull images with docker-compose
services:
clickhouse1:
image: clickhouse/integration-test

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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'

View File

@ -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/

View File

@ -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"

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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:-}

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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`.

View File

@ -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

View File

@ -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

View File

@ -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\])

View File

@ -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>\])

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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
}

View File

@ -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>

View File

@ -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;
};

View File

@ -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)

View File

@ -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
{

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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()));
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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);

View File

@ -75,7 +75,6 @@ public:
function_node->getAggregateFunction()->getParameters(),
properties);
auto function_result_type = function_node->getResultType();
function_node->resolveAsAggregateFunction(std::move(aggregate_function));
}
};

View File

@ -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:

View File

@ -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);

View File

@ -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));

View File

@ -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)

View File

@ -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;
}

View File

@ -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));

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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);
}
};

View File

@ -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

View File

@ -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;

View File

@ -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"));
}

View File

@ -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;

View File

@ -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);
}

View File

@ -12,6 +12,9 @@ using DataTypes = std::vector<DataTypePtr>;
struct Array;
/* Generic class for all functions.
* Represents interface for function signature.
*/
class IResolvedFunction
{
public:

View File

@ -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)
{

View File

@ -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_,

View File

@ -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
{

View File

@ -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_)

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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(

View File

@ -74,7 +74,7 @@ std::unique_ptr<ReadBuffer> ReadBufferFromWebServer::initialize()
0,
buf_size,
read_settings,
ReadWriteBufferFromHTTP::HTTPHeaderEntries{},
HTTPHeaderEntries{},
range,
&context->getRemoteHostFilter(),
/* delay_initialization */true,

View File

@ -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) + ")";

View File

@ -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

View File

@ -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

View 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>;
}

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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>())

View File

@ -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.

View File

@ -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");
}
}

View File

@ -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];

View File

@ -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;

View File

@ -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() = {};
}

View File

@ -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)
{

View File

@ -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);

View File

@ -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