diff --git a/README.md b/README.md index ea9f365a3c6..bad00d8280f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ClickHouse® is an open-source column-oriented database management system that a * [Tutorial](https://clickhouse.tech/docs/en/getting_started/tutorial/) shows how to set up and query small ClickHouse cluster. * [Documentation](https://clickhouse.tech/docs/en/) provides more in-depth information. * [YouTube channel](https://www.youtube.com/c/ClickHouseDB) has a lot of content about ClickHouse in video format. -* [Slack](https://join.slack.com/t/clickhousedb/shared_invite/zt-nwwakmk4-xOJ6cdy0sJC3It8j348~IA) and [Telegram](https://telegram.me/clickhouse_en) allow to chat with ClickHouse users in real-time. +* [Slack](https://join.slack.com/t/clickhousedb/shared_invite/zt-qfort0u8-TWqK4wIP0YSdoDE0btKa1w) and [Telegram](https://telegram.me/clickhouse_en) allow to chat with ClickHouse users in real-time. * [Blog](https://clickhouse.yandex/blog/en/) contains various ClickHouse-related articles, as well as announcements and reports about events. * [Code Browser](https://clickhouse.tech/codebrowser/html_report/ClickHouse/index.html) with syntax highlight and navigation. * [Contacts](https://clickhouse.tech/#contacts) can help to get your questions answered if there are any. diff --git a/contrib/grpc b/contrib/grpc index 5b79aae85c5..60c986e15ca 160000 --- a/contrib/grpc +++ b/contrib/grpc @@ -1 +1 @@ -Subproject commit 5b79aae85c515e0df4abfb7b1e07975fdc7cecc1 +Subproject commit 60c986e15cae70aade721d26badabab1f822fdd6 diff --git a/docs/en/operations/external-authenticators/ldap.md b/docs/en/operations/external-authenticators/ldap.md index 1b65ecc968b..805d45e1b38 100644 --- a/docs/en/operations/external-authenticators/ldap.md +++ b/docs/en/operations/external-authenticators/ldap.md @@ -17,6 +17,7 @@ To define LDAP server you must add `ldap_servers` section to the `config.xml`. + localhost 636 @@ -31,6 +32,18 @@ To define LDAP server you must add `ldap_servers` section to the `config.xml`. /path/to/tls_ca_cert_dir ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384 + + + + localhost + 389 + EXAMPLE\{user_name} + + CN=Users,DC=example,DC=com + (&(objectClass=user)(sAMAccountName={user_name})) + + no + ``` @@ -43,6 +56,15 @@ Note, that you can define multiple LDAP servers inside the `ldap_servers` sectio - `port` — LDAP server port, default is `636` if `enable_tls` is set to `true`, `389` otherwise. - `bind_dn` — Template used to construct the DN to bind to. - The resulting DN will be constructed by replacing all `{user_name}` substrings of the template with the actual user name during each authentication attempt. +- `user_dn_detection` - Section with LDAP search parameters for detecting the actual user DN of the bound user. + - This is mainly used in search filters for further role mapping when the server is Active Directory. The resulting user DN will be used when replacing `{user_dn}` substrings wherever they are allowed. By default, user DN is set equal to bind DN, but once search is performed, it will be updated with to the actual detected user DN value. + - `base_dn` - Template used to construct the base DN for the LDAP search. + - The resulting DN will be constructed by replacing all `{user_name}` and `{bind_dn}` substrings of the template with the actual user name and bind DN during the LDAP search. + - `scope` - Scope of the LDAP search. + - Accepted values are: `base`, `one_level`, `children`, `subtree` (the default). + - `search_filter` - Template used to construct the search filter for the LDAP search. + - The resulting filter will be constructed by replacing all `{user_name}`, `{bind_dn}`, and `{base_dn}` substrings of the template with the actual user name, bind DN, and base DN during the LDAP search. + - Note, that the special characters must be escaped properly in XML. - `verification_cooldown` — A period of time, in seconds, after a successful bind attempt, during which the user will be assumed to be successfully authenticated for all consecutive requests without contacting the LDAP server. - Specify `0` (the default) to disable caching and force contacting the LDAP server for each authentication request. - `enable_tls` — A flag to trigger the use of the secure connection to the LDAP server. @@ -107,7 +129,7 @@ Goes into `config.xml`. - + my_ldap_server @@ -122,6 +144,18 @@ Goes into `config.xml`. clickhouse_ + + + + my_ad_server + + CN=Users,DC=example,DC=com + CN + subtree + (&(objectClass=group)(member={user_dn})) + clickhouse_ + + ``` @@ -137,13 +171,13 @@ Note that `my_ldap_server` referred in the `ldap` section inside the `user_direc - When a user authenticates, while still bound to LDAP, an LDAP search is performed using `search_filter` and the name of the logged-in user. For each entry found during that search, the value of the specified attribute is extracted. For each attribute value that has the specified prefix, the prefix is removed, and the rest of the value becomes the name of a local role defined in ClickHouse, which is expected to be created beforehand by the [CREATE ROLE](../../sql-reference/statements/create/role.md#create-role-statement) statement. - There can be multiple `role_mapping` sections defined inside the same `ldap` section. All of them will be applied. - `base_dn` — Template used to construct the base DN for the LDAP search. - - The resulting DN will be constructed by replacing all `{user_name}` and `{bind_dn}` substrings of the template with the actual user name and bind DN during each LDAP search. + - The resulting DN will be constructed by replacing all `{user_name}`, `{bind_dn}`, and `{user_dn}` substrings of the template with the actual user name, bind DN, and user DN during each LDAP search. - `scope` — Scope of the LDAP search. - Accepted values are: `base`, `one_level`, `children`, `subtree` (the default). - `search_filter` — Template used to construct the search filter for the LDAP search. - - The resulting filter will be constructed by replacing all `{user_name}`, `{bind_dn}` and `{base_dn}` substrings of the template with the actual user name, bind DN and base DN during each LDAP search. + - The resulting filter will be constructed by replacing all `{user_name}`, `{bind_dn}`, `{user_dn}`, and `{base_dn}` substrings of the template with the actual user name, bind DN, user DN, and base DN during each LDAP search. - Note, that the special characters must be escaped properly in XML. - - `attribute` — Attribute name whose values will be returned by the LDAP search. + - `attribute` — Attribute name whose values will be returned by the LDAP search. `cn`, by default. - `prefix` — Prefix, that will be expected to be in front of each string in the original list of strings returned by the LDAP search. The prefix will be removed from the original strings and the resulting strings will be treated as local role names. Empty by default. [Original article](https://clickhouse.tech/docs/en/operations/external-authenticators/ldap/) diff --git a/docs/en/sql-reference/aggregate-functions/parametric-functions.md b/docs/en/sql-reference/aggregate-functions/parametric-functions.md index b9d504241db..0edb1601023 100644 --- a/docs/en/sql-reference/aggregate-functions/parametric-functions.md +++ b/docs/en/sql-reference/aggregate-functions/parametric-functions.md @@ -253,7 +253,7 @@ windowFunnel(window, [mode, [mode, ... ]])(timestamp, cond1, cond2, ..., condN) **Parameters** -- `window` — Length of the sliding window, it is the time interval between first condition and last condition. The unit of `window` depends on the `timestamp` itself and varies. Determined using the expression `timestamp of cond1 <= timestamp of cond2 <= ... <= timestamp of condN <= timestamp of cond1 + window`. +- `window` — Length of the sliding window, it is the time interval between the first and the last condition. The unit of `window` depends on the `timestamp` itself and varies. Determined using the expression `timestamp of cond1 <= timestamp of cond2 <= ... <= timestamp of condN <= timestamp of cond1 + window`. - `mode` — It is an optional argument. One or more modes can be set. - `'strict'` — If same condition holds for sequence of events then such non-unique events would be skipped. - `'strict_order'` — Don't allow interventions of other events. E.g. in the case of `A->B->D->C`, it stops finding `A->B->C` at the `D` and the max event level is 2. @@ -312,7 +312,7 @@ FROM GROUP BY user_id ) GROUP BY level -ORDER BY level ASC +ORDER BY level ASC; ``` Result: diff --git a/docs/en/sql-reference/functions/ip-address-functions.md b/docs/en/sql-reference/functions/ip-address-functions.md index 0b5dd7160b8..d37ef2e8f1a 100644 --- a/docs/en/sql-reference/functions/ip-address-functions.md +++ b/docs/en/sql-reference/functions/ip-address-functions.md @@ -422,7 +422,7 @@ Type: [UInt8](../../sql-reference/data-types/int-uint.md). Query: ``` sql -SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8') +SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8'); ``` Result: @@ -436,7 +436,7 @@ Result: Query: ``` sql -SELECT isIPAddressInRange('127.0.0.1', 'ffff::/16') +SELECT isIPAddressInRange('127.0.0.1', 'ffff::/16'); ``` Result: diff --git a/docs/en/sql-reference/functions/type-conversion-functions.md b/docs/en/sql-reference/functions/type-conversion-functions.md index d8d13d81d97..661469e6901 100644 --- a/docs/en/sql-reference/functions/type-conversion-functions.md +++ b/docs/en/sql-reference/functions/type-conversion-functions.md @@ -373,7 +373,7 @@ This function accepts a number or date or date with time, and returns a FixedStr ## reinterpretAsUUID {#reinterpretasuuid} -This function accepts 16 bytes string, and returns UUID containing bytes representing the corresponding value in network byte order (big-endian). If the string isn't long enough, the functions work as if the string is padded with the necessary number of null bytes to the end. If the string longer than 16 bytes, the extra bytes at the end are ignored. +Accepts 16 bytes string and returns UUID containing bytes representing the corresponding value in network byte order (big-endian). If the string isn't long enough, the function works as if the string is padded with the necessary number of null bytes to the end. If the string longer than 16 bytes, the extra bytes at the end are ignored. **Syntax** @@ -429,7 +429,24 @@ Result: ## reinterpret(x, T) {#type_conversion_function-reinterpret} -Use the same source in-memory bytes sequence for `x` value and reinterpret it to destination type +Uses the same source in-memory bytes sequence for `x` value and reinterprets it to destination type. + +**Syntax** + +``` sql +reinterpret(x, type) +``` + +**Arguments** + +- `x` — Any type. +- `type` — Destination type. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Destination type value. + +**Examples** Query: ```sql @@ -448,11 +465,27 @@ Result: ## CAST(x, T) {#type_conversion_function-cast} -Converts input value `x` to the `T` data type. Unlike to `reinterpret` function use external representation of `x` value. +Converts input value `x` to the `T` data type. Unlike to `reinterpret` function, type conversion is performed in a natural way. The syntax `CAST(x AS t)` is also supported. -Note, that if value `x` does not fit the bounds of type T, the function overflows. For example, CAST(-1, 'UInt8') returns 255. +!!! note "Note" + If value `x` does not fit the bounds of type `T`, the function overflows. For example, `CAST(-1, 'UInt8')` returns `255`. + +**Syntax** + +``` sql +CAST(x, T) +``` + +**Arguments** + +- `x` — Any type. +- `T` — Destination type. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Destination type value. **Examples** @@ -460,9 +493,9 @@ Query: ```sql SELECT - cast(toInt8(-1), 'UInt8') AS cast_int_to_uint, - cast(toInt8(1), 'Float32') AS cast_int_to_float, - cast('1', 'UInt32') AS cast_string_to_int + CAST(toInt8(-1), 'UInt8') AS cast_int_to_uint, + CAST(toInt8(1), 'Float32') AS cast_int_to_float, + CAST('1', 'UInt32') AS cast_string_to_int; ``` Result: @@ -492,7 +525,7 @@ Result: └─────────────────────┴─────────────────────┴────────────┴─────────────────────┴───────────────────────────┘ ``` -Conversion to FixedString(N) only works for arguments of type String or FixedString(N). +Conversion to FixedString(N) only works for arguments of type [String](../../sql-reference/data-types/string.md) or [FixedString](../../sql-reference/data-types/fixedstring.md). Type conversion to [Nullable](../../sql-reference/data-types/nullable.md) and back is supported. @@ -1038,7 +1071,7 @@ Result: ## parseDateTime64BestEffort {#parsedatetime64besteffort} -Same as [parseDateTimeBestEffort](#parsedatetimebesteffort) function but also parse milliseconds and microseconds and return `DateTime64(3)` or `DateTime64(6)` data types. +Same as [parseDateTimeBestEffort](#parsedatetimebesteffort) function but also parse milliseconds and microseconds and returns [DateTime](../../sql-reference/functions/type-conversion-functions.md#data_type-datetime) data type. **Syntax** @@ -1049,9 +1082,13 @@ parseDateTime64BestEffort(time_string [, precision [, time_zone]]) **Parameters** - `time_string` — String containing a date or date with time to convert. [String](../../sql-reference/data-types/string.md). -- `precision` — `3` for milliseconds, `6` for microseconds. Default `3`. Optional [UInt8](../../sql-reference/data-types/int-uint.md). +- `precision` — Required precision. `3` — for milliseconds, `6` — for microseconds. Default — `3`. Optional. [UInt8](../../sql-reference/data-types/int-uint.md). - `time_zone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone). The function parses `time_string` according to the timezone. Optional. [String](../../sql-reference/data-types/string.md). +**Returned value** + +- `time_string` converted to the [DateTime](../../sql-reference/data-types/datetime.md) data type. + **Examples** Query: @@ -1064,7 +1101,7 @@ UNION ALL SELECT parseDateTime64BestEffort('2021-01-01 01:01:00.12346',6) AS a, toTypeName(a) AS t UNION ALL SELECT parseDateTime64BestEffort('2021-01-01 01:01:00.12346',3,'Europe/Moscow') AS a, toTypeName(a) AS t -FORMAT PrettyCompactMonoBlcok +FORMAT PrettyCompactMonoBlock; ``` Result: @@ -1131,12 +1168,14 @@ Result: ## toUnixTimestamp64Nano {#tounixtimestamp64nano} -Converts a `DateTime64` to a `Int64` value with fixed sub-second precision. -Input value is scaled up or down appropriately depending on it precision. Please note that output value is a timestamp in UTC, not in timezone of `DateTime64`. +Converts a `DateTime64` to a `Int64` value with fixed sub-second precision. Input value is scaled up or down appropriately depending on it precision. + +!!! info "Note" + The output value is a timestamp in UTC, not in the timezone of `DateTime64`. **Syntax** -``` sql +```sql toUnixTimestamp64Milli(value) ``` @@ -1152,7 +1191,7 @@ toUnixTimestamp64Milli(value) Query: -``` sql +```sql WITH toDateTime64('2019-09-16 19:20:12.345678910', 6) AS dt64 SELECT toUnixTimestamp64Milli(dt64); ``` @@ -1298,4 +1337,3 @@ Result: │ 2,"good" │ └───────────────────────────────────────────┘ ``` - diff --git a/docs/en/sql-reference/statements/grant.md b/docs/en/sql-reference/statements/grant.md index 89f35b5f701..068eac1d083 100644 --- a/docs/en/sql-reference/statements/grant.md +++ b/docs/en/sql-reference/statements/grant.md @@ -316,7 +316,7 @@ Allows executing [CREATE](../../sql-reference/statements/create/index.md) and [A Allows executing [DROP](../../sql-reference/statements/misc.md#drop) and [DETACH](../../sql-reference/statements/misc.md#detach) queries according to the following hierarchy of privileges: -- `DROP`. Level: +- `DROP`. Level: `GROUP` - `DROP DATABASE`. Level: `DATABASE` - `DROP TABLE`. Level: `TABLE` - `DROP VIEW`. Level: `VIEW` diff --git a/docs/ru/sql-reference/aggregate-functions/parametric-functions.md b/docs/ru/sql-reference/aggregate-functions/parametric-functions.md index e5162b63b88..508c8de2a58 100644 --- a/docs/ru/sql-reference/aggregate-functions/parametric-functions.md +++ b/docs/ru/sql-reference/aggregate-functions/parametric-functions.md @@ -253,7 +253,7 @@ windowFunnel(window, [mode, [mode, ... ]])(timestamp, cond1, cond2, ..., condN) **Параметры** -- `window` — ширина скользящего окна по времени. Единица измерения зависит от `timestamp` и может варьироваться. Должно соблюдаться условие `timestamp события cond2 <= timestamp события cond1 + window`. +- `window` — ширина скользящего окна по времени. Это время между первым и последним условием. Единица измерения зависит от `timestamp` и может варьироваться. Должно соблюдаться условие `timestamp события cond1 <= timestamp события cond2 <= ... <= timestamp события condN <= timestamp события cond1 + window`. - `mode` — необязательный параметр. Может быть установленно несколько значений одновременно. - `'strict'` — не учитывать подряд идущие повторяющиеся события. - `'strict_order'` — запрещает посторонние события в искомой последовательности. Например, при поиске цепочки `A->B->C` в `A->B->D->C` поиск будет остановлен на `D` и функция вернет 2. @@ -311,7 +311,7 @@ FROM GROUP BY user_id ) GROUP BY level -ORDER BY level ASC +ORDER BY level ASC; ``` ## retention {#retention} diff --git a/docs/ru/sql-reference/functions/ip-address-functions.md b/docs/ru/sql-reference/functions/ip-address-functions.md index d7f6d2f7618..b02d45d7667 100644 --- a/docs/ru/sql-reference/functions/ip-address-functions.md +++ b/docs/ru/sql-reference/functions/ip-address-functions.md @@ -397,9 +397,9 @@ SELECT addr, isIPv6String(addr) FROM ( SELECT ['::', '1111::ffff', '::ffff:127.0 ## isIPAddressInRange {#isipaddressinrange} -Проверяет попадает ли IP адрес в интервал, заданный в [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) нотации. +Проверяет, попадает ли IP адрес в интервал, заданный в нотации [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). -**Syntax** +**Синтаксис** ``` sql isIPAddressInRange(address, prefix) @@ -409,7 +409,7 @@ isIPAddressInRange(address, prefix) **Аргументы** - `address` — IPv4 или IPv6 адрес. [String](../../sql-reference/data-types/string.md). -- `prefix` — IPv4 или IPv6 подсеть, заданная в CIDR нотации. [String](../../sql-reference/data-types/string.md). +- `prefix` — IPv4 или IPv6 подсеть, заданная в нотации CIDR. [String](../../sql-reference/data-types/string.md). **Возвращаемое значение** @@ -422,7 +422,7 @@ isIPAddressInRange(address, prefix) Запрос: ``` sql -SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8') +SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8'); ``` Результат: @@ -436,7 +436,7 @@ SELECT isIPAddressInRange('127.0.0.1', '127.0.0.0/8') Запрос: ``` sql -SELECT isIPAddressInRange('127.0.0.1', 'ffff::/16') +SELECT isIPAddressInRange('127.0.0.1', 'ffff::/16'); ``` Результат: diff --git a/docs/ru/sql-reference/functions/type-conversion-functions.md b/docs/ru/sql-reference/functions/type-conversion-functions.md index fc1dd15f8e3..2226c90525d 100644 --- a/docs/ru/sql-reference/functions/type-conversion-functions.md +++ b/docs/ru/sql-reference/functions/type-conversion-functions.md @@ -369,7 +369,7 @@ SELECT toFixedString('foo\0bar', 8) AS s, toStringCutToZero(s) AS s_cut; ## reinterpretAsUUID {#reinterpretasuuid} -Функция принимает шестнадцатибайтную строку и интерпретирует ее байты в network order (big-endian). Если строка имеет недостаточную длину, то функция работает так, как будто строка дополнена необходимым количетсвом нулевых байт с конца. Если строка длиннее, чем шестнадцать байт, то игнорируются лишние байты с конца. +Функция принимает строку из 16 байт и интерпретирует ее байты в порядок от старшего к младшему. Если строка имеет недостаточную длину, то функция работает так, как будто строка дополнена необходимым количеством нулевых байтов с конца. Если строка длиннее, чем 16 байтов, то лишние байты с конца игнорируются. **Синтаксис** @@ -425,9 +425,27 @@ SELECT uuid = uuid2; ## reinterpret(x, T) {#type_conversion_function-reinterpret} -Использует туже самую исходную последовательность байт в памяти для значения `x` и переинтерпретирует ее как конечный тип данных +Использует ту же самую исходную последовательность байтов в памяти для значения `x` и интерпретирует ее как конечный тип данных `T`. + +**Синтаксис** + +``` sql +reinterpret(x, type) +``` + +**Аргументы** + +- `x` — любой тип данных. +- `type` — конечный тип данных. [String](../../sql-reference/data-types/string.md). + +**Возвращаемое значение** + +- Значение конечного типа данных. + +**Примеры** Запрос: + ```sql SELECT reinterpret(toInt8(-1), 'UInt8') as int_to_uint, reinterpret(toInt8(1), 'Float32') as int_to_float, @@ -448,7 +466,23 @@ SELECT reinterpret(toInt8(-1), 'UInt8') as int_to_uint, Поддерживается также синтаксис `CAST(x AS t)`. -Обратите внимание, что если значение `x` не может быть преобразовано к типу `T`, возникает переполнение. Например, `CAST(-1, 'UInt8')` возвращает 255. +!!! warning "Предупреждение" + Если значение `x` не может быть преобразовано к типу `T`, возникает переполнение. Например, `CAST(-1, 'UInt8')` возвращает 255. + +**Синтаксис** + +``` sql +CAST(x, T) +``` + +**Аргументы** + +- `x` — любой тип данных. +- `T` — конечный тип данных. [String](../../sql-reference/data-types/string.md). + +**Возвращаемое значение** + +- Значение конечного типа данных. **Примеры** @@ -456,9 +490,9 @@ SELECT reinterpret(toInt8(-1), 'UInt8') as int_to_uint, ```sql SELECT - cast(toInt8(-1), 'UInt8') AS cast_int_to_uint, - cast(toInt8(1), 'Float32') AS cast_int_to_float, - cast('1', 'UInt32') AS cast_string_to_int + CAST(toInt8(-1), 'UInt8') AS cast_int_to_uint, + CAST(toInt8(1), 'Float32') AS cast_int_to_float, + CAST('1', 'UInt32') AS cast_string_to_int ``` Результат: @@ -488,9 +522,9 @@ SELECT └─────────────────────┴─────────────────────┴────────────┴─────────────────────┴───────────────────────────┘ ``` -Преобразование в FixedString(N) работает только для аргументов типа String или FixedString(N). +Преобразование в FixedString(N) работает только для аргументов типа [String](../../sql-reference/data-types/string.md) или [FixedString](../../sql-reference/data-types/fixedstring.md). -Поддержано преобразование к типу [Nullable](../../sql-reference/functions/type-conversion-functions.md) и обратно. +Поддерживается преобразование к типу [Nullable](../../sql-reference/functions/type-conversion-functions.md) и обратно. **Примеры** @@ -860,7 +894,7 @@ AS parseDateTimeBestEffortUS; ## parseDateTimeBestEffortOrZero {#parsedatetimebesteffortorzero} ## parseDateTime32BestEffortOrZero {#parsedatetime32besteffortorzero} -Работает также как [parseDateTimeBestEffort](#parsedatetimebesteffort), но возвращает нулевую дату или нулевую дату и время когда получает формат даты который не может быть обработан. +Работает аналогично функции [parseDateTimeBestEffort](#parsedatetimebesteffort), но возвращает нулевое значение, если формат даты не может быть обработан. ## parseDateTimeBestEffortUSOrNull {#parsedatetimebesteffortusornull} @@ -1036,19 +1070,23 @@ SELECT parseDateTimeBestEffortUSOrZero('02.2021') AS parseDateTimeBestEffortUSOr ## parseDateTime64BestEffort {#parsedatetime64besteffort} -Работает также как функция [parseDateTimeBestEffort](#parsedatetimebesteffort) но также понимамет милисекунды и микросекунды и возвращает `DateTime64(3)` или `DateTime64(6)` типы данных в зависимости от заданной точности. +Работает аналогично функции [parseDateTimeBestEffort](#parsedatetimebesteffort), но также принимает миллисекунды и микросекунды. Возвращает тип данных [DateTime](../../sql-reference/functions/type-conversion-functions.md#data_type-datetime). -**Syntax** +**Синтаксис** ``` sql parseDateTime64BestEffort(time_string [, precision [, time_zone]]) ``` -**Parameters** +**Аргументы** -- `time_string` — String containing a date or date with time to convert. [String](../../sql-reference/data-types/string.md). -- `precision` — `3` for milliseconds, `6` for microseconds. Default `3`. Optional [UInt8](../../sql-reference/data-types/int-uint.md). -- `time_zone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone). The function parses `time_string` according to the timezone. Optional. [String](../../sql-reference/data-types/string.md). +- `time_string` — строка, содержащая дату или дату со временем, которые нужно преобразовать. [String](../../sql-reference/data-types/string.md). +- `precision` — требуемая точность: `3` — для миллисекунд, `6` — для микросекунд. По умолчанию — `3`. Необязательный. [UInt8](../../sql-reference/data-types/int-uint.md). +- `time_zone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone). Разбирает значение `time_string` в зависимости от часового пояса. Необязательный. [String](../../sql-reference/data-types/string.md). + +**Возвращаемое значение** + +- `time_string`, преобразованная в тип данных [DateTime](../../sql-reference/data-types/datetime.md). **Примеры** @@ -1062,7 +1100,7 @@ UNION ALL SELECT parseDateTime64BestEffort('2021-01-01 01:01:00.12346',6) AS a, toTypeName(a) AS t UNION ALL SELECT parseDateTime64BestEffort('2021-01-01 01:01:00.12346',3,'Europe/Moscow') AS a, toTypeName(a) AS t -FORMAT PrettyCompactMonoBlcok +FORMAT PrettyCompactMonoBlock; ``` Результат: @@ -1078,12 +1116,11 @@ FORMAT PrettyCompactMonoBlcok ## parseDateTime64BestEffortOrNull {#parsedatetime32besteffortornull} -Работает также как функция [parseDateTime64BestEffort](#parsedatetime64besteffort) но возвращает `NULL` когда встречает формат даты который не может обработать. +Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но возвращает `NULL`, если формат даты не может быть обработан. ## parseDateTime64BestEffortOrZero {#parsedatetime64besteffortorzero} -Работает также как функция [parseDateTime64BestEffort](#parsedatetimebesteffort) но возвращает "нулевую" дату и время когда встречает формат даты который не может обработать. - +Работает аналогично функции [parseDateTime64BestEffort](#parsedatetimebesteffort), но возвращает нулевую дату и время, если формат даты не может быть обработан. ## toLowCardinality {#tolowcardinality} @@ -1130,11 +1167,14 @@ SELECT toLowCardinality('1'); ## toUnixTimestamp64Nano {#tounixtimestamp64nano} Преобразует значение `DateTime64` в значение `Int64` с фиксированной точностью менее одной секунды. -Входное значение округляется соответствующим образом вверх или вниз в зависимости от его точности. Обратите внимание, что возвращаемое значение - это временная метка в UTC, а не в часовом поясе `DateTime64`. +Входное значение округляется соответствующим образом вверх или вниз в зависимости от его точности. + +!!! info "Примечание" + Возвращаемое значение — это временная метка в UTC, а не в часовом поясе `DateTime64`. **Синтаксис** -``` sql +```sql toUnixTimestamp64Milli(value) ``` @@ -1150,7 +1190,7 @@ toUnixTimestamp64Milli(value) Запрос: -``` sql +```sql WITH toDateTime64('2019-09-16 19:20:12.345678910', 6) AS dt64 SELECT toUnixTimestamp64Milli(dt64); ``` @@ -1296,4 +1336,3 @@ FROM numbers(3); │ 2,"good" │ └───────────────────────────────────────────┘ ``` - diff --git a/docs/tools/README.md b/docs/tools/README.md index 0a6c41d8089..4340561fa57 100644 --- a/docs/tools/README.md +++ b/docs/tools/README.md @@ -51,5 +51,5 @@ The easiest way to see the result is to use `--livereload=8888` argument of buil At the moment there’s no easy way to do just that, but you can consider: -- To hit the “Watch” button on top of GitHub web interface to know as early as possible, even during pull request. Alternative to this is `#github-activity` channel of [public ClickHouse Slack](https://join.slack.com/t/clickhousedb/shared_invite/zt-nwwakmk4-xOJ6cdy0sJC3It8j348~IA). +- To hit the “Watch” button on top of GitHub web interface to know as early as possible, even during pull request. Alternative to this is `#github-activity` channel of [public ClickHouse Slack](https://join.slack.com/t/clickhousedb/shared_invite/zt-qfort0u8-TWqK4wIP0YSdoDE0btKa1w). - Some search engines allow to subscribe on specific website changes via email and you can opt-in for that for https://clickhouse.tech. diff --git a/docs/tools/website.py b/docs/tools/website.py index 6927fbd87bb..f0346de5c94 100644 --- a/docs/tools/website.py +++ b/docs/tools/website.py @@ -155,10 +155,6 @@ def build_website(args): os.path.join(args.src_dir, 'utils', 'list-versions', 'version_date.tsv'), os.path.join(args.output_dir, 'data', 'version_date.tsv')) - shutil.copy2( - os.path.join(args.website_dir, 'js', 'embedd.min.js'), - os.path.join(args.output_dir, 'js', 'embedd.min.js')) - for root, _, filenames in os.walk(args.output_dir): for filename in filenames: if filename == 'main.html': diff --git a/docs/zh/engines/table-engines/integrations/odbc.md b/docs/zh/engines/table-engines/integrations/odbc.md index 1264efeaa41..767c32cc438 100644 --- a/docs/zh/engines/table-engines/integrations/odbc.md +++ b/docs/zh/engines/table-engines/integrations/odbc.md @@ -7,11 +7,11 @@ toc_title: ODBC # ODBC {#table-engine-odbc} -允许ClickHouse通过以下方式连接到外部数据库 [ODBC](https://en.wikipedia.org/wiki/Open_Database_Connectivity). +允许ClickHouse通过[ODBC](https://en.wikipedia.org/wiki/Open_Database_Connectivity)方式连接到外部数据库. -为了安全地实现ODBC连接,ClickHouse使用单独的程序 `clickhouse-odbc-bridge`. 如果直接从ODBC驱动程序加载 `clickhouse-server`,驱动程序问题可能会导致ClickHouse服务器崩溃。 ClickHouse自动启动 `clickhouse-odbc-bridge` 当它是必需的。 ODBC桥程序是从相同的软件包作为安装 `clickhouse-server`. +为了安全地实现ODBC连接,ClickHouse使用了一个独立程序 `clickhouse-odbc-bridge`. 如果ODBC驱动程序是直接从 `clickhouse-server`中加载的,那么驱动问题可能会导致ClickHouse服务崩溃。 当有需要时,ClickHouse会自动启动 `clickhouse-odbc-bridge`。 ODBC桥梁程序与`clickhouse-server`来自相同的安装包. -该引擎支持 [可为空](../../../sql-reference/data-types/nullable.md) 数据类型。 +该引擎支持 [可为空](../../../sql-reference/data-types/nullable.md) 的数据类型。 ## 创建表 {#creating-a-table} @@ -25,14 +25,14 @@ CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster] ENGINE = ODBC(connection_settings, external_database, external_table) ``` -请参阅的详细说明 [CREATE TABLE](../../../sql-reference/statements/create.md#create-table-query) 查询。 +详情请见 [CREATE TABLE](../../../sql-reference/statements/create.md#create-table-query) 查询。 表结构可以与源表结构不同: - 列名应与源表中的列名相同,但您可以按任何顺序使用其中的一些列。 -- 列类型可能与源表中的列类型不同。 ClickHouse尝试 [投](../../../sql-reference/functions/type-conversion-functions.md#type_conversion_function-cast) ClickHouse数据类型的值。 +- 列类型可能与源表中的列类型不同。 ClickHouse尝试将数值[映射](../../../sql-reference/functions/type-conversion-functions.md#type_conversion_function-cast) 到ClickHouse的数据类型。 -**发动机参数** +**引擎参数** - `connection_settings` — Name of the section with connection settings in the `odbc.ini` 文件 - `external_database` — Name of a database in an external DBMS. @@ -40,13 +40,13 @@ ENGINE = ODBC(connection_settings, external_database, external_table) ## 用法示例 {#usage-example} -**通过ODBC从本地MySQL安装中检索数据** +**通过ODBC从本地安装的MySQL中检索数据** -此示例检查Ubuntu Linux18.04和MySQL服务器5.7。 +本示例针对Ubuntu Linux18.04和MySQL服务器5.7进行检查。 -确保安装了unixODBC和MySQL连接器。 +请确保安装了unixODBC和MySQL连接器。 -默认情况下(如果从软件包安装),ClickHouse以用户身份启动 `clickhouse`. 因此,您需要在MySQL服务器中创建和配置此用户。 +默认情况下(如果从软件包安装),ClickHouse以用户`clickhouse`的身份启动 . 因此,您需要在MySQL服务器中创建和配置此用户。 ``` bash $ sudo mysql @@ -57,7 +57,7 @@ mysql> CREATE USER 'clickhouse'@'localhost' IDENTIFIED BY 'clickhouse'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'clickhouse'@'clickhouse' WITH GRANT OPTION; ``` -然后配置连接 `/etc/odbc.ini`. +然后在`/etc/odbc.ini`中配置连接 . ``` bash $ cat /etc/odbc.ini @@ -70,7 +70,7 @@ USERNAME = clickhouse PASSWORD = clickhouse ``` -您可以使用 `isql` unixodbc安装中的实用程序。 +您可以从安装的unixodbc中使用 `isql` 实用程序来检查连接情况。 ``` bash $ isql -v mysqlconn diff --git a/docs/zh/operations/system-tables/data_type_families.md b/docs/zh/operations/system-tables/data_type_families.md index 21eb4785e23..db08ff0371b 100644 --- a/docs/zh/operations/system-tables/data_type_families.md +++ b/docs/zh/operations/system-tables/data_type_families.md @@ -5,13 +5,13 @@ machine_translated_rev: 5decc73b5dc60054f19087d3690c4eb99446a6c3 # 系统。data_type_families {#system_tables-data_type_families} -包含有关受支持的信息 [数据类型](../../sql-reference/data-types/). +包含有关受支持的[数据类型](../../sql-reference/data-types/)的信息. -列: +列字段包括: -- `name` ([字符串](../../sql-reference/data-types/string.md)) — Data type name. -- `case_insensitive` ([UInt8](../../sql-reference/data-types/int-uint.md)) — Property that shows whether you can use a data type name in a query in case insensitive manner or not. For example, `Date` 和 `date` 都是有效的。 -- `alias_to` ([字符串](../../sql-reference/data-types/string.md)) — Data type name for which `name` 是个化名 +- `name` ([String](../../sql-reference/data-types/string.md)) — 数据类型的名称. +- `case_insensitive` ([UInt8](../../sql-reference/data-types/int-uint.md)) — 该属性显示是否可以在查询中以不区分大小写的方式使用数据类型名称。例如 `Date` 和 `date` 都是有效的。 +- `alias_to` ([String](../../sql-reference/data-types/string.md)) — 名称为别名的数据类型名称。 **示例** @@ -36,4 +36,4 @@ SELECT * FROM system.data_type_families WHERE alias_to = 'String' **另请参阅** -- [语法](../../sql-reference/syntax.md) — Information about supported syntax. +- [Syntax](../../sql-reference/syntax.md) — 关于所支持的语法信息. diff --git a/docs/zh/operations/system-tables/index.md b/docs/zh/operations/system-tables/index.md index 56067bc5057..0e5778e3051 100644 --- a/docs/zh/operations/system-tables/index.md +++ b/docs/zh/operations/system-tables/index.md @@ -7,33 +7,33 @@ toc_title: "\u7CFB\u7EDF\u8868" # 系统表 {#system-tables} -## 导言 {#system-tables-introduction} +## 引言 {#system-tables-introduction} -系统表提供以下信息: +系统表提供的信息如下: -- 服务器状态、进程和环境。 +- 服务器的状态、进程以及环境。 - 服务器的内部进程。 系统表: -- 坐落于 `system` 数据库。 -- 仅适用于读取数据。 -- 不能删除或更改,但可以分离。 +- 存储于 `system` 数据库。 +- 仅提供数据读取功能。 +- 不能被删除或更改,但可以对其进行分离(detach)操作。 -大多数系统表将数据存储在RAM中。 ClickHouse服务器在开始时创建此类系统表。 +大多数系统表将其数据存储在RAM中。 一个ClickHouse服务在刚启动时便会创建此类系统表。 -与其他系统表不同,系统日志表 [metric_log](../../operations/system-tables/metric_log.md#system_tables-metric_log), [query_log](../../operations/system-tables/query_log.md#system_tables-query_log), [query_thread_log](../../operations/system-tables/query_thread_log.md#system_tables-query_thread_log), [trace_log](../../operations/system-tables/trace_log.md#system_tables-trace_log), [part_log](../../operations/system-tables/part_log.md#system.part_log), crash_log and text_log 默认采用[MergeTree](../../engines/table-engines/mergetree-family/mergetree.md) 引擎并将其数据存储在存储文件系统中。 如果从文件系统中删除表,ClickHouse服务器会在下一次写入数据时再次创建空表。 如果系统表架构在新版本中发生更改,则ClickHouse会重命名当前表并创建一个新表。 +不同于其他系统表,系统日志表 [metric_log](../../operations/system-tables/metric_log.md#system_tables-metric_log), [query_log](../../operations/system-tables/query_log.md#system_tables-query_log), [query_thread_log](../../operations/system-tables/query_thread_log.md#system_tables-query_thread_log), [trace_log](../../operations/system-tables/trace_log.md#system_tables-trace_log), [part_log](../../operations/system-tables/part_log.md#system.part_log), crash_log and text_log 默认采用[MergeTree](../../engines/table-engines/mergetree-family/mergetree.md) 引擎并将其数据存储在文件系统中。 如果人为的从文件系统中删除表,ClickHouse服务器会在下一次进行数据写入时再次创建空表。 如果系统表结构在新版本中发生更改,那么ClickHouse会重命名当前表并创建一个新表。 -用户可以通过在`/etc/clickhouse-server/config.d/`下创建与系统表同名的配置文件, 或者在`/etc/clickhouse-server/config.xml`中设置相应配置项,来自定义系统日志表的结构。可以自定义的配置项如下: +用户可以通过在`/etc/clickhouse-server/config.d/`下创建与系统表同名的配置文件, 或者在`/etc/clickhouse-server/config.xml`中设置相应配置项,来自定义系统日志表的结构。可供自定义的配置项如下: -- `database`: 系统日志表所在的数据库。这个选项目前已经废弃。所有的系统日表都位于`system`库中。 -- `table`: 系统日志表名。 +- `database`: 系统日志表所在的数据库。这个选项目前已经不推荐使用。所有的系统日表都位于`system`库中。 +- `table`: 接收数据写入的系统日志表。 - `partition_by`: 指定[PARTITION BY](../../engines/table-engines/mergetree-family/custom-partitioning-key.md)表达式。 - `ttl`: 指定系统日志表TTL选项。 -- `flush_interval_milliseconds`: 指定系统日志表数据落盘时间。 -- `engine`: 指定完整的表引擎定义。(以`ENGINE = `开始)。 这个选项与`partition_by`以及`ttl`冲突。如果两者一起设置,服务启动时会抛出异常并且退出。 +- `flush_interval_milliseconds`: 指定日志表数据刷新到磁盘的时间间隔。 +- `engine`: 指定完整的表引擎定义。(以`ENGINE = `开头)。 这个选项与`partition_by`以及`ttl`冲突。如果与两者一起设置,服务启动时会抛出异常并且退出。 -一个配置定义的例子如下: +配置定义的示例如下: ``` @@ -50,20 +50,20 @@ toc_title: "\u7CFB\u7EDF\u8868" ``` -默认情况下,表增长是无限的。 要控制表的大小,可以使用 TTL 删除过期日志记录的设置。 你也可以使用分区功能 `MergeTree`-发动机表。 +默认情况下,表增长是无限的。可以通过TTL 删除过期日志记录的设置来控制表的大小。 你也可以使用分区功能 `MergeTree`-引擎表。 ## 系统指标的来源 {#system-tables-sources-of-system-metrics} 用于收集ClickHouse服务器使用的系统指标: - `CAP_NET_ADMIN` 能力。 -- [procfs](https://en.wikipedia.org/wiki/Procfs) (仅在Linux中)。 +- [procfs](https://en.wikipedia.org/wiki/Procfs) (仅限于Linux)。 **procfs** -如果ClickHouse服务器没有 `CAP_NET_ADMIN` 能力,它试图回落到 `ProcfsMetricsProvider`. `ProcfsMetricsProvider` 允许收集每个查询系统指标(用于CPU和I/O)。 +如果ClickHouse服务器没有 `CAP_NET_ADMIN` 能力,那么它将试图退回到 `ProcfsMetricsProvider`. `ProcfsMetricsProvider` 允许收集每个查询系统指标(包括CPU和I/O)。 -如果系统上支持并启用procfs,ClickHouse server将收集这些指标: +如果系统上支持并启用procfs,ClickHouse server将收集如下指标: - `OSCPUVirtualTimeMicroseconds` - `OSCPUWaitMicroseconds` diff --git a/docs/zh/sql-reference/statements/create.md b/docs/zh/sql-reference/statements/create.md index 639af0841dc..46e82bd1733 100644 --- a/docs/zh/sql-reference/statements/create.md +++ b/docs/zh/sql-reference/statements/create.md @@ -238,7 +238,7 @@ SELECT a, b, c FROM (SELECT ...) 当一个`SELECT`子句包含`DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`时,请注意,这些仅会在插入数据时在每个单独的数据块上执行。例如,如果你在其中包含了`GROUP BY`,则只会在查询期间进行聚合,但聚合范围仅限于单个批的写入数据。数据不会进一步被聚合。但是当你使用一些其他数据聚合引擎时这是例外的,如:`SummingMergeTree`。 -目前对物化视图执行`ALTER`是不支持的,因此这可能是不方便的。如果物化视图是使用的`TO [db.]name`的方式进行构建的,你可以使用`DETACH`语句现将视图剥离,然后使用`ALTER`运行在目标表上,然后使用`ATTACH`将之前剥离的表重新加载进来。 +目前对物化视图执行`ALTER`是不支持的,因此这可能是不方便的。如果物化视图是使用的`TO [db.]name`的方式进行构建的,你可以使用`DETACH`语句先将视图剥离,然后使用`ALTER`运行在目标表上,然后使用`ATTACH`将之前剥离的表重新加载进来。 视图看起来和普通的表相同。例如,你可以通过`SHOW TABLES`查看到它们。 diff --git a/docs/zh/sql-reference/syntax.md b/docs/zh/sql-reference/syntax.md index 8c331db1139..c05c5a1a7bf 100644 --- a/docs/zh/sql-reference/syntax.md +++ b/docs/zh/sql-reference/syntax.md @@ -14,7 +14,7 @@ INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') 含`INSERT INTO t VALUES` 的部分由完整SQL解析器处理,包含数据的部分 `(1, 'Hello, world'), (2, 'abc'), (3, 'def')` 交给快速流式解析器解析。通过设置参数 [input_format_values_interpret_expressions](../operations/settings/settings.md#settings-input_format_values_interpret_expressions),你也可以对数据部分开启完整SQL解析器。当 `input_format_values_interpret_expressions = 1` 时,CH优先采用快速流式解析器来解析数据。如果失败,CH再尝试用完整SQL解析器来处理,就像处理SQL [expression](#syntax-expressions) 一样。 -数据可以采用任何格式。当CH接受到请求时,服务端先在内存中计算不超过 [max_query_size](../operations/settings/settings.md#settings-max_query_size) 字节的请求数据(默认1 mb),然后剩下部分交给快速流式解析器。 +数据可以采用任何格式。当CH接收到请求时,服务端先在内存中计算不超过 [max_query_size](../operations/settings/settings.md#settings-max_query_size) 字节的请求数据(默认1 mb),然后剩下部分交给快速流式解析器。 这将避免在处理大型的 `INSERT`语句时出现问题。 diff --git a/programs/server/config.xml b/programs/server/config.xml index df8a5266c39..75647b10416 100644 --- a/programs/server/config.xml +++ b/programs/server/config.xml @@ -362,6 +362,20 @@ bind_dn - template used to construct the DN to bind to. The resulting DN will be constructed by replacing all '{user_name}' substrings of the template with the actual user name during each authentication attempt. + user_dn_detection - section with LDAP search parameters for detecting the actual user DN of the bound user. + This is mainly used in search filters for further role mapping when the server is Active Directory. The + resulting user DN will be used when replacing '{user_dn}' substrings wherever they are allowed. By default, + user DN is set equal to bind DN, but once search is performed, it will be updated with to the actual detected + user DN value. + base_dn - template used to construct the base DN for the LDAP search. + The resulting DN will be constructed by replacing all '{user_name}' and '{bind_dn}' substrings + of the template with the actual user name and bind DN during the LDAP search. + scope - scope of the LDAP search. + Accepted values are: 'base', 'one_level', 'children', 'subtree' (the default). + search_filter - template used to construct the search filter for the LDAP search. + The resulting filter will be constructed by replacing all '{user_name}', '{bind_dn}', and '{base_dn}' + substrings of the template with the actual user name, bind DN, and base DN during the LDAP search. + Note, that the special characters must be escaped properly in XML. verification_cooldown - a period of time, in seconds, after a successful bind attempt, during which a user will be assumed to be successfully authenticated for all consecutive requests without contacting the LDAP server. Specify 0 (the default) to disable caching and force contacting the LDAP server for each authentication request. @@ -393,6 +407,17 @@ /path/to/tls_ca_cert_dir ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384 + Example (typical Active Directory with configured user DN detection for further role mapping): + + localhost + 389 + EXAMPLE\{user_name} + + CN=Users,DC=example,DC=com + (&(objectClass=user)(sAMAccountName={user_name})) + + no + --> @@ -444,15 +469,16 @@ There can be multiple 'role_mapping' sections defined inside the same 'ldap' section. All of them will be applied. base_dn - template used to construct the base DN for the LDAP search. - The resulting DN will be constructed by replacing all '{user_name}' and '{bind_dn}' substrings - of the template with the actual user name and bind DN during each LDAP search. + The resulting DN will be constructed by replacing all '{user_name}', '{bind_dn}', and '{user_dn}' + substrings of the template with the actual user name, bind DN, and user DN during each LDAP search. scope - scope of the LDAP search. Accepted values are: 'base', 'one_level', 'children', 'subtree' (the default). search_filter - template used to construct the search filter for the LDAP search. - The resulting filter will be constructed by replacing all '{user_name}', '{bind_dn}', and '{base_dn}' - substrings of the template with the actual user name, bind DN, and base DN during each LDAP search. + The resulting filter will be constructed by replacing all '{user_name}', '{bind_dn}', '{user_dn}', and + '{base_dn}' substrings of the template with the actual user name, bind DN, user DN, and base DN during + each LDAP search. Note, that the special characters must be escaped properly in XML. - attribute - attribute name whose values will be returned by the LDAP search. + attribute - attribute name whose values will be returned by the LDAP search. 'cn', by default. prefix - prefix, that will be expected to be in front of each string in the original list of strings returned by the LDAP search. Prefix will be removed from the original strings and resulting strings will be treated as local role names. Empty, by default. @@ -471,6 +497,17 @@ clickhouse_ + Example (typical Active Directory with role mapping that relies on the detected user DN): + + my_ad_server + + CN=Users,DC=example,DC=com + CN + subtree + (&(objectClass=group)(member={user_dn})) + clickhouse_ + + --> diff --git a/src/Access/ContextAccess.cpp b/src/Access/ContextAccess.cpp index 0bcaef1e441..90495a83dfc 100644 --- a/src/Access/ContextAccess.cpp +++ b/src/Access/ContextAccess.cpp @@ -143,11 +143,13 @@ ContextAccess::ContextAccess(const AccessControlManager & manager_, const Params : manager(&manager_) , params(params_) { + std::lock_guard lock{mutex}; + subscription_for_user_change = manager->subscribeForChanges( *params.user_id, [this](const UUID &, const AccessEntityPtr & entity) { UserPtr changed_user = entity ? typeid_cast(entity) : nullptr; - std::lock_guard lock{mutex}; + std::lock_guard lock2{mutex}; setUser(changed_user); }); @@ -189,7 +191,7 @@ void ContextAccess::setUser(const UserPtr & user_) const current_roles_with_admin_option = user->granted_roles.findGrantedWithAdminOption(params.current_roles); } - subscription_for_roles_changes = {}; + subscription_for_roles_changes.reset(); enabled_roles = manager->getEnabledRoles(current_roles, current_roles_with_admin_option); subscription_for_roles_changes = enabled_roles->subscribeForChanges([this](const std::shared_ptr & roles_info_) { diff --git a/src/Access/ExternalAuthenticators.cpp b/src/Access/ExternalAuthenticators.cpp index 0c4d2f417c9..d4100c4e520 100644 --- a/src/Access/ExternalAuthenticators.cpp +++ b/src/Access/ExternalAuthenticators.cpp @@ -20,13 +20,42 @@ namespace ErrorCodes namespace { -auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const String & name) +void parseLDAPSearchParams(LDAPClient::SearchParams & params, const Poco::Util::AbstractConfiguration & config, const String & prefix) +{ + const bool has_base_dn = config.has(prefix + ".base_dn"); + const bool has_search_filter = config.has(prefix + ".search_filter"); + const bool has_attribute = config.has(prefix + ".attribute"); + const bool has_scope = config.has(prefix + ".scope"); + + if (has_base_dn) + params.base_dn = config.getString(prefix + ".base_dn"); + + if (has_search_filter) + params.search_filter = config.getString(prefix + ".search_filter"); + + if (has_attribute) + params.attribute = config.getString(prefix + ".attribute"); + + if (has_scope) + { + auto scope = config.getString(prefix + ".scope"); + boost::algorithm::to_lower(scope); + + if (scope == "base") params.scope = LDAPClient::SearchParams::Scope::BASE; + else if (scope == "one_level") params.scope = LDAPClient::SearchParams::Scope::ONE_LEVEL; + else if (scope == "subtree") params.scope = LDAPClient::SearchParams::Scope::SUBTREE; + else if (scope == "children") params.scope = LDAPClient::SearchParams::Scope::CHILDREN; + else + throw Exception("Invalid value for 'scope' field of LDAP search parameters in '" + prefix + + "' section, must be one of 'base', 'one_level', 'subtree', or 'children'", ErrorCodes::BAD_ARGUMENTS); + } +} + +void parseLDAPServer(LDAPClient::Params & params, const Poco::Util::AbstractConfiguration & config, const String & name) { if (name.empty()) throw Exception("LDAP server name cannot be empty", ErrorCodes::BAD_ARGUMENTS); - LDAPClient::Params params; - const String ldap_server_config = "ldap_servers." + name; const bool has_host = config.has(ldap_server_config + ".host"); @@ -34,6 +63,7 @@ auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const Str const bool has_bind_dn = config.has(ldap_server_config + ".bind_dn"); const bool has_auth_dn_prefix = config.has(ldap_server_config + ".auth_dn_prefix"); const bool has_auth_dn_suffix = config.has(ldap_server_config + ".auth_dn_suffix"); + const bool has_user_dn_detection = config.has(ldap_server_config + ".user_dn_detection"); const bool has_verification_cooldown = config.has(ldap_server_config + ".verification_cooldown"); const bool has_enable_tls = config.has(ldap_server_config + ".enable_tls"); const bool has_tls_minimum_protocol_version = config.has(ldap_server_config + ".tls_minimum_protocol_version"); @@ -66,6 +96,17 @@ auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const Str params.bind_dn = auth_dn_prefix + "{user_name}" + auth_dn_suffix; } + if (has_user_dn_detection) + { + if (!params.user_dn_detection) + { + params.user_dn_detection.emplace(); + params.user_dn_detection->attribute = "dn"; + } + + parseLDAPSearchParams(*params.user_dn_detection, config, ldap_server_config + ".user_dn_detection"); + } + if (has_verification_cooldown) params.verification_cooldown = std::chrono::seconds{config.getUInt64(ldap_server_config + ".verification_cooldown")}; @@ -143,14 +184,10 @@ auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const Str } else params.port = (params.enable_tls == LDAPClient::Params::TLSEnable::YES ? 636 : 389); - - return params; } -auto parseKerberosParams(const Poco::Util::AbstractConfiguration & config) +void parseKerberosParams(GSSAcceptorContext::Params & params, const Poco::Util::AbstractConfiguration & config) { - GSSAcceptorContext::Params params; - Poco::Util::AbstractConfiguration::Keys keys; config.keys("kerberos", keys); @@ -180,12 +217,20 @@ auto parseKerberosParams(const Poco::Util::AbstractConfiguration & config) params.realm = config.getString("kerberos.realm", ""); params.principal = config.getString("kerberos.principal", ""); - - return params; } } +void parseLDAPRoleSearchParams(LDAPClient::RoleSearchParams & params, const Poco::Util::AbstractConfiguration & config, const String & prefix) +{ + parseLDAPSearchParams(params, config, prefix); + + const bool has_prefix = config.has(prefix + ".prefix"); + + if (has_prefix) + params.prefix = config.getString(prefix + ".prefix"); +} + void ExternalAuthenticators::reset() { std::scoped_lock lock(mutex); @@ -229,7 +274,8 @@ void ExternalAuthenticators::setConfiguration(const Poco::Util::AbstractConfigur { try { - ldap_client_params_blueprint.insert_or_assign(ldap_server_name, parseLDAPServer(config, ldap_server_name)); + ldap_client_params_blueprint.erase(ldap_server_name); + parseLDAPServer(ldap_client_params_blueprint.emplace(ldap_server_name, LDAPClient::Params{}).first->second, config, ldap_server_name); } catch (...) { @@ -240,7 +286,7 @@ void ExternalAuthenticators::setConfiguration(const Poco::Util::AbstractConfigur try { if (kerberos_keys_count > 0) - kerberos_params = parseKerberosParams(config); + parseKerberosParams(kerberos_params.emplace(), config); } catch (...) { @@ -249,7 +295,7 @@ void ExternalAuthenticators::setConfiguration(const Poco::Util::AbstractConfigur } bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const BasicCredentials & credentials, - const LDAPClient::SearchParamsList * search_params, LDAPClient::SearchResultsList * search_results) const + const LDAPClient::RoleSearchParamsList * role_search_params, LDAPClient::SearchResultsList * role_search_results) const { std::optional params; std::size_t params_hash = 0; @@ -267,9 +313,9 @@ bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const B params->password = credentials.getPassword(); params->combineCoreHash(params_hash); - if (search_params) + if (role_search_params) { - for (const auto & params_instance : *search_params) + for (const auto & params_instance : *role_search_params) { params_instance.combineHash(params_hash); } @@ -301,14 +347,14 @@ bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const B // Ensure that search_params are compatible. ( - search_params == nullptr ? - entry.last_successful_search_results.empty() : - search_params->size() == entry.last_successful_search_results.size() + role_search_params == nullptr ? + entry.last_successful_role_search_results.empty() : + role_search_params->size() == entry.last_successful_role_search_results.size() ) ) { - if (search_results) - *search_results = entry.last_successful_search_results; + if (role_search_results) + *role_search_results = entry.last_successful_role_search_results; return true; } @@ -326,7 +372,7 @@ bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const B } LDAPSimpleAuthClient client(params.value()); - const auto result = client.authenticate(search_params, search_results); + const auto result = client.authenticate(role_search_params, role_search_results); const auto current_check_timestamp = std::chrono::steady_clock::now(); // Update the cache, but only if this is the latest check and the server is still configured in a compatible way. @@ -345,9 +391,9 @@ bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const B std::size_t new_params_hash = 0; new_params.combineCoreHash(new_params_hash); - if (search_params) + if (role_search_params) { - for (const auto & params_instance : *search_params) + for (const auto & params_instance : *role_search_params) { params_instance.combineHash(new_params_hash); } @@ -363,17 +409,17 @@ bool ExternalAuthenticators::checkLDAPCredentials(const String & server, const B entry.last_successful_params_hash = params_hash; entry.last_successful_authentication_timestamp = current_check_timestamp; - if (search_results) - entry.last_successful_search_results = *search_results; + if (role_search_results) + entry.last_successful_role_search_results = *role_search_results; else - entry.last_successful_search_results.clear(); + entry.last_successful_role_search_results.clear(); } else if ( entry.last_successful_params_hash != params_hash || ( - search_params == nullptr ? - !entry.last_successful_search_results.empty() : - search_params->size() != entry.last_successful_search_results.size() + role_search_params == nullptr ? + !entry.last_successful_role_search_results.empty() : + role_search_params->size() != entry.last_successful_role_search_results.size() ) ) { diff --git a/src/Access/ExternalAuthenticators.h b/src/Access/ExternalAuthenticators.h index c8feea7eada..24f1f7b6528 100644 --- a/src/Access/ExternalAuthenticators.h +++ b/src/Access/ExternalAuthenticators.h @@ -34,7 +34,7 @@ public: // The name and readiness of the credentials must be verified before calling these. bool checkLDAPCredentials(const String & server, const BasicCredentials & credentials, - const LDAPClient::SearchParamsList * search_params = nullptr, LDAPClient::SearchResultsList * search_results = nullptr) const; + const LDAPClient::RoleSearchParamsList * role_search_params = nullptr, LDAPClient::SearchResultsList * role_search_results = nullptr) const; bool checkKerberosCredentials(const String & realm, const GSSAcceptorContext & credentials) const; GSSAcceptorContext::Params getKerberosParams() const; @@ -44,7 +44,7 @@ private: { std::size_t last_successful_params_hash = 0; std::chrono::steady_clock::time_point last_successful_authentication_timestamp; - LDAPClient::SearchResultsList last_successful_search_results; + LDAPClient::SearchResultsList last_successful_role_search_results; }; using LDAPCache = std::unordered_map; // user name -> cache entry @@ -58,4 +58,6 @@ private: std::optional kerberos_params; }; +void parseLDAPRoleSearchParams(LDAPClient::RoleSearchParams & params, const Poco::Util::AbstractConfiguration & config, const String & prefix); + } diff --git a/src/Access/LDAPAccessStorage.cpp b/src/Access/LDAPAccessStorage.cpp index b47a9b3e041..c1d54e8c9aa 100644 --- a/src/Access/LDAPAccessStorage.cpp +++ b/src/Access/LDAPAccessStorage.cpp @@ -68,34 +68,15 @@ void LDAPAccessStorage::setConfiguration(AccessControlManager * access_control_m common_roles_cfg.insert(role_names.begin(), role_names.end()); } - LDAPClient::SearchParamsList role_search_params_cfg; + LDAPClient::RoleSearchParamsList role_search_params_cfg; if (has_role_mapping) { Poco::Util::AbstractConfiguration::Keys all_keys; config.keys(prefix, all_keys); for (const auto & key : all_keys) { - if (key != "role_mapping" && key.find("role_mapping[") != 0) - continue; - - const String rm_prefix = prefix_str + key; - const String rm_prefix_str = rm_prefix + '.'; - role_search_params_cfg.emplace_back(); - auto & rm_params = role_search_params_cfg.back(); - - rm_params.base_dn = config.getString(rm_prefix_str + "base_dn", ""); - rm_params.search_filter = config.getString(rm_prefix_str + "search_filter", ""); - rm_params.attribute = config.getString(rm_prefix_str + "attribute", "cn"); - rm_params.prefix = config.getString(rm_prefix_str + "prefix", ""); - - auto scope = config.getString(rm_prefix_str + "scope", "subtree"); - boost::algorithm::to_lower(scope); - if (scope == "base") rm_params.scope = LDAPClient::SearchParams::Scope::BASE; - else if (scope == "one_level") rm_params.scope = LDAPClient::SearchParams::Scope::ONE_LEVEL; - else if (scope == "subtree") rm_params.scope = LDAPClient::SearchParams::Scope::SUBTREE; - else if (scope == "children") rm_params.scope = LDAPClient::SearchParams::Scope::CHILDREN; - else - throw Exception("Invalid value of 'scope' field in '" + key + "' section of LDAP user directory, must be one of 'base', 'one_level', 'subtree', or 'children'", ErrorCodes::BAD_ARGUMENTS); + if (key == "role_mapping" || key.find("role_mapping[") == 0) + parseLDAPRoleSearchParams(role_search_params_cfg.emplace_back(), config, prefix_str + key); } } @@ -364,7 +345,7 @@ std::set LDAPAccessStorage::mapExternalRolesNoLock(const LDAPClient::Sea bool LDAPAccessStorage::areLDAPCredentialsValidNoLock(const User & user, const Credentials & credentials, - const ExternalAuthenticators & external_authenticators, LDAPClient::SearchResultsList & search_results) const + const ExternalAuthenticators & external_authenticators, LDAPClient::SearchResultsList & role_search_results) const { if (!credentials.isReady()) return false; @@ -373,7 +354,7 @@ bool LDAPAccessStorage::areLDAPCredentialsValidNoLock(const User & user, const C return false; if (const auto * basic_credentials = dynamic_cast(&credentials)) - return external_authenticators.checkLDAPCredentials(ldap_server_name, *basic_credentials, &role_search_params, &search_results); + return external_authenticators.checkLDAPCredentials(ldap_server_name, *basic_credentials, &role_search_params, &role_search_results); return false; } diff --git a/src/Access/LDAPAccessStorage.h b/src/Access/LDAPAccessStorage.h index ea0ab47c225..33ac9f0a914 100644 --- a/src/Access/LDAPAccessStorage.h +++ b/src/Access/LDAPAccessStorage.h @@ -68,12 +68,12 @@ private: void updateAssignedRolesNoLock(const UUID & id, const String & user_name, const LDAPClient::SearchResultsList & external_roles) const; std::set mapExternalRolesNoLock(const LDAPClient::SearchResultsList & external_roles) const; bool areLDAPCredentialsValidNoLock(const User & user, const Credentials & credentials, - const ExternalAuthenticators & external_authenticators, LDAPClient::SearchResultsList & search_results) const; + const ExternalAuthenticators & external_authenticators, LDAPClient::SearchResultsList & role_search_results) const; mutable std::recursive_mutex mutex; AccessControlManager * access_control_manager = nullptr; String ldap_server_name; - LDAPClient::SearchParamsList role_search_params; + LDAPClient::RoleSearchParamsList role_search_params; std::set common_role_names; // role name that should be granted to all users at all times mutable std::map external_role_hashes; // user name -> LDAPClient::SearchResultsList hash (most recently retrieved and processed) mutable std::map> users_per_roles; // role name -> user names (...it should be granted to; may but don't have to exist for common roles) diff --git a/src/Access/LDAPClient.cpp b/src/Access/LDAPClient.cpp index 5c4b7dd8d99..a8f9675774b 100644 --- a/src/Access/LDAPClient.cpp +++ b/src/Access/LDAPClient.cpp @@ -32,6 +32,11 @@ void LDAPClient::SearchParams::combineHash(std::size_t & seed) const boost::hash_combine(seed, static_cast(scope)); boost::hash_combine(seed, search_filter); boost::hash_combine(seed, attribute); +} + +void LDAPClient::RoleSearchParams::combineHash(std::size_t & seed) const +{ + SearchParams::combineHash(seed); boost::hash_combine(seed, prefix); } @@ -42,6 +47,9 @@ void LDAPClient::Params::combineCoreHash(std::size_t & seed) const boost::hash_combine(seed, bind_dn); boost::hash_combine(seed, user); boost::hash_combine(seed, password); + + if (user_dn_detection) + user_dn_detection->combineHash(seed); } LDAPClient::LDAPClient(const Params & params_) @@ -286,18 +294,33 @@ void LDAPClient::openConnection() if (params.enable_tls == LDAPClient::Params::TLSEnable::YES_STARTTLS) diag(ldap_start_tls_s(handle, nullptr, nullptr)); + final_user_name = escapeForLDAP(params.user); + final_bind_dn = replacePlaceholders(params.bind_dn, { {"{user_name}", final_user_name} }); + final_user_dn = final_bind_dn; // The default value... may be updated right after a successful bind. + switch (params.sasl_mechanism) { case LDAPClient::Params::SASLMechanism::SIMPLE: { - const auto escaped_user_name = escapeForLDAP(params.user); - const auto bind_dn = replacePlaceholders(params.bind_dn, { {"{user_name}", escaped_user_name} }); - ::berval cred; cred.bv_val = const_cast(params.password.c_str()); cred.bv_len = params.password.size(); - diag(ldap_sasl_bind_s(handle, bind_dn.c_str(), LDAP_SASL_SIMPLE, &cred, nullptr, nullptr, nullptr)); + diag(ldap_sasl_bind_s(handle, final_bind_dn.c_str(), LDAP_SASL_SIMPLE, &cred, nullptr, nullptr, nullptr)); + + // Once bound, run the user DN search query and update the default value, if asked. + if (params.user_dn_detection) + { + const auto user_dn_search_results = search(*params.user_dn_detection); + + if (user_dn_search_results.empty()) + throw Exception("Failed to detect user DN: empty search results", ErrorCodes::LDAP_ERROR); + + if (user_dn_search_results.size() > 1) + throw Exception("Failed to detect user DN: more than one entry in the search results", ErrorCodes::LDAP_ERROR); + + final_user_dn = *user_dn_search_results.begin(); + } break; } @@ -316,6 +339,9 @@ void LDAPClient::closeConnection() noexcept ldap_unbind_ext_s(handle, nullptr, nullptr); handle = nullptr; + final_user_name.clear(); + final_bind_dn.clear(); + final_user_dn.clear(); } LDAPClient::SearchResults LDAPClient::search(const SearchParams & search_params) @@ -333,10 +359,19 @@ LDAPClient::SearchResults LDAPClient::search(const SearchParams & search_params) case SearchParams::Scope::CHILDREN: scope = LDAP_SCOPE_CHILDREN; break; } - const auto escaped_user_name = escapeForLDAP(params.user); - const auto bind_dn = replacePlaceholders(params.bind_dn, { {"{user_name}", escaped_user_name} }); - const auto base_dn = replacePlaceholders(search_params.base_dn, { {"{user_name}", escaped_user_name}, {"{bind_dn}", bind_dn} }); - const auto search_filter = replacePlaceholders(search_params.search_filter, { {"{user_name}", escaped_user_name}, {"{bind_dn}", bind_dn}, {"{base_dn}", base_dn} }); + const auto final_base_dn = replacePlaceholders(search_params.base_dn, { + {"{user_name}", final_user_name}, + {"{bind_dn}", final_bind_dn}, + {"{user_dn}", final_user_dn} + }); + + const auto final_search_filter = replacePlaceholders(search_params.search_filter, { + {"{user_name}", final_user_name}, + {"{bind_dn}", final_bind_dn}, + {"{user_dn}", final_user_dn}, + {"{base_dn}", final_base_dn} + }); + char * attrs[] = { const_cast(search_params.attribute.c_str()), nullptr }; ::timeval timeout = { params.search_timeout.count(), 0 }; LDAPMessage* msgs = nullptr; @@ -349,7 +384,7 @@ LDAPClient::SearchResults LDAPClient::search(const SearchParams & search_params) } }); - diag(ldap_search_ext_s(handle, base_dn.c_str(), scope, search_filter.c_str(), attrs, 0, nullptr, nullptr, &timeout, params.search_limit, &msgs)); + diag(ldap_search_ext_s(handle, final_base_dn.c_str(), scope, final_search_filter.c_str(), attrs, 0, nullptr, nullptr, &timeout, params.search_limit, &msgs)); for ( auto * msg = ldap_first_message(handle, msgs); @@ -361,6 +396,27 @@ LDAPClient::SearchResults LDAPClient::search(const SearchParams & search_params) { case LDAP_RES_SEARCH_ENTRY: { + // Extract DN separately, if the requested attribute is DN. + if (boost::iequals("dn", search_params.attribute)) + { + BerElement * ber = nullptr; + + SCOPE_EXIT({ + if (ber) + { + ber_free(ber, 0); + ber = nullptr; + } + }); + + ::berval bv; + + diag(ldap_get_dn_ber(handle, msg, &ber, &bv)); + + if (bv.bv_val && bv.bv_len > 0) + result.emplace(bv.bv_val, bv.bv_len); + } + BerElement * ber = nullptr; SCOPE_EXIT({ @@ -471,12 +527,12 @@ LDAPClient::SearchResults LDAPClient::search(const SearchParams & search_params) return result; } -bool LDAPSimpleAuthClient::authenticate(const SearchParamsList * search_params, SearchResultsList * search_results) +bool LDAPSimpleAuthClient::authenticate(const RoleSearchParamsList * role_search_params, SearchResultsList * role_search_results) { if (params.user.empty()) throw Exception("LDAP authentication of a user with empty name is not allowed", ErrorCodes::BAD_ARGUMENTS); - if (!search_params != !search_results) + if (!role_search_params != !role_search_results) throw Exception("Cannot return LDAP search results", ErrorCodes::BAD_ARGUMENTS); // Silently reject authentication attempt if the password is empty as if it didn't match. @@ -489,21 +545,21 @@ bool LDAPSimpleAuthClient::authenticate(const SearchParamsList * search_params, openConnection(); // While connected, run search queries and save the results, if asked. - if (search_params) + if (role_search_params) { - search_results->clear(); - search_results->reserve(search_params->size()); + role_search_results->clear(); + role_search_results->reserve(role_search_params->size()); try { - for (const auto & single_search_params : *search_params) + for (const auto & params_instance : *role_search_params) { - search_results->emplace_back(search(single_search_params)); + role_search_results->emplace_back(search(params_instance)); } } catch (...) { - search_results->clear(); + role_search_results->clear(); throw; } } @@ -532,7 +588,7 @@ LDAPClient::SearchResults LDAPClient::search(const SearchParams &) throw Exception("ClickHouse was built without LDAP support", ErrorCodes::FEATURE_IS_NOT_ENABLED_AT_BUILD_TIME); } -bool LDAPSimpleAuthClient::authenticate(const SearchParamsList *, SearchResultsList *) +bool LDAPSimpleAuthClient::authenticate(const RoleSearchParamsList *, SearchResultsList *) { throw Exception("ClickHouse was built without LDAP support", ErrorCodes::FEATURE_IS_NOT_ENABLED_AT_BUILD_TIME); } diff --git a/src/Access/LDAPClient.h b/src/Access/LDAPClient.h index 4fc97bb957b..388e7ad0f0d 100644 --- a/src/Access/LDAPClient.h +++ b/src/Access/LDAPClient.h @@ -38,12 +38,20 @@ public: Scope scope = Scope::SUBTREE; String search_filter; String attribute = "cn"; + + void combineHash(std::size_t & seed) const; + }; + + struct RoleSearchParams + : public SearchParams + { String prefix; void combineHash(std::size_t & seed) const; }; - using SearchParamsList = std::vector; + using RoleSearchParamsList = std::vector; + using SearchResults = std::set; using SearchResultsList = std::vector; @@ -105,6 +113,8 @@ public: String user; String password; + std::optional user_dn_detection; + std::chrono::seconds verification_cooldown{0}; std::chrono::seconds operation_timeout{40}; @@ -134,6 +144,9 @@ protected: #if USE_LDAP LDAP * handle = nullptr; #endif + String final_user_name; + String final_bind_dn; + String final_user_dn; }; class LDAPSimpleAuthClient @@ -141,7 +154,7 @@ class LDAPSimpleAuthClient { public: using LDAPClient::LDAPClient; - bool authenticate(const SearchParamsList * search_params, SearchResultsList * search_results); + bool authenticate(const RoleSearchParamsList * role_search_params, SearchResultsList * role_search_results); }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d22a69c211c..a0f36163d68 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,8 +106,8 @@ endif() list (APPEND clickhouse_common_io_sources ${CONFIG_BUILD}) list (APPEND clickhouse_common_io_headers ${CONFIG_VERSION} ${CONFIG_COMMON}) -list (APPEND dbms_sources Functions/IFunction.cpp Functions/IFunctionOld.cpp Functions/FunctionFactory.cpp Functions/FunctionHelpers.cpp Functions/extractTimeZoneFromFunctionArguments.cpp Functions/replicate.cpp Functions/FunctionsLogical.cpp) -list (APPEND dbms_headers Functions/IFunctionOld.h Functions/FunctionFactory.h Functions/FunctionHelpers.h Functions/extractTimeZoneFromFunctionArguments.h Functions/replicate.h Functions/FunctionsLogical.h) +list (APPEND dbms_sources Functions/IFunction.cpp Functions/FunctionFactory.cpp Functions/FunctionHelpers.cpp Functions/extractTimeZoneFromFunctionArguments.cpp Functions/replicate.cpp Functions/FunctionsLogical.cpp) +list (APPEND dbms_headers Functions/IFunction.h Functions/FunctionFactory.h Functions/FunctionHelpers.h Functions/extractTimeZoneFromFunctionArguments.h Functions/replicate.h Functions/FunctionsLogical.h) list (APPEND dbms_sources AggregateFunctions/AggregateFunctionFactory.cpp diff --git a/src/Common/HashTable/LRUHashMap.h b/src/Common/HashTable/LRUHashMap.h index 870fb219523..bdefee351b1 100644 --- a/src/Common/HashTable/LRUHashMap.h +++ b/src/Common/HashTable/LRUHashMap.h @@ -220,6 +220,12 @@ public: return find(key) != nullptr; } + Value & ALWAYS_INLINE operator[](const Key & key) + { + auto [it, _] = emplace(key); + return it->getMapped(); + } + bool ALWAYS_INLINE erase(const Key & key) { auto key_hash = Base::hash(key); diff --git a/src/Common/examples/CMakeLists.txt b/src/Common/examples/CMakeLists.txt index 0395cb32438..c94ce580942 100644 --- a/src/Common/examples/CMakeLists.txt +++ b/src/Common/examples/CMakeLists.txt @@ -36,7 +36,7 @@ add_executable (arena_with_free_lists arena_with_free_lists.cpp) target_link_libraries (arena_with_free_lists PRIVATE dbms) add_executable (lru_hash_map_perf lru_hash_map_perf.cpp) -target_link_libraries (lru_hash_map_perf PRIVATE clickhouse_common_io) +target_link_libraries (lru_hash_map_perf PRIVATE dbms) add_executable (thread_creation_latency thread_creation_latency.cpp) target_link_libraries (thread_creation_latency PRIVATE clickhouse_common_io) diff --git a/src/Common/examples/lru_hash_map_perf.cpp b/src/Common/examples/lru_hash_map_perf.cpp index 14beff3f7da..c40548bea49 100644 --- a/src/Common/examples/lru_hash_map_perf.cpp +++ b/src/Common/examples/lru_hash_map_perf.cpp @@ -7,23 +7,26 @@ #include #include +#include +#include + template class LRUHashMapBasic { public: using key_type = Key; using value_type = Value; - using list_type = std::list; - using node = std::pair; - using map_type = std::unordered_map>; + using list_type = std::list>; + using map_type = std::unordered_map; - LRUHashMapBasic(size_t max_size_, bool preallocated) + LRUHashMapBasic(size_t max_size_, bool preallocated = false) : hash_map(preallocated ? max_size_ : 32) , max_size(max_size_) { } - void insert(const Key &key, const Value &value) + template + std::pair emplace(const Key &key, Args &&... args) { auto it = hash_map.find(key); @@ -33,40 +36,39 @@ public: { auto iterator_to_remove = list.begin(); - hash_map.erase(*iterator_to_remove); + auto & key_to_remove = iterator_to_remove->first; + hash_map.erase(key_to_remove); + list.erase(iterator_to_remove); } - list.push_back(key); - hash_map[key] = std::make_pair(value, --list.end()); + + Value value(std::forward(args)...); + auto node = std::make_pair(key, std::move(value)); + + list.push_back(std::move(node)); + + auto inserted_iterator = --list.end(); + + hash_map[key] = inserted_iterator; + + return std::make_pair(&inserted_iterator->second, true); } else { - auto & [value_to_update, iterator_in_list_to_update] = it->second; + auto & iterator_in_list_to_update = it->second; list.splice(list.end(), list, iterator_in_list_to_update); + iterator_in_list_to_update = --list.end(); - iterator_in_list_to_update = list.end(); - value_to_update = value; + return std::make_pair(&iterator_in_list_to_update->second, false); } } - value_type & get(const key_type &key) + value_type & operator[](const key_type & key) { - auto iterator_in_map = hash_map.find(key); - assert(iterator_in_map != hash_map.end()); - - auto & [value_to_return, iterator_in_list_to_update] = iterator_in_map->second; - - list.splice(list.end(), list, iterator_in_list_to_update); - iterator_in_list_to_update = list.end(); - - return value_to_return; - } - - const value_type & get(const key_type & key) const - { - return const_cast *>(this)->get(key); + auto [it, _] = emplace(key); + return *it; } size_t getMaxSize() const @@ -101,110 +103,45 @@ private: size_t max_size; }; -std::vector generateNumbersToInsert(size_t numbers_to_insert_size) +template +static void NO_INLINE test(const Key * data, size_t size, const std::string & name) { - std::vector numbers; - numbers.reserve(numbers_to_insert_size); - - std::random_device rd; - pcg64 gen(rd()); - - UInt64 min = std::numeric_limits::min(); - UInt64 max = std::numeric_limits::max(); - - auto distribution = std::uniform_int_distribution<>(min, max); - - for (size_t i = 0; i < numbers_to_insert_size; ++i) - { - UInt64 number = distribution(gen); - numbers.emplace_back(number); - } - - return numbers; -} - -void testInsertElementsIntoHashMap(size_t map_size, const std::vector & numbers_to_insert, bool preallocated) -{ - size_t numbers_to_insert_size = numbers_to_insert.size(); - std::cout << "TestInsertElementsIntoHashMap preallocated map size: " << map_size << " numbers to insert size: " << numbers_to_insert_size; - std::cout << std::endl; - - HashMap hash_map(preallocated ? map_size : 32); - + size_t cache_size = size / 10; + Map cache(cache_size); Stopwatch watch; - for (size_t i = 0; i < numbers_to_insert_size; ++i) - hash_map.insert({ numbers_to_insert[i], numbers_to_insert[i] }); + for (size_t i = 0; i < size; ++i) + ++cache[data[i]]; - std::cout << "Inserted in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; + watch.stop(); - UInt64 summ = 0; - - for (size_t i = 0; i < numbers_to_insert_size; ++i) - { - auto * it = hash_map.find(numbers_to_insert[i]); - - if (it) - summ += it->getMapped(); - } - - std::cout << "Calculated summ: " << summ << " in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; + std::cerr << name + << ":\nElapsed: " << watch.elapsedSeconds() + << " (" << size / watch.elapsedSeconds() << " elem/sec.)" + << ", map size: " << cache.size() << "\n"; } -void testInsertElementsIntoStandardMap(size_t map_size, const std::vector & numbers_to_insert, bool preallocated) +template +static void NO_INLINE testForType(size_t method, size_t rows_size) { - size_t numbers_to_insert_size = numbers_to_insert.size(); - std::cout << "TestInsertElementsIntoStandardMap map size: " << map_size << " numbers to insert size: " << numbers_to_insert_size; - std::cout << std::endl; + std::cerr << std::fixed << std::setprecision(3); - std::unordered_map hash_map(preallocated ? map_size : 32); + std::vector data(rows_size); - Stopwatch watch; - - for (size_t i = 0; i < numbers_to_insert_size; ++i) - hash_map.insert({ numbers_to_insert[i], numbers_to_insert[i] }); - - std::cout << "Inserted in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; - - UInt64 summ = 0; - - for (size_t i = 0; i < numbers_to_insert_size; ++i) { - auto it = hash_map.find(numbers_to_insert[i]); - - if (it != hash_map.end()) - summ += it->second; + DB::ReadBufferFromFileDescriptor in1(STDIN_FILENO); + DB::CompressedReadBuffer in2(in1); + in2.readStrict(reinterpret_cast(data.data()), sizeof(data[0]) * rows_size); } - std::cout << "Calculated summ: " << summ << " in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; -} - -template -UInt64 testInsertIntoEmptyCache(size_t map_size, const std::vector & numbers_to_insert, bool preallocated) -{ - size_t numbers_to_insert_size = numbers_to_insert.size(); - std::cout << "Test testInsertPreallocated preallocated map size: " << map_size << " numbers to insert size: " << numbers_to_insert_size; - std::cout << std::endl; - - LRUCache cache(map_size, preallocated); - Stopwatch watch; - - for (size_t i = 0; i < numbers_to_insert_size; ++i) + if (method == 0) { - cache.insert(numbers_to_insert[i], numbers_to_insert[i]); + test>(data.data(), data.size(), "CH HashMap"); + } + else if (method == 1) + { + test>(data.data(), data.size(), "BasicLRU"); } - - std::cout << "Inserted in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; - - UInt64 summ = 0; - - for (size_t i = 0; i < numbers_to_insert_size; ++i) - if (cache.contains(numbers_to_insert[i])) - summ += cache.get(numbers_to_insert[i]); - - std::cout << "Calculated summ: " << summ << " in " << watch.elapsedMilliseconds() << " milliseconds" << std::endl; - - return summ; } int main(int argc, char ** argv) @@ -212,33 +149,34 @@ int main(int argc, char ** argv) (void)(argc); (void)(argv); - size_t hash_map_size = 1200000; - size_t numbers_to_insert_size = 12000000; - std::vector numbers = generateNumbersToInsert(numbers_to_insert_size); + if (argc < 4) + { + std::cerr << "Usage: program method column_type_name rows_count < input_column.bin \n"; + return 1; + } - std::cout << "Test insert into HashMap preallocated=0" << std::endl; - testInsertElementsIntoHashMap(hash_map_size, numbers, true); - std::cout << std::endl; + size_t method = std::stoull(argv[1]); + std::string type_name = std::string(argv[2]); + size_t n = std::stoull(argv[3]); - std::cout << "Test insert into HashMap preallocated=1" << std::endl; - testInsertElementsIntoHashMap(hash_map_size, numbers, true); - std::cout << std::endl; - - std::cout << "Test LRUHashMap preallocated=0" << std::endl; - testInsertIntoEmptyCache>(hash_map_size, numbers, false); - std::cout << std::endl; - - std::cout << "Test LRUHashMap preallocated=1" << std::endl; - testInsertIntoEmptyCache>(hash_map_size, numbers, true); - std::cout << std::endl; - - std::cout << "Test LRUHashMapBasic preallocated=0" << std::endl; - testInsertIntoEmptyCache>(hash_map_size, numbers, false); - std::cout << std::endl; - - std::cout << "Test LRUHashMapBasic preallocated=1" << std::endl; - testInsertIntoEmptyCache>(hash_map_size, numbers, true); - std::cout << std::endl; + if (type_name == "UInt8") + testForType(method, n); + else if (type_name == "UInt16") + testForType(method, n); + else if (type_name == "UInt32") + testForType(method, n); + else if (type_name == "UInt64") + testForType(method, n); + else if (type_name == "Int8") + testForType(method, n); + else if (type_name == "Int16") + testForType(method, n); + else if (type_name == "Int32") + testForType(method, n); + else if (type_name == "Int64") + testForType(method, n); + else + std::cerr << "Unexpected type passed " << type_name << std::endl; return 0; } diff --git a/src/Common/isLocalAddress.cpp b/src/Common/isLocalAddress.cpp index 8da281e3051..cecff489a22 100644 --- a/src/Common/isLocalAddress.cpp +++ b/src/Common/isLocalAddress.cpp @@ -1,29 +1,84 @@ #include +#include #include +#include #include -#include -#include +#include +#include #include namespace DB { +namespace ErrorCodes +{ + extern const int SYSTEM_ERROR; +} + +namespace +{ + +struct NetworkInterfaces +{ + ifaddrs * ifaddr; + NetworkInterfaces() + { + if (getifaddrs(&ifaddr) == -1) + { + throwFromErrno("Cannot getifaddrs", ErrorCodes::SYSTEM_ERROR); + } + } + + bool hasAddress(const Poco::Net::IPAddress & address) const + { + ifaddrs * iface; + for (iface = ifaddr; iface != nullptr; iface = iface->ifa_next) + { + auto family = iface->ifa_addr->sa_family; + std::optional interface_address; + switch (family) + { + /// We interested only in IP-adresses + case AF_INET: + { + interface_address.emplace(*(iface->ifa_addr)); + break; + } + case AF_INET6: + { + interface_address.emplace(&reinterpret_cast(iface->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + break; + } + default: + continue; + } + + /** Compare the addresses without taking into account `scope`. + * Theoretically, this may not be correct - depends on `route` setting + * - through which interface we will actually access the specified address. + */ + if (interface_address->length() == address.length() + && 0 == memcmp(interface_address->addr(), address.addr(), address.length())) + return true; + } + return false; + } + + ~NetworkInterfaces() + { + freeifaddrs(ifaddr); + } +}; + +} + + bool isLocalAddress(const Poco::Net::IPAddress & address) { - static auto interfaces = Poco::Net::NetworkInterface::list(); - - return interfaces.end() != std::find_if(interfaces.begin(), interfaces.end(), - [&] (const Poco::Net::NetworkInterface & interface) - { - /** Compare the addresses without taking into account `scope`. - * Theoretically, this may not be correct - depends on `route` setting - * - through which interface we will actually access the specified address. - */ - return interface.address().length() == address.length() - && 0 == memcmp(interface.address().addr(), address.addr(), address.length()); - }); + NetworkInterfaces interfaces; + return interfaces.hasAddress(address); } bool isLocalAddress(const Poco::Net::SocketAddress & address, UInt16 clickhouse_port) diff --git a/src/Common/tests/gtest_local_address.cpp b/src/Common/tests/gtest_local_address.cpp new file mode 100644 index 00000000000..504fba19713 --- /dev/null +++ b/src/Common/tests/gtest_local_address.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + + +TEST(LocalAddress, SmokeTest) +{ + auto cmd = DB::ShellCommand::executeDirect("/bin/hostname", {"-i"}); + std::string address_str; + DB::readString(address_str, cmd->out); + cmd->wait(); + std::cerr << "Got Address:" << address_str << std::endl; + + Poco::Net::IPAddress address(address_str); + + EXPECT_TRUE(DB::isLocalAddress(address)); +} diff --git a/src/Compression/tests/gtest_compressionCodec.cpp b/src/Compression/tests/gtest_compressionCodec.cpp index 20fe5476807..6ba2d3457ea 100644 --- a/src/Compression/tests/gtest_compressionCodec.cpp +++ b/src/Compression/tests/gtest_compressionCodec.cpp @@ -345,10 +345,12 @@ CodecTestSequence operator*(CodecTestSequence && left, T times) std::ostream & operator<<(std::ostream & ostr, const Codec & codec) { - return ostr << "Codec{" - << "name: " << codec.codec_statement - << ", expected_compression_ratio: " << *codec.expected_compression_ratio - << "}"; + ostr << "Codec{" + << "name: " << codec.codec_statement; + if (codec.expected_compression_ratio) + return ostr << ", expected_compression_ratio: " << *codec.expected_compression_ratio << "}"; + else + return ostr << "}"; } std::ostream & operator<<(std::ostream & ostr, const CodecTestSequence & seq) diff --git a/src/DataTypes/DataTypeDateTime64.h b/src/DataTypes/DataTypeDateTime64.h index f51e0f5d047..ac0f49613a2 100644 --- a/src/DataTypes/DataTypeDateTime64.h +++ b/src/DataTypes/DataTypeDateTime64.h @@ -35,6 +35,8 @@ public: bool canBePromoted() const override { return false; } + bool canBeUsedAsVersion() const override { return true; } + protected: SerializationPtr doGetDefaultSerialization() const override; }; diff --git a/src/DataTypes/DataTypeUUID.h b/src/DataTypes/DataTypeUUID.h index 70104a03478..5ed7a912607 100644 --- a/src/DataTypes/DataTypeUUID.h +++ b/src/DataTypes/DataTypeUUID.h @@ -35,6 +35,7 @@ public: bool textCanContainOnlyValidUTF8() const override { return true; } bool isComparable() const override { return true; } bool isValueUnambiguouslyRepresentedInContiguousMemoryRegion() const override { return true; } + bool isValueUnambiguouslyRepresentedInFixedSizeContiguousMemoryRegion() const override { return true; } bool haveMaximumSizeOfValue() const override { return true; } size_t getSizeOfValueInMemory() const override { return sizeof(UUID); } bool isCategorial() const override { return true; } diff --git a/src/DataTypes/IDataType.h b/src/DataTypes/IDataType.h index 4602083f488..85526cd98de 100644 --- a/src/DataTypes/IDataType.h +++ b/src/DataTypes/IDataType.h @@ -177,7 +177,7 @@ public: */ virtual bool canBeComparedWithCollation() const { return false; } - /** If the type is totally comparable (Ints, Date, DateTime, not nullable, not floats) + /** If the type is totally comparable (Ints, Date, DateTime, DateTime64, not nullable, not floats) * and "simple" enough (not String, FixedString) to be used as version number * (to select rows with maximum version). */ diff --git a/src/Databases/DatabaseLazy.cpp b/src/Databases/DatabaseLazy.cpp index d498cb96062..80179de104a 100644 --- a/src/Databases/DatabaseLazy.cpp +++ b/src/Databases/DatabaseLazy.cpp @@ -203,7 +203,7 @@ void DatabaseLazy::shutdown() for (const auto & kv : tables_snapshot) { if (kv.second.table) - kv.second.table->shutdown(); + kv.second.table->flushAndShutdown(); } std::lock_guard lock(mutex); diff --git a/src/Databases/DatabaseReplicated.cpp b/src/Databases/DatabaseReplicated.cpp index b7214917ce8..d36fe45f748 100644 --- a/src/Databases/DatabaseReplicated.cpp +++ b/src/Databases/DatabaseReplicated.cpp @@ -529,7 +529,7 @@ void DatabaseReplicated::recoverLostReplica(const ZooKeeperPtr & current_zookeep dropped_tables.push_back(tryGetTableUUID(table_name)); dropped_dictionaries += table->isDictionary(); - table->shutdown(); + table->flushAndShutdown(); DatabaseAtomic::dropTable(getContext(), table_name, true); } else diff --git a/src/Databases/DatabasesCommon.cpp b/src/Databases/DatabasesCommon.cpp index 9329b0a4210..9d79a0dfe96 100644 --- a/src/Databases/DatabasesCommon.cpp +++ b/src/Databases/DatabasesCommon.cpp @@ -125,10 +125,15 @@ void DatabaseWithOwnTablesBase::shutdown() tables_snapshot = tables; } + for (const auto & kv : tables_snapshot) + { + kv.second->flush(); + } + for (const auto & kv : tables_snapshot) { auto table_id = kv.second->getStorageID(); - kv.second->shutdown(); + kv.second->flushAndShutdown(); if (table_id.hasUUID()) { assert(getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE || getUUID() != UUIDHelpers::Nil); diff --git a/src/Databases/MySQL/DatabaseConnectionMySQL.cpp b/src/Databases/MySQL/DatabaseConnectionMySQL.cpp index 59a575996ee..5cd59f8a7c8 100644 --- a/src/Databases/MySQL/DatabaseConnectionMySQL.cpp +++ b/src/Databases/MySQL/DatabaseConnectionMySQL.cpp @@ -316,7 +316,7 @@ void DatabaseConnectionMySQL::shutdown() } for (const auto & [table_name, modify_time_and_storage] : tables_snapshot) - modify_time_and_storage.second->shutdown(); + modify_time_and_storage.second->flushAndShutdown(); std::lock_guard lock(mutex); local_tables_cache.clear(); @@ -343,7 +343,7 @@ void DatabaseConnectionMySQL::cleanOutdatedTables() { const auto table_lock = (*iterator)->lockExclusively(RWLockImpl::NO_QUERY, lock_acquire_timeout); - (*iterator)->shutdown(); + (*iterator)->flushAndShutdown(); (*iterator)->is_dropped = true; iterator = outdated_tables.erase(iterator); } diff --git a/src/Functions/CMakeLists.txt b/src/Functions/CMakeLists.txt index ba876e02424..271deb0f42c 100644 --- a/src/Functions/CMakeLists.txt +++ b/src/Functions/CMakeLists.txt @@ -5,8 +5,8 @@ add_subdirectory(divide) include("${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake") add_headers_and_sources(clickhouse_functions .) -list(REMOVE_ITEM clickhouse_functions_sources IFunctionOld.cpp FunctionFactory.cpp FunctionHelpers.cpp) -list(REMOVE_ITEM clickhouse_functions_headers IFunctionOld.h FunctionFactory.h FunctionHelpers.h) +list(REMOVE_ITEM clickhouse_functions_sources IFunction.cpp FunctionFactory.cpp FunctionHelpers.cpp) +list(REMOVE_ITEM clickhouse_functions_headers IFunction.h FunctionFactory.h FunctionHelpers.h) add_library(clickhouse_functions ${clickhouse_functions_sources}) diff --git a/src/Functions/CustomWeekTransforms.h b/src/Functions/CustomWeekTransforms.h index f07f2777cec..d1a8e3a54fd 100644 --- a/src/Functions/CustomWeekTransforms.h +++ b/src/Functions/CustomWeekTransforms.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/DateTimeTransforms.h b/src/Functions/DateTimeTransforms.h index aa8f52b335e..03f35333150 100644 --- a/src/Functions/DateTimeTransforms.h +++ b/src/Functions/DateTimeTransforms.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionBinaryArithmetic.h b/src/Functions/FunctionBinaryArithmetic.h index 0d90eece3e2..927b870891f 100644 --- a/src/Functions/FunctionBinaryArithmetic.h +++ b/src/Functions/FunctionBinaryArithmetic.h @@ -23,7 +23,7 @@ #include #include #include "Core/DecimalFunctions.h" -#include "IFunctionOld.h" +#include "IFunction.h" #include "FunctionHelpers.h" #include "IsOperation.h" #include "DivisionUtils.h" diff --git a/src/Functions/FunctionBitTestMany.h b/src/Functions/FunctionBitTestMany.h index 6ed787d707e..567be37cda8 100644 --- a/src/Functions/FunctionBitTestMany.h +++ b/src/Functions/FunctionBitTestMany.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionCustomWeekToSomething.h b/src/Functions/FunctionCustomWeekToSomething.h index c229764b8a4..0ef6a342218 100644 --- a/src/Functions/FunctionCustomWeekToSomething.h +++ b/src/Functions/FunctionCustomWeekToSomething.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionDateOrDateTimeAddInterval.h b/src/Functions/FunctionDateOrDateTimeAddInterval.h index d0b05c83eaa..14ab9f00452 100644 --- a/src/Functions/FunctionDateOrDateTimeAddInterval.h +++ b/src/Functions/FunctionDateOrDateTimeAddInterval.h @@ -7,7 +7,7 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionDateOrDateTimeToSomething.h b/src/Functions/FunctionDateOrDateTimeToSomething.h index ded6c157433..8b8f1b483c8 100644 --- a/src/Functions/FunctionDateOrDateTimeToSomething.h +++ b/src/Functions/FunctionDateOrDateTimeToSomething.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionFQDN.cpp b/src/Functions/FunctionFQDN.cpp index 439181862a7..304aad17d22 100644 --- a/src/Functions/FunctionFQDN.cpp +++ b/src/Functions/FunctionFQDN.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/FunctionFactory.h b/src/Functions/FunctionFactory.h index 966ee2df952..bac55dade16 100644 --- a/src/Functions/FunctionFactory.h +++ b/src/Functions/FunctionFactory.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/src/Functions/FunctionHelpers.cpp b/src/Functions/FunctionHelpers.cpp index 8fc21fc0c57..dcdd0e521eb 100644 --- a/src/Functions/FunctionHelpers.cpp +++ b/src/Functions/FunctionHelpers.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionIfBase.h b/src/Functions/FunctionIfBase.h index 32f0f629287..17d02de2e27 100644 --- a/src/Functions/FunctionIfBase.h +++ b/src/Functions/FunctionIfBase.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #if !defined(ARCADIA_BUILD) diff --git a/src/Functions/FunctionMathBinaryFloat64.h b/src/Functions/FunctionMathBinaryFloat64.h index 2f43981f751..8cc012d3ab2 100644 --- a/src/Functions/FunctionMathBinaryFloat64.h +++ b/src/Functions/FunctionMathBinaryFloat64.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #if !defined(ARCADIA_BUILD) diff --git a/src/Functions/FunctionMathConstFloat64.h b/src/Functions/FunctionMathConstFloat64.h index f983988a9ae..ab7d401e99e 100644 --- a/src/Functions/FunctionMathConstFloat64.h +++ b/src/Functions/FunctionMathConstFloat64.h @@ -2,7 +2,7 @@ #include #include -#include +#include namespace DB diff --git a/src/Functions/FunctionMathUnary.h b/src/Functions/FunctionMathUnary.h index 5f310e2d8f8..a637bbe3bd8 100644 --- a/src/Functions/FunctionMathUnary.h +++ b/src/Functions/FunctionMathUnary.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #if !defined(ARCADIA_BUILD) diff --git a/src/Functions/FunctionNumericPredicate.h b/src/Functions/FunctionNumericPredicate.h index d27739c28de..d5fa9f03aba 100644 --- a/src/Functions/FunctionNumericPredicate.h +++ b/src/Functions/FunctionNumericPredicate.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/FunctionStartsEndsWith.h b/src/Functions/FunctionStartsEndsWith.h index ead22ab15d1..65dbf393290 100644 --- a/src/Functions/FunctionStartsEndsWith.h +++ b/src/Functions/FunctionStartsEndsWith.h @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionStringOrArrayToT.h b/src/Functions/FunctionStringOrArrayToT.h index 1e163b2ebef..158179fffe9 100644 --- a/src/Functions/FunctionStringOrArrayToT.h +++ b/src/Functions/FunctionStringOrArrayToT.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionStringToString.h b/src/Functions/FunctionStringToString.h index 50341ba149e..26480a83995 100644 --- a/src/Functions/FunctionStringToString.h +++ b/src/Functions/FunctionStringToString.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/FunctionUnaryArithmetic.h b/src/Functions/FunctionUnaryArithmetic.h index ee9cb914831..68fcfadfb84 100644 --- a/src/Functions/FunctionUnaryArithmetic.h +++ b/src/Functions/FunctionUnaryArithmetic.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionUnixTimestamp64.h b/src/Functions/FunctionUnixTimestamp64.h index 969b31cd13b..a4357c148ac 100644 --- a/src/Functions/FunctionUnixTimestamp64.h +++ b/src/Functions/FunctionUnixTimestamp64.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsBitmap.h b/src/Functions/FunctionsBitmap.h index 9bdcb2f81cb..bbdc53c3006 100644 --- a/src/Functions/FunctionsBitmap.h +++ b/src/Functions/FunctionsBitmap.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionsCoding.h b/src/Functions/FunctionsCoding.h index 512afc01674..01602cf1175 100644 --- a/src/Functions/FunctionsCoding.h +++ b/src/Functions/FunctionsCoding.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsConsistentHashing.h b/src/Functions/FunctionsConsistentHashing.h index 2448cee3f46..4c393f6ee01 100644 --- a/src/Functions/FunctionsConsistentHashing.h +++ b/src/Functions/FunctionsConsistentHashing.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionsEmbeddedDictionaries.h b/src/Functions/FunctionsEmbeddedDictionaries.h index aa32521ba6a..884f53125eb 100644 --- a/src/Functions/FunctionsEmbeddedDictionaries.h +++ b/src/Functions/FunctionsEmbeddedDictionaries.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsExternalDictionaries.h b/src/Functions/FunctionsExternalDictionaries.h index e2ee7dd31f3..6d9e4ce6768 100644 --- a/src/Functions/FunctionsExternalDictionaries.h +++ b/src/Functions/FunctionsExternalDictionaries.h @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionsExternalModels.h b/src/Functions/FunctionsExternalModels.h index f3e727cfcef..8f8b0e0c860 100644 --- a/src/Functions/FunctionsExternalModels.h +++ b/src/Functions/FunctionsExternalModels.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace DB diff --git a/src/Functions/FunctionsHashing.h b/src/Functions/FunctionsHashing.h index efd9a46b1d8..690991759a3 100644 --- a/src/Functions/FunctionsHashing.h +++ b/src/Functions/FunctionsHashing.h @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsJSON.h b/src/Functions/FunctionsJSON.h index ebc828fb287..2b49d01de2c 100644 --- a/src/Functions/FunctionsJSON.h +++ b/src/Functions/FunctionsJSON.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/FunctionsLogical.h b/src/Functions/FunctionsLogical.h index 94bbafc5808..acc34a40d00 100644 --- a/src/Functions/FunctionsLogical.h +++ b/src/Functions/FunctionsLogical.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionsMultiStringFuzzySearch.h b/src/Functions/FunctionsMultiStringFuzzySearch.h index 143fa445a1c..209efb0fc2f 100644 --- a/src/Functions/FunctionsMultiStringFuzzySearch.h +++ b/src/Functions/FunctionsMultiStringFuzzySearch.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsMultiStringPosition.h b/src/Functions/FunctionsMultiStringPosition.h index e68a5f87f35..f36f7639ccd 100644 --- a/src/Functions/FunctionsMultiStringPosition.h +++ b/src/Functions/FunctionsMultiStringPosition.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsMultiStringSearch.h b/src/Functions/FunctionsMultiStringSearch.h index 43f9c89e333..08b4668940e 100644 --- a/src/Functions/FunctionsMultiStringSearch.h +++ b/src/Functions/FunctionsMultiStringSearch.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsRandom.h b/src/Functions/FunctionsRandom.h index 08b58e8a1a7..75037d02a2d 100644 --- a/src/Functions/FunctionsRandom.h +++ b/src/Functions/FunctionsRandom.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsRound.h b/src/Functions/FunctionsRound.h index a56f609e2f8..f56b92d6db5 100644 --- a/src/Functions/FunctionsRound.h +++ b/src/Functions/FunctionsRound.h @@ -9,7 +9,7 @@ #include #include #include -#include "IFunctionOld.h" +#include "IFunction.h" #include #include #include diff --git a/src/Functions/FunctionsStringArray.h b/src/Functions/FunctionsStringArray.h index 046bfbfb6e9..27f10797651 100644 --- a/src/Functions/FunctionsStringArray.h +++ b/src/Functions/FunctionsStringArray.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsStringHash.h b/src/Functions/FunctionsStringHash.h index 00f38117dfa..37fa7d618b9 100644 --- a/src/Functions/FunctionsStringHash.h +++ b/src/Functions/FunctionsStringHash.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include namespace DB diff --git a/src/Functions/FunctionsStringSearch.h b/src/Functions/FunctionsStringSearch.h index 489332833c6..0789247e2d4 100644 --- a/src/Functions/FunctionsStringSearch.h +++ b/src/Functions/FunctionsStringSearch.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/FunctionsStringSearchToString.h b/src/Functions/FunctionsStringSearchToString.h index 92abd017c23..af91a9511e1 100644 --- a/src/Functions/FunctionsStringSearchToString.h +++ b/src/Functions/FunctionsStringSearchToString.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/FunctionsStringSimilarity.h b/src/Functions/FunctionsStringSimilarity.h index fcc500cd66f..6efb373aace 100644 --- a/src/Functions/FunctionsStringSimilarity.h +++ b/src/Functions/FunctionsStringSimilarity.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include namespace DB diff --git a/src/Functions/FunctionsVisitParam.h b/src/Functions/FunctionsVisitParam.h index 61b361c97fa..922ea44be9a 100644 --- a/src/Functions/FunctionsVisitParam.h +++ b/src/Functions/FunctionsVisitParam.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/IFunction.cpp b/src/Functions/IFunction.cpp index 6fa3cb130e5..262f5f7f0a8 100644 --- a/src/Functions/IFunction.cpp +++ b/src/Functions/IFunction.cpp @@ -15,7 +15,17 @@ #include #include #include -#include + +#if !defined(ARCADIA_BUILD) +# include +#endif + +#if USE_EMBEDDED_COMPILER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +# include +# pragma GCC diagnostic pop +#endif namespace DB { @@ -343,4 +353,77 @@ DataTypePtr IFunctionOverloadResolver::getReturnTypeWithoutLowCardinality(const return getReturnTypeImpl(arguments); } + +#if USE_EMBEDDED_COMPILER + +static std::optional removeNullables(const DataTypes & types) +{ + for (const auto & type : types) + { + if (!typeid_cast(type.get())) + continue; + DataTypes filtered; + for (const auto & sub_type : types) + filtered.emplace_back(removeNullable(sub_type)); + return filtered; + } + return {}; +} + +bool IFunction::isCompilable(const DataTypes & arguments) const +{ + if (useDefaultImplementationForNulls()) + if (auto denulled = removeNullables(arguments)) + return isCompilableImpl(*denulled); + return isCompilableImpl(arguments); +} + +llvm::Value * IFunction::compile(llvm::IRBuilderBase & builder, const DataTypes & arguments, Values values) const +{ + auto denulled_arguments = removeNullables(arguments); + if (useDefaultImplementationForNulls() && denulled_arguments) + { + auto & b = static_cast &>(builder); + + std::vector unwrapped_values; + std::vector is_null_values; + + unwrapped_values.reserve(arguments.size()); + is_null_values.reserve(arguments.size()); + + for (size_t i = 0; i < arguments.size(); ++i) + { + auto * value = values[i]; + + WhichDataType data_type(arguments[i]); + if (data_type.isNullable()) + { + unwrapped_values.emplace_back(b.CreateExtractValue(value, {0})); + is_null_values.emplace_back(b.CreateExtractValue(value, {1})); + } + else + { + unwrapped_values.emplace_back(value); + } + } + + auto * result = compileImpl(builder, *denulled_arguments, unwrapped_values); + + auto * nullable_structure_type = toNativeType(b, makeNullable(getReturnTypeImpl(*denulled_arguments))); + auto * nullable_structure_value = llvm::Constant::getNullValue(nullable_structure_type); + + auto * nullable_structure_with_result_value = b.CreateInsertValue(nullable_structure_value, result, {0}); + auto * nullable_structure_result_null = b.CreateExtractValue(nullable_structure_with_result_value, {1}); + + for (auto * is_null_value : is_null_values) + nullable_structure_result_null = b.CreateOr(nullable_structure_result_null, is_null_value); + + return b.CreateInsertValue(nullable_structure_with_result_value, nullable_structure_result_null, {1}); + } + + return compileImpl(builder, arguments, std::move(values)); +} + +#endif + } diff --git a/src/Functions/IFunction.h b/src/Functions/IFunction.h index 05a77699b82..fe3ec21afa1 100644 --- a/src/Functions/IFunction.h +++ b/src/Functions/IFunction.h @@ -326,4 +326,120 @@ private: using FunctionOverloadResolverPtr = std::shared_ptr; +/// Old function interface. Check documentation in IFunction.h. +/// If client do not need statefull properties it can implement this interface. +class IFunction +{ +public: + + virtual ~IFunction() = default; + + virtual String getName() const = 0; + + virtual ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const = 0; + virtual ColumnPtr executeImplDryRun(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const + { + return executeImpl(arguments, result_type, input_rows_count); + } + + /** Default implementation in presence of Nullable arguments or NULL constants as arguments is the following: + * if some of arguments are NULL constants then return NULL constant, + * if some of arguments are Nullable, then execute function as usual for columns, + * where Nullable columns are substituted with nested columns (they have arbitrary values in rows corresponding to NULL value) + * and wrap result in Nullable column where NULLs are in all rows where any of arguments are NULL. + */ + virtual bool useDefaultImplementationForNulls() const { return true; } + + /** If the function have non-zero number of arguments, + * and if all arguments are constant, that we could automatically provide default implementation: + * arguments are converted to ordinary columns with single value, then function is executed as usual, + * and then the result is converted to constant column. + */ + virtual bool useDefaultImplementationForConstants() const { return false; } + + /** If function arguments has single low cardinality column and all other arguments are constants, call function on nested column. + * Otherwise, convert all low cardinality columns to ordinary columns. + * Returns ColumnLowCardinality if at least one argument is ColumnLowCardinality. + */ + virtual bool useDefaultImplementationForLowCardinalityColumns() const { return true; } + + /// If it isn't, will convert all ColumnLowCardinality arguments to full columns. + virtual bool canBeExecutedOnLowCardinalityDictionary() const { return true; } + + /** Some arguments could remain constant during this implementation. + */ + virtual ColumnNumbers getArgumentsThatAreAlwaysConstant() const { return {}; } + + /** True if function can be called on default arguments (include Nullable's) and won't throw. + * Counterexample: modulo(0, 0) + */ + virtual bool canBeExecutedOnDefaultArguments() const { return true; } + + /// Properties from IFunctionBase (see IFunction.h) + virtual bool isSuitableForConstantFolding() const { return true; } + virtual ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const ColumnsWithTypeAndName & /*arguments*/) const { return nullptr; } + virtual bool isInjective(const ColumnsWithTypeAndName & /*sample_columns*/) const { return false; } + virtual bool isDeterministic() const { return true; } + virtual bool isDeterministicInScopeOfQuery() const { return true; } + virtual bool isStateful() const { return false; } + virtual bool hasInformationAboutMonotonicity() const { return false; } + + using Monotonicity = IFunctionBase::Monotonicity; + virtual Monotonicity getMonotonicityForRange(const IDataType & /*type*/, const Field & /*left*/, const Field & /*right*/) const + { + throw Exception("Function " + getName() + " has no information about its monotonicity.", ErrorCodes::NOT_IMPLEMENTED); + } + + /// For non-variadic functions, return number of arguments; otherwise return zero (that should be ignored). + virtual size_t getNumberOfArguments() const = 0; + + virtual DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const + { + throw Exception("getReturnType is not implemented for " + getName(), ErrorCodes::NOT_IMPLEMENTED); + } + + /// Get the result type by argument type. If the function does not apply to these arguments, throw an exception. + virtual DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const + { + DataTypes data_types(arguments.size()); + for (size_t i = 0; i < arguments.size(); ++i) + data_types[i] = arguments[i].type; + + return getReturnTypeImpl(data_types); + } + + virtual bool isVariadic() const { return false; } + + virtual void getLambdaArgumentTypes(DataTypes & /*arguments*/) const + { + throw Exception("Function " + getName() + " can't have lambda-expressions as arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + virtual ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const { return {}; } + + +#if USE_EMBEDDED_COMPILER + + bool isCompilable(const DataTypes & arguments) const; + + llvm::Value * compile(llvm::IRBuilderBase &, const DataTypes & arguments, Values values) const; + +#endif + +protected: + +#if USE_EMBEDDED_COMPILER + + virtual bool isCompilableImpl(const DataTypes &) const { return false; } + + virtual llvm::Value * compileImpl(llvm::IRBuilderBase &, const DataTypes &, Values) const + { + throw Exception(getName() + " is not JIT-compilable", ErrorCodes::NOT_IMPLEMENTED); + } + +#endif +}; + +using FunctionPtr = std::shared_ptr; + } diff --git a/src/Functions/IFunctionAdaptors.h b/src/Functions/IFunctionAdaptors.h index 313d006e00c..b213a459103 100644 --- a/src/Functions/IFunctionAdaptors.h +++ b/src/Functions/IFunctionAdaptors.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace DB { diff --git a/src/Functions/IFunctionOld.cpp b/src/Functions/IFunctionOld.cpp deleted file mode 100644 index c25247a9742..00000000000 --- a/src/Functions/IFunctionOld.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "IFunctionOld.h" - -#include - -#if !defined(ARCADIA_BUILD) -# include -#endif - -#if USE_EMBEDDED_COMPILER -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -# include -# pragma GCC diagnostic pop -#endif - -namespace DB -{ - -#if USE_EMBEDDED_COMPILER - -static std::optional removeNullables(const DataTypes & types) -{ - for (const auto & type : types) - { - if (!typeid_cast(type.get())) - continue; - DataTypes filtered; - for (const auto & sub_type : types) - filtered.emplace_back(removeNullable(sub_type)); - return filtered; - } - return {}; -} - -bool IFunction::isCompilable(const DataTypes & arguments) const -{ - if (useDefaultImplementationForNulls()) - if (auto denulled = removeNullables(arguments)) - return isCompilableImpl(*denulled); - return isCompilableImpl(arguments); -} - -llvm::Value * IFunction::compile(llvm::IRBuilderBase & builder, const DataTypes & arguments, Values values) const -{ - auto denulled_arguments = removeNullables(arguments); - if (useDefaultImplementationForNulls() && denulled_arguments) - { - auto & b = static_cast &>(builder); - - std::vector unwrapped_values; - std::vector is_null_values; - - unwrapped_values.reserve(arguments.size()); - is_null_values.reserve(arguments.size()); - - for (size_t i = 0; i < arguments.size(); ++i) - { - auto * value = values[i]; - - WhichDataType data_type(arguments[i]); - if (data_type.isNullable()) - { - unwrapped_values.emplace_back(b.CreateExtractValue(value, {0})); - is_null_values.emplace_back(b.CreateExtractValue(value, {1})); - } - else - { - unwrapped_values.emplace_back(value); - } - } - - auto * result = compileImpl(builder, *denulled_arguments, unwrapped_values); - - auto * nullable_structure_type = toNativeType(b, makeNullable(getReturnTypeImpl(*denulled_arguments))); - auto * nullable_structure_value = llvm::Constant::getNullValue(nullable_structure_type); - - auto * nullable_structure_with_result_value = b.CreateInsertValue(nullable_structure_value, result, {0}); - auto * nullable_structure_result_null = b.CreateExtractValue(nullable_structure_with_result_value, {1}); - - for (auto * is_null_value : is_null_values) - nullable_structure_result_null = b.CreateOr(nullable_structure_result_null, is_null_value); - - return b.CreateInsertValue(nullable_structure_with_result_value, nullable_structure_result_null, {1}); - } - - return compileImpl(builder, arguments, std::move(values)); -} - -#endif - -} diff --git a/src/Functions/IFunctionOld.h b/src/Functions/IFunctionOld.h deleted file mode 100644 index 4b8ef64bc65..00000000000 --- a/src/Functions/IFunctionOld.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int NOT_IMPLEMENTED; -} - -/// Old function interface. Check documentation in IFunction.h -class IFunction -{ -public: - - virtual ~IFunction() = default; - - virtual String getName() const = 0; - - virtual ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const = 0; - virtual ColumnPtr executeImplDryRun(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const - { - return executeImpl(arguments, result_type, input_rows_count); - } - - /** Default implementation in presence of Nullable arguments or NULL constants as arguments is the following: - * if some of arguments are NULL constants then return NULL constant, - * if some of arguments are Nullable, then execute function as usual for columns, - * where Nullable columns are substituted with nested columns (they have arbitrary values in rows corresponding to NULL value) - * and wrap result in Nullable column where NULLs are in all rows where any of arguments are NULL. - */ - virtual bool useDefaultImplementationForNulls() const { return true; } - - /** If the function have non-zero number of arguments, - * and if all arguments are constant, that we could automatically provide default implementation: - * arguments are converted to ordinary columns with single value, then function is executed as usual, - * and then the result is converted to constant column. - */ - virtual bool useDefaultImplementationForConstants() const { return false; } - - /** If function arguments has single low cardinality column and all other arguments are constants, call function on nested column. - * Otherwise, convert all low cardinality columns to ordinary columns. - * Returns ColumnLowCardinality if at least one argument is ColumnLowCardinality. - */ - virtual bool useDefaultImplementationForLowCardinalityColumns() const { return true; } - - /// If it isn't, will convert all ColumnLowCardinality arguments to full columns. - virtual bool canBeExecutedOnLowCardinalityDictionary() const { return true; } - - /** Some arguments could remain constant during this implementation. - */ - virtual ColumnNumbers getArgumentsThatAreAlwaysConstant() const { return {}; } - - /** True if function can be called on default arguments (include Nullable's) and won't throw. - * Counterexample: modulo(0, 0) - */ - virtual bool canBeExecutedOnDefaultArguments() const { return true; } - - /// Properties from IFunctionBase (see IFunction.h) - virtual bool isSuitableForConstantFolding() const { return true; } - virtual ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const ColumnsWithTypeAndName & /*arguments*/) const { return nullptr; } - virtual bool isInjective(const ColumnsWithTypeAndName & /*sample_columns*/) const { return false; } - virtual bool isDeterministic() const { return true; } - virtual bool isDeterministicInScopeOfQuery() const { return true; } - virtual bool isStateful() const { return false; } - virtual bool hasInformationAboutMonotonicity() const { return false; } - - using Monotonicity = IFunctionBase::Monotonicity; - virtual Monotonicity getMonotonicityForRange(const IDataType & /*type*/, const Field & /*left*/, const Field & /*right*/) const - { - throw Exception("Function " + getName() + " has no information about its monotonicity.", ErrorCodes::NOT_IMPLEMENTED); - } - - /// For non-variadic functions, return number of arguments; otherwise return zero (that should be ignored). - virtual size_t getNumberOfArguments() const = 0; - - virtual DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const - { - throw Exception("getReturnType is not implemented for " + getName(), ErrorCodes::NOT_IMPLEMENTED); - } - - /// Get the result type by argument type. If the function does not apply to these arguments, throw an exception. - virtual DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const - { - DataTypes data_types(arguments.size()); - for (size_t i = 0; i < arguments.size(); ++i) - data_types[i] = arguments[i].type; - - return getReturnTypeImpl(data_types); - } - - virtual bool isVariadic() const { return false; } - - virtual void getLambdaArgumentTypes(DataTypes & /*arguments*/) const - { - throw Exception("Function " + getName() + " can't have lambda-expressions as arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - } - - virtual ColumnNumbers getArgumentsThatDontImplyNullableReturnType(size_t /*number_of_arguments*/) const { return {}; } - - -#if USE_EMBEDDED_COMPILER - - bool isCompilable(const DataTypes & arguments) const; - - llvm::Value * compile(llvm::IRBuilderBase &, const DataTypes & arguments, Values values) const; - -#endif - -protected: - -#if USE_EMBEDDED_COMPILER - - virtual bool isCompilableImpl(const DataTypes &) const { return false; } - - virtual llvm::Value * compileImpl(llvm::IRBuilderBase &, const DataTypes &, Values) const - { - throw Exception(getName() + " is not JIT-compilable", ErrorCodes::NOT_IMPLEMENTED); - } - -#endif -}; - -using FunctionPtr = std::shared_ptr; - -} diff --git a/src/Functions/LeastGreatestGeneric.h b/src/Functions/LeastGreatestGeneric.h index bc36372174a..51564ad7cdc 100644 --- a/src/Functions/LeastGreatestGeneric.h +++ b/src/Functions/LeastGreatestGeneric.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/PerformanceAdaptors.h b/src/Functions/PerformanceAdaptors.h index 18fe31ec762..9ef6454d085 100644 --- a/src/Functions/PerformanceAdaptors.h +++ b/src/Functions/PerformanceAdaptors.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/src/Functions/URL/port.cpp b/src/Functions/URL/port.cpp index 46197f43c8c..179a2be4471 100644 --- a/src/Functions/URL/port.cpp +++ b/src/Functions/URL/port.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/addressToLine.cpp b/src/Functions/addressToLine.cpp index 5c83db50f08..aabf388b428 100644 --- a/src/Functions/addressToLine.cpp +++ b/src/Functions/addressToLine.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/addressToSymbol.cpp b/src/Functions/addressToSymbol.cpp index fd1664288ed..7ffdc6d4260 100644 --- a/src/Functions/addressToSymbol.cpp +++ b/src/Functions/addressToSymbol.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/appendTrailingCharIfAbsent.cpp b/src/Functions/appendTrailingCharIfAbsent.cpp index 359d20c9615..266b2a44f4a 100644 --- a/src/Functions/appendTrailingCharIfAbsent.cpp +++ b/src/Functions/appendTrailingCharIfAbsent.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/array/FunctionArrayMapped.h b/src/Functions/array/FunctionArrayMapped.h index a9a75a95399..3609398bc3f 100644 --- a/src/Functions/array/FunctionArrayMapped.h +++ b/src/Functions/array/FunctionArrayMapped.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/array/arrayConcat.cpp b/src/Functions/array/arrayConcat.cpp index 1e35932454d..57a783a3244 100644 --- a/src/Functions/array/arrayConcat.cpp +++ b/src/Functions/array/arrayConcat.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayDistinct.cpp b/src/Functions/array/arrayDistinct.cpp index 5dc8c740c43..916af560c8f 100644 --- a/src/Functions/array/arrayDistinct.cpp +++ b/src/Functions/array/arrayDistinct.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayElement.cpp b/src/Functions/array/arrayElement.cpp index 529d94c04ab..f3d3f558d7b 100644 --- a/src/Functions/array/arrayElement.cpp +++ b/src/Functions/array/arrayElement.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayEnumerate.cpp b/src/Functions/array/arrayEnumerate.cpp index c08e0a3bab9..6d59a2c3805 100644 --- a/src/Functions/array/arrayEnumerate.cpp +++ b/src/Functions/array/arrayEnumerate.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayEnumerateExtended.h b/src/Functions/array/arrayEnumerateExtended.h index 78d48b7a476..7e4fe24873a 100644 --- a/src/Functions/array/arrayEnumerateExtended.h +++ b/src/Functions/array/arrayEnumerateExtended.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/array/arrayEnumerateRanked.h b/src/Functions/array/arrayEnumerateRanked.h index 85b3d751304..2c999415f33 100644 --- a/src/Functions/array/arrayEnumerateRanked.h +++ b/src/Functions/array/arrayEnumerateRanked.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/array/arrayFlatten.cpp b/src/Functions/array/arrayFlatten.cpp index 994f1a2c6cc..3d286aa0bb4 100644 --- a/src/Functions/array/arrayFlatten.cpp +++ b/src/Functions/array/arrayFlatten.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayIndex.h b/src/Functions/array/arrayIndex.h index 55b68155551..f3b279faaef 100644 --- a/src/Functions/array/arrayIndex.h +++ b/src/Functions/array/arrayIndex.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/array/arrayIntersect.cpp b/src/Functions/array/arrayIntersect.cpp index aac918a9181..93c1ee06403 100644 --- a/src/Functions/array/arrayIntersect.cpp +++ b/src/Functions/array/arrayIntersect.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayJoin.cpp b/src/Functions/array/arrayJoin.cpp index 97cfeb6cd20..da8c4e6e80b 100644 --- a/src/Functions/array/arrayJoin.cpp +++ b/src/Functions/array/arrayJoin.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayPop.h b/src/Functions/array/arrayPop.h index faf5842982e..270b5e20f85 100644 --- a/src/Functions/array/arrayPop.h +++ b/src/Functions/array/arrayPop.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/array/arrayPush.h b/src/Functions/array/arrayPush.h index 6f038eaeed1..3a63e7b631d 100644 --- a/src/Functions/array/arrayPush.h +++ b/src/Functions/array/arrayPush.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/array/arrayReduce.cpp b/src/Functions/array/arrayReduce.cpp index a69ed9dddc8..bbdd142c062 100644 --- a/src/Functions/array/arrayReduce.cpp +++ b/src/Functions/array/arrayReduce.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayReduceInRanges.cpp b/src/Functions/array/arrayReduceInRanges.cpp index 32c02dff14c..bcb34385d17 100644 --- a/src/Functions/array/arrayReduceInRanges.cpp +++ b/src/Functions/array/arrayReduceInRanges.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayResize.cpp b/src/Functions/array/arrayResize.cpp index e771db4bd9a..f8eea06335b 100644 --- a/src/Functions/array/arrayResize.cpp +++ b/src/Functions/array/arrayResize.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayReverse.cpp b/src/Functions/array/arrayReverse.cpp index f7b81f51d7c..fb4a559b37f 100644 --- a/src/Functions/array/arrayReverse.cpp +++ b/src/Functions/array/arrayReverse.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arraySlice.cpp b/src/Functions/array/arraySlice.cpp index c77a97a2aa0..567135de884 100644 --- a/src/Functions/array/arraySlice.cpp +++ b/src/Functions/array/arraySlice.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayUniq.cpp b/src/Functions/array/arrayUniq.cpp index 6843bbdd00f..62de746f136 100644 --- a/src/Functions/array/arrayUniq.cpp +++ b/src/Functions/array/arrayUniq.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/arrayWithConstant.cpp b/src/Functions/array/arrayWithConstant.cpp index 5cfb11fddd3..578e8bf2296 100644 --- a/src/Functions/array/arrayWithConstant.cpp +++ b/src/Functions/array/arrayWithConstant.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/emptyArray.cpp b/src/Functions/array/emptyArray.cpp index 4f65380428e..370c51f3e8d 100644 --- a/src/Functions/array/emptyArray.cpp +++ b/src/Functions/array/emptyArray.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/emptyArrayToSingle.cpp b/src/Functions/array/emptyArrayToSingle.cpp index 343d76882e4..be387620e60 100644 --- a/src/Functions/array/emptyArrayToSingle.cpp +++ b/src/Functions/array/emptyArrayToSingle.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/array/hasAllAny.h b/src/Functions/array/hasAllAny.h index 4e03f215b55..04c6558f066 100644 --- a/src/Functions/array/hasAllAny.h +++ b/src/Functions/array/hasAllAny.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/array/range.cpp b/src/Functions/array/range.cpp index 2ec2cc13401..5b9886580dc 100644 --- a/src/Functions/array/range.cpp +++ b/src/Functions/array/range.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/assumeNotNull.cpp b/src/Functions/assumeNotNull.cpp index 0c1cf515725..019c637e50c 100644 --- a/src/Functions/assumeNotNull.cpp +++ b/src/Functions/assumeNotNull.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/bar.cpp b/src/Functions/bar.cpp index bf0097ba40e..2e26f7af0bb 100644 --- a/src/Functions/bar.cpp +++ b/src/Functions/bar.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/bitmaskToList.cpp b/src/Functions/bitmaskToList.cpp index 1e4d886c127..8c3105724ac 100644 --- a/src/Functions/bitmaskToList.cpp +++ b/src/Functions/bitmaskToList.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/blockNumber.cpp b/src/Functions/blockNumber.cpp index 5c15d720954..9a57f8a96b0 100644 --- a/src/Functions/blockNumber.cpp +++ b/src/Functions/blockNumber.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/blockSerializedSize.cpp b/src/Functions/blockSerializedSize.cpp index 1cad4cbd773..30f77bbf627 100644 --- a/src/Functions/blockSerializedSize.cpp +++ b/src/Functions/blockSerializedSize.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/blockSize.cpp b/src/Functions/blockSize.cpp index 4476438385b..294686054f0 100644 --- a/src/Functions/blockSize.cpp +++ b/src/Functions/blockSize.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/buildId.cpp b/src/Functions/buildId.cpp index 26b10a8bb6e..cc0c21350ca 100644 --- a/src/Functions/buildId.cpp +++ b/src/Functions/buildId.cpp @@ -1,6 +1,6 @@ #if defined(__ELF__) && !defined(__FreeBSD__) -#include +#include #include #include #include diff --git a/src/Functions/byteSize.cpp b/src/Functions/byteSize.cpp index 463cd4bced0..54a7da59b9c 100644 --- a/src/Functions/byteSize.cpp +++ b/src/Functions/byteSize.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace DB diff --git a/src/Functions/coalesce.cpp b/src/Functions/coalesce.cpp index 37cc52557d4..791b9d993b4 100644 --- a/src/Functions/coalesce.cpp +++ b/src/Functions/coalesce.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace DB diff --git a/src/Functions/concat.cpp b/src/Functions/concat.cpp index a024738eab4..c1b9f8e7967 100644 --- a/src/Functions/concat.cpp +++ b/src/Functions/concat.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/connectionId.cpp b/src/Functions/connectionId.cpp index c9e8787dffb..ae04cfd1af6 100644 --- a/src/Functions/connectionId.cpp +++ b/src/Functions/connectionId.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include diff --git a/src/Functions/countDigits.cpp b/src/Functions/countDigits.cpp index b06d5017aab..597a2c625b9 100644 --- a/src/Functions/countDigits.cpp +++ b/src/Functions/countDigits.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/countMatches.h b/src/Functions/countMatches.h index 3bb466f0e31..6ae69520cb9 100644 --- a/src/Functions/countMatches.h +++ b/src/Functions/countMatches.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/currentDatabase.cpp b/src/Functions/currentDatabase.cpp index ed14ccaf447..16eff20cfd5 100644 --- a/src/Functions/currentDatabase.cpp +++ b/src/Functions/currentDatabase.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/currentUser.cpp b/src/Functions/currentUser.cpp index bf63658df4c..22ad49fb29d 100644 --- a/src/Functions/currentUser.cpp +++ b/src/Functions/currentUser.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/dateDiff.cpp b/src/Functions/dateDiff.cpp index 532c4e1c3ec..cbad9dc1ce4 100644 --- a/src/Functions/dateDiff.cpp +++ b/src/Functions/dateDiff.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/Functions/defaultValueOfArgumentType.cpp b/src/Functions/defaultValueOfArgumentType.cpp index aa8cfca2083..957d829039d 100644 --- a/src/Functions/defaultValueOfArgumentType.cpp +++ b/src/Functions/defaultValueOfArgumentType.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/defaultValueOfTypeName.cpp b/src/Functions/defaultValueOfTypeName.cpp index ea39f8e1e75..1bf978ab17b 100644 --- a/src/Functions/defaultValueOfTypeName.cpp +++ b/src/Functions/defaultValueOfTypeName.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/dumpColumnStructure.cpp b/src/Functions/dumpColumnStructure.cpp index 7bbeee97b85..3189e343beb 100644 --- a/src/Functions/dumpColumnStructure.cpp +++ b/src/Functions/dumpColumnStructure.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/errorCodeToName.cpp b/src/Functions/errorCodeToName.cpp index 5090d41218f..d8e8e0f0d29 100644 --- a/src/Functions/errorCodeToName.cpp +++ b/src/Functions/errorCodeToName.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/evalMLMethod.cpp b/src/Functions/evalMLMethod.cpp index 224f85d6815..a69a6f0f550 100644 --- a/src/Functions/evalMLMethod.cpp +++ b/src/Functions/evalMLMethod.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/extractAllGroups.h b/src/Functions/extractAllGroups.h index 0edbeaaf7b1..864a788cf18 100644 --- a/src/Functions/extractAllGroups.h +++ b/src/Functions/extractAllGroups.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/extractTextFromHTML.cpp b/src/Functions/extractTextFromHTML.cpp index 28638696700..6a7bdbeaba9 100644 --- a/src/Functions/extractTextFromHTML.cpp +++ b/src/Functions/extractTextFromHTML.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/filesystem.cpp b/src/Functions/filesystem.cpp index 7f28be10b6e..d264c972656 100644 --- a/src/Functions/filesystem.cpp +++ b/src/Functions/filesystem.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/finalizeAggregation.cpp b/src/Functions/finalizeAggregation.cpp index 48d28f1bd16..b3dfbc0aa15 100644 --- a/src/Functions/finalizeAggregation.cpp +++ b/src/Functions/finalizeAggregation.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/formatDateTime.cpp b/src/Functions/formatDateTime.cpp index 89b98f1657c..d16985b5b34 100644 --- a/src/Functions/formatDateTime.cpp +++ b/src/Functions/formatDateTime.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/formatReadable.h b/src/Functions/formatReadable.h index e4681163e8a..6cf4fadbf05 100644 --- a/src/Functions/formatReadable.h +++ b/src/Functions/formatReadable.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/formatReadableTimeDelta.cpp b/src/Functions/formatReadableTimeDelta.cpp index 83af6968bac..69dbaa71041 100644 --- a/src/Functions/formatReadableTimeDelta.cpp +++ b/src/Functions/formatReadableTimeDelta.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/formatRow.cpp b/src/Functions/formatRow.cpp index 9012137b334..2d7739a02d6 100644 --- a/src/Functions/formatRow.cpp +++ b/src/Functions/formatRow.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/formatString.cpp b/src/Functions/formatString.cpp index 4de34c1f43f..4a3b04aaa05 100644 --- a/src/Functions/formatString.cpp +++ b/src/Functions/formatString.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/fuzzBits.cpp b/src/Functions/fuzzBits.cpp index b6732d3211c..0884f586082 100644 --- a/src/Functions/fuzzBits.cpp +++ b/src/Functions/fuzzBits.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/geoToH3.cpp b/src/Functions/geoToH3.cpp index 23df9d246ec..6030cbeea65 100644 --- a/src/Functions/geoToH3.cpp +++ b/src/Functions/geoToH3.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/geohashesInBox.cpp b/src/Functions/geohashesInBox.cpp index 55d89649dc8..c0629ab9655 100644 --- a/src/Functions/geohashesInBox.cpp +++ b/src/Functions/geohashesInBox.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/getMacro.cpp b/src/Functions/getMacro.cpp index 10d89a2e7d1..c869685af42 100644 --- a/src/Functions/getMacro.cpp +++ b/src/Functions/getMacro.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/getScalar.cpp b/src/Functions/getScalar.cpp index 8d6aa70bdb3..a29abd257e7 100644 --- a/src/Functions/getScalar.cpp +++ b/src/Functions/getScalar.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/getSetting.cpp b/src/Functions/getSetting.cpp index b90fa48dc73..0206de33125 100644 --- a/src/Functions/getSetting.cpp +++ b/src/Functions/getSetting.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/getSizeOfEnumType.cpp b/src/Functions/getSizeOfEnumType.cpp index e58faacb187..7db11d41d0f 100644 --- a/src/Functions/getSizeOfEnumType.cpp +++ b/src/Functions/getSizeOfEnumType.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/globalVariable.cpp b/src/Functions/globalVariable.cpp index 6a5fda3b831..c141ceb2692 100644 --- a/src/Functions/globalVariable.cpp +++ b/src/Functions/globalVariable.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/greatCircleDistance.cpp b/src/Functions/greatCircleDistance.cpp index d9ead27ac9f..756b76859ae 100644 --- a/src/Functions/greatCircleDistance.cpp +++ b/src/Functions/greatCircleDistance.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/hasColumnInTable.cpp b/src/Functions/hasColumnInTable.cpp index 05967133406..da7e59d69e3 100644 --- a/src/Functions/hasColumnInTable.cpp +++ b/src/Functions/hasColumnInTable.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/hostName.cpp b/src/Functions/hostName.cpp index f09069a7399..0aba155bb36 100644 --- a/src/Functions/hostName.cpp +++ b/src/Functions/hostName.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/identity.cpp b/src/Functions/identity.cpp index bdc74fbaf19..d15d9e1f710 100644 --- a/src/Functions/identity.cpp +++ b/src/Functions/identity.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/src/Functions/if.cpp b/src/Functions/if.cpp index e57b621acad..ec3447ffb81 100644 --- a/src/Functions/if.cpp +++ b/src/Functions/if.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/ifNotFinite.cpp b/src/Functions/ifNotFinite.cpp index d85fc4ee4ca..a5e3131117e 100644 --- a/src/Functions/ifNotFinite.cpp +++ b/src/Functions/ifNotFinite.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/ifNull.cpp b/src/Functions/ifNull.cpp index eba3f74753c..82b63f4dbda 100644 --- a/src/Functions/ifNull.cpp +++ b/src/Functions/ifNull.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/ignore.cpp b/src/Functions/ignore.cpp index cdb267d7a2a..45079639835 100644 --- a/src/Functions/ignore.cpp +++ b/src/Functions/ignore.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/in.cpp b/src/Functions/in.cpp index d891b84fe22..827e0212396 100644 --- a/src/Functions/in.cpp +++ b/src/Functions/in.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/indexHint.cpp b/src/Functions/indexHint.cpp index 2f1fc40bee9..d2a9a0abb8c 100644 --- a/src/Functions/indexHint.cpp +++ b/src/Functions/indexHint.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/initializeAggregation.cpp b/src/Functions/initializeAggregation.cpp index 0f19dcdc3c6..aea97a48037 100644 --- a/src/Functions/initializeAggregation.cpp +++ b/src/Functions/initializeAggregation.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/isConstant.cpp b/src/Functions/isConstant.cpp index b2440aec13f..3069ec79ae1 100644 --- a/src/Functions/isConstant.cpp +++ b/src/Functions/isConstant.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/isDecimalOverflow.cpp b/src/Functions/isDecimalOverflow.cpp index ae8cff19192..d409afaf234 100644 --- a/src/Functions/isDecimalOverflow.cpp +++ b/src/Functions/isDecimalOverflow.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/isIPAddressContainedIn.cpp b/src/Functions/isIPAddressContainedIn.cpp index 06f439f956c..0886ef55e7b 100644 --- a/src/Functions/isIPAddressContainedIn.cpp +++ b/src/Functions/isIPAddressContainedIn.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/isNotNull.cpp b/src/Functions/isNotNull.cpp index 05964716053..81c870a6303 100644 --- a/src/Functions/isNotNull.cpp +++ b/src/Functions/isNotNull.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/isNull.cpp b/src/Functions/isNull.cpp index 074f52c3cb6..de840dab2bf 100644 --- a/src/Functions/isNull.cpp +++ b/src/Functions/isNull.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/isZeroOrNull.cpp b/src/Functions/isZeroOrNull.cpp index 9152c2692d4..a2a06af7569 100644 --- a/src/Functions/isZeroOrNull.cpp +++ b/src/Functions/isZeroOrNull.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/logTrace.cpp b/src/Functions/logTrace.cpp index 17ddcba0929..2ccc4d2ffd2 100644 --- a/src/Functions/logTrace.cpp +++ b/src/Functions/logTrace.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/lowCardinalityIndices.cpp b/src/Functions/lowCardinalityIndices.cpp index 4e560eaf0fa..580e7381955 100644 --- a/src/Functions/lowCardinalityIndices.cpp +++ b/src/Functions/lowCardinalityIndices.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/lowCardinalityKeys.cpp b/src/Functions/lowCardinalityKeys.cpp index ae916cecebe..46128267871 100644 --- a/src/Functions/lowCardinalityKeys.cpp +++ b/src/Functions/lowCardinalityKeys.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/map.cpp b/src/Functions/map.cpp index 7e1ea33a21c..f1b08dc75b7 100644 --- a/src/Functions/map.cpp +++ b/src/Functions/map.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/materialize.h b/src/Functions/materialize.h index bc4fc7a9aad..4676b263f39 100644 --- a/src/Functions/materialize.h +++ b/src/Functions/materialize.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace DB diff --git a/src/Functions/neighbor.cpp b/src/Functions/neighbor.cpp index d49d4ab70dc..785c5817176 100644 --- a/src/Functions/neighbor.cpp +++ b/src/Functions/neighbor.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/nullIf.cpp b/src/Functions/nullIf.cpp index 66c35a26978..14f2f72fe61 100644 --- a/src/Functions/nullIf.cpp +++ b/src/Functions/nullIf.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/partitionId.cpp b/src/Functions/partitionId.cpp index 4238f1f0bf1..cf679452da1 100644 --- a/src/Functions/partitionId.cpp +++ b/src/Functions/partitionId.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/pointInEllipses.cpp b/src/Functions/pointInEllipses.cpp index b10bbd40197..f7bfc24559c 100644 --- a/src/Functions/pointInEllipses.cpp +++ b/src/Functions/pointInEllipses.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/randomFixedString.cpp b/src/Functions/randomFixedString.cpp index d2484bfc2b4..13996eee677 100644 --- a/src/Functions/randomFixedString.cpp +++ b/src/Functions/randomFixedString.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/randomPrintableASCII.cpp b/src/Functions/randomPrintableASCII.cpp index e6491945dfd..ba8c16aa689 100644 --- a/src/Functions/randomPrintableASCII.cpp +++ b/src/Functions/randomPrintableASCII.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/randomString.cpp b/src/Functions/randomString.cpp index 758abb15ec9..10795626326 100644 --- a/src/Functions/randomString.cpp +++ b/src/Functions/randomString.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/randomStringUTF8.cpp b/src/Functions/randomStringUTF8.cpp index 60476a89c26..018c591a1fe 100644 --- a/src/Functions/randomStringUTF8.cpp +++ b/src/Functions/randomStringUTF8.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/repeat.cpp b/src/Functions/repeat.cpp index 430fcc81181..423ed53c53f 100644 --- a/src/Functions/repeat.cpp +++ b/src/Functions/repeat.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/replicate.cpp b/src/Functions/replicate.cpp index f023f813828..796d5645a2e 100644 --- a/src/Functions/replicate.cpp +++ b/src/Functions/replicate.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Functions/replicate.h b/src/Functions/replicate.h index cd401f1d267..71b39e9e60e 100644 --- a/src/Functions/replicate.h +++ b/src/Functions/replicate.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace DB diff --git a/src/Functions/rowNumberInAllBlocks.cpp b/src/Functions/rowNumberInAllBlocks.cpp index ca3df2f0c40..9c358aec8f0 100644 --- a/src/Functions/rowNumberInAllBlocks.cpp +++ b/src/Functions/rowNumberInAllBlocks.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/rowNumberInBlock.cpp b/src/Functions/rowNumberInBlock.cpp index 18d1b65588b..48fa472e1dd 100644 --- a/src/Functions/rowNumberInBlock.cpp +++ b/src/Functions/rowNumberInBlock.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/runningAccumulate.cpp b/src/Functions/runningAccumulate.cpp index e7f7d51a3b8..1eab573b046 100644 --- a/src/Functions/runningAccumulate.cpp +++ b/src/Functions/runningAccumulate.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/runningConcurrency.cpp b/src/Functions/runningConcurrency.cpp index 452e6542d83..022e2be5f6c 100644 --- a/src/Functions/runningConcurrency.cpp +++ b/src/Functions/runningConcurrency.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/runningDifference.h b/src/Functions/runningDifference.h index 34f4c4033e1..f87c57af043 100644 --- a/src/Functions/runningDifference.h +++ b/src/Functions/runningDifference.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/sleep.h b/src/Functions/sleep.h index 3ffb0f43925..c0aad0b3820 100644 --- a/src/Functions/sleep.h +++ b/src/Functions/sleep.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include #include diff --git a/src/Functions/substring.cpp b/src/Functions/substring.cpp index 5e5e3b64280..5ce75035475 100644 --- a/src/Functions/substring.cpp +++ b/src/Functions/substring.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/subtractDays.cpp b/src/Functions/subtractDays.cpp index 7e4dbb2ecc1..21966a15311 100644 --- a/src/Functions/subtractDays.cpp +++ b/src/Functions/subtractDays.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractHours.cpp b/src/Functions/subtractHours.cpp index 1a261ad3d36..e71c9d74a01 100644 --- a/src/Functions/subtractHours.cpp +++ b/src/Functions/subtractHours.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractMinutes.cpp b/src/Functions/subtractMinutes.cpp index 9ea92a49cf0..ba9d593a64d 100644 --- a/src/Functions/subtractMinutes.cpp +++ b/src/Functions/subtractMinutes.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractMonths.cpp b/src/Functions/subtractMonths.cpp index effdb077bcf..64eeba2ce86 100644 --- a/src/Functions/subtractMonths.cpp +++ b/src/Functions/subtractMonths.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractQuarters.cpp b/src/Functions/subtractQuarters.cpp index 3b6ff64b719..6c066ed17a1 100644 --- a/src/Functions/subtractQuarters.cpp +++ b/src/Functions/subtractQuarters.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractSeconds.cpp b/src/Functions/subtractSeconds.cpp index d63a1f41d9c..81a7f7e2df1 100644 --- a/src/Functions/subtractSeconds.cpp +++ b/src/Functions/subtractSeconds.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractWeeks.cpp b/src/Functions/subtractWeeks.cpp index 74e422acbbf..55b52043dd0 100644 --- a/src/Functions/subtractWeeks.cpp +++ b/src/Functions/subtractWeeks.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/subtractYears.cpp b/src/Functions/subtractYears.cpp index 93fcb44baf0..241142722d5 100644 --- a/src/Functions/subtractYears.cpp +++ b/src/Functions/subtractYears.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Functions/throwIf.cpp b/src/Functions/throwIf.cpp index 1e22295edb7..1b56cc0d188 100644 --- a/src/Functions/throwIf.cpp +++ b/src/Functions/throwIf.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/tid.cpp b/src/Functions/tid.cpp index 56aad782cdd..404eff862b3 100644 --- a/src/Functions/tid.cpp +++ b/src/Functions/tid.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include diff --git a/src/Functions/timeSlot.cpp b/src/Functions/timeSlot.cpp index 7819a7c1341..afe99c86eb2 100644 --- a/src/Functions/timeSlot.cpp +++ b/src/Functions/timeSlot.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/timeSlots.cpp b/src/Functions/timeSlots.cpp index 8530c41bf2f..b64d2687b05 100644 --- a/src/Functions/timeSlots.cpp +++ b/src/Functions/timeSlots.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/Functions/timezone.cpp b/src/Functions/timezone.cpp index 27ed19a22aa..67f7462fc95 100644 --- a/src/Functions/timezone.cpp +++ b/src/Functions/timezone.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/timezoneOf.cpp b/src/Functions/timezoneOf.cpp index 9606951d006..0e6fa1bb213 100644 --- a/src/Functions/timezoneOf.cpp +++ b/src/Functions/timezoneOf.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/toColumnTypeName.cpp b/src/Functions/toColumnTypeName.cpp index 44d27f9fd48..0b73fe772d1 100644 --- a/src/Functions/toColumnTypeName.cpp +++ b/src/Functions/toColumnTypeName.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/toCustomWeek.cpp b/src/Functions/toCustomWeek.cpp index 715e899b5fe..5ba0b8e8b2a 100644 --- a/src/Functions/toCustomWeek.cpp +++ b/src/Functions/toCustomWeek.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace DB diff --git a/src/Functions/toFixedString.h b/src/Functions/toFixedString.h index 1d6b79cb583..fe437a24303 100644 --- a/src/Functions/toFixedString.h +++ b/src/Functions/toFixedString.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/Functions/toLowCardinality.cpp b/src/Functions/toLowCardinality.cpp index 53cf1e9fea8..983e66d1007 100644 --- a/src/Functions/toLowCardinality.cpp +++ b/src/Functions/toLowCardinality.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/toModifiedJulianDay.cpp b/src/Functions/toModifiedJulianDay.cpp index fe03fcb1bda..a44979b52ff 100644 --- a/src/Functions/toModifiedJulianDay.cpp +++ b/src/Functions/toModifiedJulianDay.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/toNullable.cpp b/src/Functions/toNullable.cpp index 0f9a4a437f6..5e383893476 100644 --- a/src/Functions/toNullable.cpp +++ b/src/Functions/toNullable.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/toStartOfInterval.cpp b/src/Functions/toStartOfInterval.cpp index b7716501d02..ee592fbb1e3 100644 --- a/src/Functions/toStartOfInterval.cpp +++ b/src/Functions/toStartOfInterval.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Functions/toTimezone.cpp b/src/Functions/toTimezone.cpp index 58ebb67ce17..551e07a8354 100644 --- a/src/Functions/toTimezone.cpp +++ b/src/Functions/toTimezone.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/src/Functions/toTypeName.cpp b/src/Functions/toTypeName.cpp index 556cb7d7877..4c7b00e74ed 100644 --- a/src/Functions/toTypeName.cpp +++ b/src/Functions/toTypeName.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/today.cpp b/src/Functions/today.cpp index 8e481700a9e..43be4c4582a 100644 --- a/src/Functions/today.cpp +++ b/src/Functions/today.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include diff --git a/src/Functions/transform.cpp b/src/Functions/transform.cpp index 1e4d12b82af..1debc2cb6a0 100644 --- a/src/Functions/transform.cpp +++ b/src/Functions/transform.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Functions/tuple.cpp b/src/Functions/tuple.cpp index e527fcd7a73..dda034ee911 100644 --- a/src/Functions/tuple.cpp +++ b/src/Functions/tuple.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/tupleElement.cpp b/src/Functions/tupleElement.cpp index 8dadda3f14f..97e2f70fccf 100644 --- a/src/Functions/tupleElement.cpp +++ b/src/Functions/tupleElement.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/uptime.cpp b/src/Functions/uptime.cpp index a5561c709e8..02454df4de5 100644 --- a/src/Functions/uptime.cpp +++ b/src/Functions/uptime.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/validateNestedArraySizes.cpp b/src/Functions/validateNestedArraySizes.cpp index b589b1e2e5c..1d96f988690 100644 --- a/src/Functions/validateNestedArraySizes.cpp +++ b/src/Functions/validateNestedArraySizes.cpp @@ -59,13 +59,26 @@ DataTypePtr FunctionValidateNestedArraySizes::getReturnTypeImpl(const DataTypes ColumnPtr FunctionValidateNestedArraySizes::executeImpl( const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const { + bool is_condition_const = false; + bool condition = false; const ColumnUInt8 * condition_column = typeid_cast(arguments[0].column.get()); + if (!condition_column) + { + if (checkAndGetColumnConst(arguments[0].column.get())) + { + is_condition_const = true; + condition = arguments[0].column->getBool(0); + } + } size_t args_num = arguments.size(); for (size_t i = 0; i < input_rows_count; ++i) { - if (!condition_column->getData()[i]) + if (is_condition_const && !condition) + break; + + if (!is_condition_const && !condition_column->getData()[i]) continue; /// The condition is true, then check the row in subcolumns in Nested Type has the same array size diff --git a/src/Functions/version.cpp b/src/Functions/version.cpp index 833816d6057..4e0ddf60975 100644 --- a/src/Functions/version.cpp +++ b/src/Functions/version.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/visibleWidth.cpp b/src/Functions/visibleWidth.cpp index 137b39994b1..6e96a4844ce 100644 --- a/src/Functions/visibleWidth.cpp +++ b/src/Functions/visibleWidth.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/Functions/ya.make b/src/Functions/ya.make index fcc92da6fcc..2a541369ff4 100644 --- a/src/Functions/ya.make +++ b/src/Functions/ya.make @@ -74,7 +74,6 @@ SRCS( GatherUtils/sliceFromRightConstantOffsetUnbounded.cpp GeoHash.cpp IFunction.cpp - IFunctionOld.cpp TargetSpecific.cpp URL/URLHierarchy.cpp URL/URLPathHierarchy.cpp diff --git a/src/Functions/yesterday.cpp b/src/Functions/yesterday.cpp index 4fdbf34a968..737552e192e 100644 --- a/src/Functions/yesterday.cpp +++ b/src/Functions/yesterday.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include diff --git a/src/Interpreters/InterpreterDropQuery.cpp b/src/Interpreters/InterpreterDropQuery.cpp index 0b4efe4f978..24cff90caea 100644 --- a/src/Interpreters/InterpreterDropQuery.cpp +++ b/src/Interpreters/InterpreterDropQuery.cpp @@ -171,7 +171,7 @@ BlockIO InterpreterDropQuery::executeToTableImpl(ASTDropQuery & query, DatabaseP else table->checkTableCanBeDetached(); - table->shutdown(); + table->flushAndShutdown(); TableExclusiveLockHolder table_lock; if (database->getUUID() == UUIDHelpers::Nil) @@ -215,7 +215,7 @@ BlockIO InterpreterDropQuery::executeToTableImpl(ASTDropQuery & query, DatabaseP else table->checkTableCanBeDropped(); - table->shutdown(); + table->flushAndShutdown(); TableExclusiveLockHolder table_lock; if (database->getUUID() == UUIDHelpers::Nil) @@ -253,7 +253,7 @@ BlockIO InterpreterDropQuery::executeToTemporaryTable(const String & table_name, else if (kind == ASTDropQuery::Kind::Drop) { context_handle->removeExternalTable(table_name); - table->shutdown(); + table->flushAndShutdown(); auto table_lock = table->lockExclusively(getContext()->getCurrentQueryId(), getContext()->getSettingsRef().lock_acquire_timeout); /// Delete table data table->drop(); @@ -328,6 +328,14 @@ BlockIO InterpreterDropQuery::executeToDatabaseImpl(const ASTDropQuery & query, query_for_table.database = database_name; query_for_table.no_delay = query.no_delay; + /// Flush should not be done if shouldBeEmptyOnDetach() == false, + /// since in this case getTablesIterator() may do some additional work, + /// see DatabaseMaterializeMySQL<>::getTablesIterator() + for (auto iterator = database->getTablesIterator(getContext()); iterator->isValid(); iterator->next()) + { + iterator->table()->flush(); + } + for (auto iterator = database->getTablesIterator(getContext()); iterator->isValid(); iterator->next()) { DatabasePtr db; diff --git a/src/Interpreters/InterpreterInsertQuery.cpp b/src/Interpreters/InterpreterInsertQuery.cpp index c24cd6b4efc..9b3d1bcebd7 100644 --- a/src/Interpreters/InterpreterInsertQuery.cpp +++ b/src/Interpreters/InterpreterInsertQuery.cpp @@ -309,8 +309,7 @@ BlockIO InterpreterInsertQuery::execute() auto out_wrapper = std::make_shared(out); out_wrapper->setProcessListElement(getContext()->getProcessListElement()); - out = std::move(out_wrapper); - out_streams.emplace_back(std::move(out)); + out_streams.emplace_back(std::move(out_wrapper)); } } diff --git a/src/Interpreters/InterpreterSystemQuery.cpp b/src/Interpreters/InterpreterSystemQuery.cpp index 8a4b3b07692..e7babb9b83f 100644 --- a/src/Interpreters/InterpreterSystemQuery.cpp +++ b/src/Interpreters/InterpreterSystemQuery.cpp @@ -436,7 +436,7 @@ StoragePtr InterpreterSystemQuery::tryRestartReplica(const StorageID & replica, if (!table || !dynamic_cast(table.get())) return nullptr; - table->shutdown(); + table->flushAndShutdown(); { /// If table was already dropped by anyone, an exception will be thrown auto table_lock = table->lockExclusively(getContext()->getCurrentQueryId(), getContext()->getSettingsRef().lock_acquire_timeout); diff --git a/src/Interpreters/JIT/CompileDAG.h b/src/Interpreters/JIT/CompileDAG.h index 87228c83d5c..ee9cc5cc83a 100644 --- a/src/Interpreters/JIT/CompileDAG.h +++ b/src/Interpreters/JIT/CompileDAG.h @@ -12,7 +12,7 @@ #include #include -#include +#include namespace llvm { diff --git a/src/Interpreters/SystemLog.h b/src/Interpreters/SystemLog.h index aa01ca3517b..074586efe3d 100644 --- a/src/Interpreters/SystemLog.h +++ b/src/Interpreters/SystemLog.h @@ -153,7 +153,7 @@ public: { stopFlushThread(); if (table) - table->shutdown(); + table->flushAndShutdown(); } String getName() override diff --git a/src/Storages/HDFS/StorageHDFS.cpp b/src/Storages/HDFS/StorageHDFS.cpp index 989f35c4005..68c2d022ab8 100644 --- a/src/Storages/HDFS/StorageHDFS.cpp +++ b/src/Storages/HDFS/StorageHDFS.cpp @@ -202,9 +202,18 @@ public: void writeSuffix() override { - writer->writeSuffix(); - writer->flush(); - write_buf->sync(); + try + { + writer->writeSuffix(); + writer->flush(); + write_buf->sync(); + write_buf->finalize(); + } + catch (...) + { + writer.reset(); + throw; + } } private: diff --git a/src/Storages/HDFS/WriteBufferFromHDFS.cpp b/src/Storages/HDFS/WriteBufferFromHDFS.cpp index 3873eace10d..c1323df86f0 100644 --- a/src/Storages/HDFS/WriteBufferFromHDFS.cpp +++ b/src/Storages/HDFS/WriteBufferFromHDFS.cpp @@ -33,12 +33,13 @@ struct WriteBufferFromHDFS::WriteBufferFromHDFSImpl , fs(createHDFSFS(builder.get())) { const size_t begin_of_path = hdfs_uri.find('/', hdfs_uri.find("//") + 2); - const std::string path = hdfs_uri.substr(begin_of_path); + const String path = hdfs_uri.substr(begin_of_path); if (path.find_first_of("*?{") != std::string::npos) throw Exception("URI '" + hdfs_uri + "' contains globs, so the table is in readonly mode", ErrorCodes::CANNOT_OPEN_FILE); if (!hdfsExists(fs.get(), path.c_str())) throw Exception("File: " + path + " is already exists", ErrorCodes::BAD_ARGUMENTS); + fout = hdfsOpenFile(fs.get(), path.c_str(), O_WRONLY, 0, 0, 0); /// O_WRONLY meaning create or overwrite i.e., implies O_TRUNCAT here if (fout == nullptr) @@ -58,9 +59,11 @@ struct WriteBufferFromHDFS::WriteBufferFromHDFSImpl int write(const char * start, size_t size) const { int bytes_written = hdfsWrite(fs.get(), fout, start, size); + if (bytes_written < 0) throw Exception("Fail to write HDFS file: " + hdfs_uri + " " + std::string(hdfsGetLastError()), ErrorCodes::NETWORK_ERROR); + return bytes_written; } @@ -97,7 +100,8 @@ void WriteBufferFromHDFS::sync() impl->sync(); } -WriteBufferFromHDFS::~WriteBufferFromHDFS() + +void WriteBufferFromHDFS::finalize() { try { @@ -109,5 +113,11 @@ WriteBufferFromHDFS::~WriteBufferFromHDFS() } } + +WriteBufferFromHDFS::~WriteBufferFromHDFS() +{ + finalize(); +} + } #endif diff --git a/src/Storages/HDFS/WriteBufferFromHDFS.h b/src/Storages/HDFS/WriteBufferFromHDFS.h index 339ec0c2a7c..a28caaf60ee 100644 --- a/src/Storages/HDFS/WriteBufferFromHDFS.h +++ b/src/Storages/HDFS/WriteBufferFromHDFS.h @@ -13,19 +13,23 @@ namespace DB /** Accepts HDFS path to file and opens it. * Closes file by himself (thus "owns" a file descriptor). */ -class WriteBufferFromHDFS : public BufferWithOwnMemory +class WriteBufferFromHDFS final : public BufferWithOwnMemory { struct WriteBufferFromHDFSImpl; std::unique_ptr impl; + public: WriteBufferFromHDFS(const std::string & hdfs_name_, const Poco::Util::AbstractConfiguration &, size_t buf_size_ = DBMS_DEFAULT_BUFFER_SIZE); - WriteBufferFromHDFS(WriteBufferFromHDFS &&) = default; - void nextImpl() override; + WriteBufferFromHDFS(WriteBufferFromHDFS &&) = default; ~WriteBufferFromHDFS() override; + void nextImpl() override; + void sync() override; + + void finalize() override; }; } #endif diff --git a/src/Storages/IStorage.h b/src/Storages/IStorage.h index 6e2ea6aa866..a96748ceb63 100644 --- a/src/Storages/IStorage.h +++ b/src/Storages/IStorage.h @@ -444,6 +444,21 @@ public: */ virtual void startup() {} + /** + * If the storage requires some complicated work on destroying, + * then you have two virtual methods: + * - flush() + * - shutdown() + * + * @see shutdown() + * @see flush() + */ + void flushAndShutdown() + { + flush(); + shutdown(); + } + /** If the table have to do some complicated work when destroying an object - do it in advance. * For example, if the table contains any threads for background work - ask them to complete and wait for completion. * By default, does nothing. @@ -451,6 +466,10 @@ public: */ virtual void shutdown() {} + /// Called before shutdown() to flush data to underlying storage + /// (for Buffer) + virtual void flush() {} + /// Asks table to stop executing some action identified by action_type /// If table does not support such type of lock, and empty lock is returned virtual ActionLock getActionLock(StorageActionBlockType /* action_type */) diff --git a/src/Storages/MergeTree/IMergeTreeDataPart.h b/src/Storages/MergeTree/IMergeTreeDataPart.h index 2752456ee6a..38aeb15ebeb 100644 --- a/src/Storages/MergeTree/IMergeTreeDataPart.h +++ b/src/Storages/MergeTree/IMergeTreeDataPart.h @@ -45,11 +45,6 @@ class IMergeTreeDataPartWriter; class MarkCache; class UncompressedCache; - -namespace ErrorCodes -{ -} - /// Description of the data part. class IMergeTreeDataPart : public std::enable_shared_from_this { diff --git a/src/Storages/MergeTree/MergeTreeData.cpp b/src/Storages/MergeTree/MergeTreeData.cpp index 6f6466880d5..41adca37c60 100644 --- a/src/Storages/MergeTree/MergeTreeData.cpp +++ b/src/Storages/MergeTree/MergeTreeData.cpp @@ -649,7 +649,7 @@ void MergeTreeData::MergingParams::check(const StorageInMemoryMetadata & metadat throw Exception("The column " + version_column + " cannot be used as a version column for storage " + storage + " because it is of type " + column.type->getName() + - " (must be of an integer type or of type Date or DateTime)", ErrorCodes::BAD_TYPE_OF_FIELD); + " (must be of an integer type or of type Date/DateTime/DateTime64)", ErrorCodes::BAD_TYPE_OF_FIELD); miss_column = false; break; } @@ -2351,7 +2351,7 @@ MergeTreeData::DataPartsVector MergeTreeData::removePartsInRangeFromWorkingSet(c DataPartsVector parts_to_remove; if (drop_range.min_block > drop_range.max_block) - return parts_to_remove; + throw Exception(ErrorCodes::LOGICAL_ERROR, "Invalid drop range: {}", drop_range.getPartName()); auto partition_range = getDataPartsPartitionRange(drop_range.partition_id); diff --git a/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp b/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp index 8dec315e61b..0c3b0998a55 100644 --- a/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp +++ b/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp @@ -890,18 +890,25 @@ bool ReplicatedMergeTreeQueue::checkReplaceRangeCanBeRemoved(const MergeTreePart { if (entry_ptr->type != LogEntry::REPLACE_RANGE) return false; + assert(entry_ptr->replace_range_entry); if (current.type != LogEntry::REPLACE_RANGE && current.type != LogEntry::DROP_RANGE) return false; - if (entry_ptr->replace_range_entry != nullptr && entry_ptr->replace_range_entry == current.replace_range_entry) /// same partition, don't want to drop ourselves + if (entry_ptr->replace_range_entry == current.replace_range_entry) /// same partition, don't want to drop ourselves return false; + size_t number_of_covered_parts = 0; for (const String & new_part_name : entry_ptr->replace_range_entry->new_part_names) - if (!part_info.contains(MergeTreePartInfo::fromPartName(new_part_name, format_version))) - return false; + { + if (part_info.contains(MergeTreePartInfo::fromPartName(new_part_name, format_version))) + ++number_of_covered_parts; + } - return true; + /// It must either cover all new parts from REPLACE_RANGE or no one. Otherwise it's a bug in replication, + /// which may lead to intersecting entries. + assert(number_of_covered_parts == 0 || number_of_covered_parts == entry_ptr->replace_range_entry->new_part_names.size()); + return number_of_covered_parts == entry_ptr->replace_range_entry->new_part_names.size(); } void ReplicatedMergeTreeQueue::removePartProducingOpsInRange( diff --git a/src/Storages/StorageBuffer.cpp b/src/Storages/StorageBuffer.cpp index a3ad3f3f13f..6688112c9f1 100644 --- a/src/Storages/StorageBuffer.cpp +++ b/src/Storages/StorageBuffer.cpp @@ -674,7 +674,7 @@ void StorageBuffer::startup() } -void StorageBuffer::shutdown() +void StorageBuffer::flush() { if (!flush_handle) return; diff --git a/src/Storages/StorageBuffer.h b/src/Storages/StorageBuffer.h index 586b6426407..d9cb22ef446 100644 --- a/src/Storages/StorageBuffer.h +++ b/src/Storages/StorageBuffer.h @@ -88,7 +88,7 @@ public: void startup() override; /// Flush all buffers into the subordinate table and stop background thread. - void shutdown() override; + void flush() override; bool optimize( const ASTPtr & query, const StorageMetadataPtr & metadata_snapshot, diff --git a/src/Storages/StorageMemory.cpp b/src/Storages/StorageMemory.cpp index 289a17366bb..13d5df866bc 100644 --- a/src/Storages/StorageMemory.cpp +++ b/src/Storages/StorageMemory.cpp @@ -311,8 +311,8 @@ void StorageMemory::mutate(const MutationCommands & commands, ContextPtr context rows += buffer.rows(); bytes += buffer.bytes(); } - total_size_bytes.store(rows, std::memory_order_relaxed); - total_size_rows.store(bytes, std::memory_order_relaxed); + total_size_bytes.store(bytes, std::memory_order_relaxed); + total_size_rows.store(rows, std::memory_order_relaxed); data.set(std::move(new_data)); } diff --git a/src/Storages/StorageProxy.h b/src/Storages/StorageProxy.h index 205440261b8..60e7bf24046 100644 --- a/src/Storages/StorageProxy.h +++ b/src/Storages/StorageProxy.h @@ -133,6 +133,7 @@ public: void startup() override { getNested()->startup(); } void shutdown() override { getNested()->shutdown(); } + void flush() override { getNested()->flush(); } ActionLock getActionLock(StorageActionBlockType action_type) override { return getNested()->getActionLock(action_type); } diff --git a/src/Storages/StorageReplicatedMergeTree.cpp b/src/Storages/StorageReplicatedMergeTree.cpp index a4a959c9fba..e8036dd51f2 100644 --- a/src/Storages/StorageReplicatedMergeTree.cpp +++ b/src/Storages/StorageReplicatedMergeTree.cpp @@ -587,6 +587,8 @@ void StorageReplicatedMergeTree::createNewZooKeeperNodes() /// Part movement. zookeeper->createIfNotExists(zookeeper_path + "/part_moves_shard", String()); zookeeper->createIfNotExists(zookeeper_path + "/pinned_part_uuids", getPinnedPartUUIDs()->toString()); + /// For ALTER PARTITION with multi-leaders + zookeeper->createIfNotExists(zookeeper_path + "/alter_partition_version", String()); } @@ -6298,6 +6300,10 @@ void StorageReplicatedMergeTree::replacePartitionFrom( static const String TMP_PREFIX = "tmp_replace_from_"; auto zookeeper = getZooKeeper(); + String alter_partition_version_path = zookeeper_path + "/alter_partition_version"; + Coordination::Stat alter_partition_version_stat; + zookeeper->get(alter_partition_version_path, &alter_partition_version_stat); + /// Firstly, generate last block number and compute drop_range /// NOTE: Even if we make ATTACH PARTITION instead of REPLACE PARTITION drop_range will not be empty, it will contain a block. /// So, such case has special meaning, if drop_range contains only one block it means that nothing to drop. @@ -6381,10 +6387,6 @@ void StorageReplicatedMergeTree::replacePartitionFrom( entry_replace.columns_version = -1; } - /// We are almost ready to commit changes, remove fetches and merges from drop range - /// FIXME it's unsafe to remove queue entries before we actually commit REPLACE_RANGE to replication log - queue.removePartProducingOpsInRange(zookeeper, drop_range, entry); - /// Remove deduplication block_ids of replacing parts if (replace) clearBlocksInPartition(*zookeeper, drop_range.partition_id, drop_range.max_block, drop_range.max_block); @@ -6412,6 +6414,9 @@ void StorageReplicatedMergeTree::replacePartitionFrom( txn->moveOpsTo(ops); delimiting_block_lock->getUnlockOps(ops); + /// Check and update version to avoid race with DROP_RANGE + ops.emplace_back(zkutil::makeCheckRequest(alter_partition_version_path, alter_partition_version_stat.version)); + ops.emplace_back(zkutil::makeSetRequest(alter_partition_version_path, "", -1)); /// Just update version, because merges assignment relies on it ops.emplace_back(zkutil::makeSetRequest(zookeeper_path + "/log", "", -1)); ops.emplace_back(zkutil::makeCreateRequest(zookeeper_path + "/log/log-", entry.toString(), zkutil::CreateMode::PersistentSequential)); @@ -6424,8 +6429,13 @@ void StorageReplicatedMergeTree::replacePartitionFrom( renameTempPartAndReplace(part, nullptr, &transaction, data_parts_lock); } - op_results = zookeeper->multi(ops); - delimiting_block_lock->assumeUnlocked(); + Coordination::Error code = zookeeper->tryMulti(ops, op_results); + if (code == Coordination::Error::ZOK) + delimiting_block_lock->assumeUnlocked(); + else if (code == Coordination::Error::ZBADVERSION) + throw Exception(ErrorCodes::CANNOT_ASSIGN_ALTER, "Cannot assign ALTER PARTITION, because another ALTER PARTITION query was concurrently executed"); + else + zkutil::KeeperMultiException::check(code, ops, op_results); { auto data_parts_lock = lockParts(); @@ -6509,6 +6519,10 @@ void StorageReplicatedMergeTree::movePartitionToTable(const StoragePtr & dest_ta /// Clone parts into destination table. + String alter_partition_version_path = dest_table_storage->zookeeper_path + "/alter_partition_version"; + Coordination::Stat alter_partition_version_stat; + zookeeper->get(alter_partition_version_path, &alter_partition_version_stat); + for (const auto & src_part : src_all_parts) { if (!dest_table_storage->canReplacePartition(src_part)) @@ -6568,8 +6582,6 @@ void StorageReplicatedMergeTree::movePartitionToTable(const StoragePtr & dest_ta entry_replace.columns_version = -1; } - queue.removePartProducingOpsInRange(zookeeper, drop_range, entry); - clearBlocksInPartition(*zookeeper, drop_range.partition_id, drop_range.max_block, drop_range.max_block); DataPartsVector parts_to_remove; @@ -6590,6 +6602,11 @@ void StorageReplicatedMergeTree::movePartitionToTable(const StoragePtr & dest_ta } } + /// Check and update version to avoid race with DROP_RANGE + ops.emplace_back(zkutil::makeCheckRequest(alter_partition_version_path, alter_partition_version_stat.version)); + ops.emplace_back(zkutil::makeSetRequest(alter_partition_version_path, "", -1)); + /// Just update version, because merges assignment relies on it + ops.emplace_back(zkutil::makeSetRequest(dest_table_storage->zookeeper_path + "/log", "", -1)); ops.emplace_back(zkutil::makeCreateRequest(dest_table_storage->zookeeper_path + "/log/log-", entry.toString(), zkutil::CreateMode::PersistentSequential)); @@ -6605,7 +6622,11 @@ void StorageReplicatedMergeTree::movePartitionToTable(const StoragePtr & dest_ta for (MutableDataPartPtr & part : dst_parts) dest_table_storage->renameTempPartAndReplace(part, nullptr, &transaction, lock); - op_results = zookeeper->multi(ops); + Coordination::Error code = zookeeper->tryMulti(ops, op_results); + if (code == Coordination::Error::ZBADVERSION) + throw Exception(ErrorCodes::CANNOT_ASSIGN_ALTER, "Cannot assign ALTER PARTITION, because another ALTER PARTITION query was concurrently executed"); + else + zkutil::KeeperMultiException::check(code, ops, op_results); parts_to_remove = removePartsInRangeFromWorkingSet(drop_range, true, lock); transaction.commit(&lock); @@ -6636,16 +6657,27 @@ void StorageReplicatedMergeTree::movePartitionToTable(const StoragePtr & dest_ta dest_table_storage->waitForAllReplicasToProcessLogEntry(entry); } - Coordination::Requests ops_src; + /// Create DROP_RANGE for the source table + alter_partition_version_path = zookeeper_path + "/alter_partition_version"; + zookeeper->get(alter_partition_version_path, &alter_partition_version_stat); + Coordination::Requests ops_src; ops_src.emplace_back(zkutil::makeCreateRequest( zookeeper_path + "/log/log-", entry_delete.toString(), zkutil::CreateMode::PersistentSequential)); + /// Check and update version to avoid race with REPLACE_RANGE + ops_src.emplace_back(zkutil::makeCheckRequest(alter_partition_version_path, alter_partition_version_stat.version)); + ops_src.emplace_back(zkutil::makeSetRequest(alter_partition_version_path, "", -1)); /// Just update version, because merges assignment relies on it ops_src.emplace_back(zkutil::makeSetRequest(zookeeper_path + "/log", "", -1)); delimiting_block_lock->getUnlockOps(ops_src); - op_results = zookeeper->multi(ops_src); - delimiting_block_lock->assumeUnlocked(); + Coordination::Error code = zookeeper->tryMulti(ops_src, op_results); + if (code == Coordination::Error::ZBADVERSION) + throw Exception(ErrorCodes::CANNOT_ASSIGN_ALTER, "Cannot DROP PARTITION in {} after copying partition to {}, " + "because another ALTER PARTITION query was concurrently executed", + getStorageID().getFullTableName(), dest_table_storage->getStorageID().getFullTableName()); + else + zkutil::KeeperMultiException::check(code, ops_src, op_results); log_znode_path = dynamic_cast(*op_results.front()).path_created; entry_delete.znode_name = log_znode_path.substr(log_znode_path.find_last_of('/') + 1); @@ -6972,6 +7004,10 @@ bool StorageReplicatedMergeTree::dropPart( bool StorageReplicatedMergeTree::dropAllPartsInPartition( zkutil::ZooKeeper & zookeeper, String & partition_id, LogEntry & entry, ContextPtr query_context, bool detach) { + String alter_partition_version_path = zookeeper_path + "/alter_partition_version"; + Coordination::Stat alter_partition_version_stat; + zookeeper.get(alter_partition_version_path, &alter_partition_version_stat); + MergeTreePartInfo drop_range_info; /// It prevent other replicas from assigning merges which intersect locked block number. std::optional delimiting_block_lock; @@ -6996,13 +7032,24 @@ bool StorageReplicatedMergeTree::dropAllPartsInPartition( Coordination::Requests ops; ops.emplace_back(zkutil::makeCreateRequest(zookeeper_path + "/log/log-", entry.toString(), zkutil::CreateMode::PersistentSequential)); + /// Check and update version to avoid race with REPLACE_RANGE. + /// Otherwise new parts covered by drop_range_info may appear after execution of current DROP_RANGE entry + /// as a result of execution of concurrently created REPLACE_RANGE entry. + ops.emplace_back(zkutil::makeCheckRequest(alter_partition_version_path, alter_partition_version_stat.version)); + ops.emplace_back(zkutil::makeSetRequest(alter_partition_version_path, "", -1)); /// Just update version, because merges assignment relies on it ops.emplace_back(zkutil::makeSetRequest(zookeeper_path + "/log", "", -1)); delimiting_block_lock->getUnlockOps(ops); if (auto txn = query_context->getZooKeeperMetadataTransaction()) txn->moveOpsTo(ops); - Coordination::Responses responses = zookeeper.multi(ops); - delimiting_block_lock->assumeUnlocked(); + Coordination::Responses responses; + Coordination::Error code = zookeeper.tryMulti(ops, responses); + if (code == Coordination::Error::ZOK) + delimiting_block_lock->assumeUnlocked(); + else if (code == Coordination::Error::ZBADVERSION) + throw Exception(ErrorCodes::CANNOT_ASSIGN_ALTER, "Cannot assign ALTER PARTITION, because another ALTER PARTITION query was concurrently executed"); + else + zkutil::KeeperMultiException::check(code, ops, responses); String log_znode_path = dynamic_cast(*responses.front()).path_created; entry.znode_name = log_znode_path.substr(log_znode_path.find_last_of('/') + 1); diff --git a/src/Storages/StorageTableFunction.h b/src/Storages/StorageTableFunction.h index 7d909165d5f..e6f21c44fc3 100644 --- a/src/Storages/StorageTableFunction.h +++ b/src/Storages/StorageTableFunction.h @@ -62,6 +62,13 @@ public: nested->shutdown(); } + void flush() override + { + std::lock_guard lock{nested_mutex}; + if (nested) + nested->flush(); + } + void drop() override { std::lock_guard lock{nested_mutex}; diff --git a/src/Storages/System/StorageSystemStackTrace.cpp b/src/Storages/System/StorageSystemStackTrace.cpp index a6651aff8be..406e154029d 100644 --- a/src/Storages/System/StorageSystemStackTrace.cpp +++ b/src/Storages/System/StorageSystemStackTrace.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,7 @@ NamesAndTypesList StorageSystemStackTrace::getNamesAndTypes() { return { + { "thread_name", std::make_shared() }, { "thread_id", std::make_shared() }, { "query_id", std::make_shared() }, { "trace", std::make_shared(std::make_shared()) } @@ -213,6 +215,18 @@ void StorageSystemStackTrace::fillData(MutableColumns & res_columns, ContextPtr, throwFromErrno("Cannot send signal with sigqueue", ErrorCodes::CANNOT_SIGQUEUE); } + std::filesystem::path thread_name_path = it->path(); + thread_name_path.append("comm"); + + String thread_name; + if (std::filesystem::exists(thread_name_path)) + { + constexpr size_t comm_buf_size = 32; /// More than enough for thread name + ReadBufferFromFile comm(thread_name_path.string(), comm_buf_size); + readStringUntilEOF(thread_name, comm); + comm.close(); + } + /// Just in case we will wait for pipe with timeout. In case signal didn't get processed. if (wait(100) && sig_value.sival_int == data_ready_num.load(std::memory_order_acquire)) @@ -225,9 +239,10 @@ void StorageSystemStackTrace::fillData(MutableColumns & res_columns, ContextPtr, for (size_t i = stack_trace_offset; i < stack_trace_size; ++i) arr.emplace_back(reinterpret_cast(stack_trace.getFramePointers()[i])); - res_columns[0]->insert(tid); - res_columns[1]->insertData(query_id_data, query_id_size); - res_columns[2]->insert(arr); + res_columns[0]->insert(thread_name); + res_columns[1]->insert(tid); + res_columns[2]->insertData(query_id_data, query_id_size); + res_columns[3]->insert(arr); } else { @@ -235,9 +250,10 @@ void StorageSystemStackTrace::fillData(MutableColumns & res_columns, ContextPtr, /// Cannot obtain a stack trace. But create a record in result nevertheless. - res_columns[0]->insert(tid); - res_columns[1]->insertDefault(); + res_columns[0]->insert(thread_name); + res_columns[1]->insert(tid); res_columns[2]->insertDefault(); + res_columns[3]->insertDefault(); } /// Signed integer overflow is undefined behavior in both C and C++. However, according to diff --git a/src/Storages/tests/gtest_storage_log.cpp b/src/Storages/tests/gtest_storage_log.cpp index e18e4b40ac9..e8057c54a0f 100644 --- a/src/Storages/tests/gtest_storage_log.cpp +++ b/src/Storages/tests/gtest_storage_log.cpp @@ -53,7 +53,7 @@ public: void TearDown() override { - table->shutdown(); + table->flushAndShutdown(); destroyDisk(disk); } diff --git a/tests/integration/test_jbod_balancer/test.py b/tests/integration/test_jbod_balancer/test.py index abc6a0bff11..ef0308cc658 100644 --- a/tests/integration/test_jbod_balancer/test.py +++ b/tests/integration/test_jbod_balancer/test.py @@ -92,7 +92,10 @@ def test_jbod_balanced_merge(start_cluster): node1.query("create table tmp1 as tbl") node1.query("create table tmp2 as tbl") - for i in range(200): + p = Pool(20) + + def task(i): + print("Processing insert {}/{}".format(i, 200)) # around 1k per block node1.query( "insert into tbl select randConstant() % 2, randomPrintableASCII(16) from numbers(50)" @@ -104,6 +107,8 @@ def test_jbod_balanced_merge(start_cluster): "insert into tmp2 select randConstant() % 2, randomPrintableASCII(16) from numbers(50)" ) + p.map(task, range(200)) + time.sleep(1) check_balance(node1, "tbl") @@ -151,8 +156,10 @@ def test_replicated_balanced_merge_fetch(start_cluster): node.query("create table tmp2 as tmp1") node2.query("alter table tbl modify setting always_fetch_merged_part = 1") + p = Pool(20) - for i in range(200): + def task(i): + print("Processing insert {}/{}".format(i, 200)) # around 1k per block node1.query( "insert into tbl select randConstant() % 2, randomPrintableASCII(16) from numbers(50)" @@ -170,6 +177,8 @@ def test_replicated_balanced_merge_fetch(start_cluster): "insert into tmp2 select randConstant() % 2, randomPrintableASCII(16) from numbers(50)" ) + p.map(task, range(200)) + node2.query("SYSTEM SYNC REPLICA tbl", timeout=10) check_balance(node1, "tbl") diff --git a/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.reference b/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.reference index 5aaf21f9137..29777b0c05c 100644 --- a/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.reference +++ b/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.reference @@ -8,7 +8,9 @@ 3 3 4 4 5 5 +5 2 2 3 3 4 4 5 5 +4 diff --git a/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.sql b/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.sql index 408487ed205..0e2861b8e94 100644 --- a/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.sql +++ b/tests/queries/0_stateless/01497_mutation_support_for_storage_memory.sql @@ -13,8 +13,12 @@ ALTER TABLE defaults UPDATE n = 100 WHERE s = '1'; SELECT * FROM defaults; +SELECT count(*) FROM defaults; + ALTER TABLE defaults DELETE WHERE n = 100; SELECT * FROM defaults; +SELECT count(*) FROM defaults; + DROP TABLE defaults; diff --git a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference index c6f75cab8b7..48c30f97cd6 100644 --- a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference +++ b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.reference @@ -1,3 +1,4 @@ +********* test 1 ********** 1 [100,200] ['aa','bb'] [1,2] 0 [0,1] ['aa','bb'] [0,0] 1 [100,200] ['aa','bb'] [1,2] @@ -14,6 +15,13 @@ 2 [100,200,300] ['a','b','c'] [100,200,300] 3 [68,72] ['aa','bb'] [68,72] 4 [4,5] ['aa','bb'] [4,8] +********* test 2 ********** +0 [0,1] ['aa','bb'] [0,0] [0,1] ['aa','bb'] +1 [1,2] ['aa','bb'] [1,2] [1,2] ['aa','bb'] +2 [2,3] ['aa','bb'] [2,4] [2,3] ['aa','bb'] +3 [3,4] ['aa','bb'] [3,6] [3,4] ['aa','bb'] +4 [4,5] ['aa','bb'] [4,8] [4,5] ['aa','bb'] +********* test 3 ********** 0 0 aa 0 1 1 bb 2 2 2 aa 4 diff --git a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql index 8e850b70c24..accb785ba03 100644 --- a/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql +++ b/tests/queries/0_stateless/01788_update_nested_type_subcolumn_check.sql @@ -11,6 +11,7 @@ ENGINE = MergeTree ORDER BY tuple() SETTINGS min_bytes_for_wide_part = 0; +SELECT '********* test 1 **********'; set mutations_sync = 1; INSERT INTO test_wide_nested SELECT number, [number,number + 1], ['aa','bb'], [number,number * 2] FROM numbers(5); @@ -31,6 +32,7 @@ select * from test_wide_nested; alter table test_wide_nested update `info.id` = [100,200], `info.age` = [10,20,30], `info.name` = ['a','b','c'] where id = 0; -- { serverError 341 } -- Recreate table, because KILL MUTATION is not suitable for parallel tests execution. +SELECT '********* test 2 **********'; DROP TABLE test_wide_nested; CREATE TABLE test_wide_nested @@ -45,11 +47,16 @@ ORDER BY tuple() SETTINGS min_bytes_for_wide_part = 0; INSERT INTO test_wide_nested SELECT number, [number,number + 1], ['aa','bb'], [number,number * 2] FROM numbers(5); +ALTER TABLE test_wide_nested ADD COLUMN `info2.id` Array(Int); +ALTER TABLE test_wide_nested ADD COLUMN `info2.name` Array(String); +ALTER table test_wide_nested update `info2.id` = `info.id`, `info2.name` = `info.name` where 1; +select * from test_wide_nested; alter table test_wide_nested update `info.id` = [100,200,300], `info.age` = [10,20,30] where id = 1; -- { serverError 341 } DROP TABLE test_wide_nested; +SELECT '********* test 3 **********'; DROP TABLE IF EXISTS test_wide_not_nested; CREATE TABLE test_wide_not_nested diff --git a/tests/queries/0_stateless/01867_support_datetime64_version_column.reference b/tests/queries/0_stateless/01867_support_datetime64_version_column.reference new file mode 100644 index 00000000000..3a6dbdc870c --- /dev/null +++ b/tests/queries/0_stateless/01867_support_datetime64_version_column.reference @@ -0,0 +1,3 @@ +1 1970-01-01 08:25:46.300800003 a1 +2 1970-01-01 08:25:46.300800005 a1 +3 1970-01-01 08:25:46.300800005 c1 diff --git a/tests/queries/0_stateless/01867_support_datetime64_version_column.sql b/tests/queries/0_stateless/01867_support_datetime64_version_column.sql new file mode 100644 index 00000000000..f4427be635a --- /dev/null +++ b/tests/queries/0_stateless/01867_support_datetime64_version_column.sql @@ -0,0 +1,16 @@ +drop table if exists replacing; +create table replacing( `A` Int64, `D` DateTime64(9), `S` String) ENGINE = ReplacingMergeTree(D) ORDER BY A; + +insert into replacing values (1,'1970-01-01 08:25:46.300800000','a'); +insert into replacing values (2,'1970-01-01 08:25:46.300800002','b'); +insert into replacing values (1,'1970-01-01 08:25:46.300800003','a1'); +insert into replacing values (1,'1970-01-01 08:25:46.300800002','a2'); +insert into replacing values (2,'1970-01-01 08:25:46.300800004','b1'); +insert into replacing values (3,'1970-01-01 08:25:46.300800005','c1'); +insert into replacing values (2,'1970-01-01 08:25:46.300800005','a1'); + +OPTIMIZE TABLE replacing FINAL; + +select * from replacing; + +drop table replacing; diff --git a/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.reference b/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.reference new file mode 100644 index 00000000000..d9ca990623e --- /dev/null +++ b/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.reference @@ -0,0 +1 @@ +E711B35C04C4F061A0DBD36A00A67B90 diff --git a/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.sql b/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.sql new file mode 100644 index 00000000000..f6cf90c372c --- /dev/null +++ b/tests/queries/0_stateless/01869_reinterpret_as_fixed_string_uuid.sql @@ -0,0 +1 @@ +SELECT hex(reinterpretAsFixedString(toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0'))); diff --git a/tests/queries/0_stateless/01870_buffer_flush.reference b/tests/queries/0_stateless/01870_buffer_flush.reference new file mode 100644 index 00000000000..fd3306644d5 --- /dev/null +++ b/tests/queries/0_stateless/01870_buffer_flush.reference @@ -0,0 +1,2 @@ +0 +5 diff --git a/tests/queries/0_stateless/01870_buffer_flush.sql b/tests/queries/0_stateless/01870_buffer_flush.sql new file mode 100644 index 00000000000..55ec79325dc --- /dev/null +++ b/tests/queries/0_stateless/01870_buffer_flush.sql @@ -0,0 +1,26 @@ +-- Check that Buffer will be flushed before shutdown +-- (via DETACH DATABASE) + +drop database if exists db_01870; +create database db_01870; + +-- Right now the order for shutdown is defined and it is: +-- (prefixes are important, to define the order) +-- - a_data_01870 +-- - z_buffer_01870 +-- so on DETACH DATABASE the following error will be printed: +-- +-- Destination table default.a_data_01870 doesn't exist. Block of data is discarded. +create table db_01870.a_data_01870 as system.numbers Engine=TinyLog(); +create table db_01870.z_buffer_01870 as system.numbers Engine=Buffer(db_01870, a_data_01870, 1, + 100, 100, /* time */ + 100, 100, /* rows */ + 100, 1e6 /* bytes */ +); +insert into db_01870.z_buffer_01870 select * from system.numbers limit 5; +select count() from db_01870.a_data_01870; +detach database db_01870; +attach database db_01870; +select count() from db_01870.a_data_01870; + +drop database db_01870; diff --git a/tests/queries/skip_list.json b/tests/queries/skip_list.json index f858c339dee..cba09040311 100644 --- a/tests/queries/skip_list.json +++ b/tests/queries/skip_list.json @@ -721,6 +721,7 @@ "01804_dictionary_decimal256_type", "01850_dist_INSERT_preserve_error", // uses cluster with different static databases shard_0/shard_1 "01821_table_comment", - "01710_projection_fetch" + "01710_projection_fetch", + "01870_buffer_flush" // creates database ] } diff --git a/tests/testflows/ldap/role_mapping/tests/user_dn_detection.py b/tests/testflows/ldap/role_mapping/tests/user_dn_detection.py index b1a74d6e6b5..147da8a5dcc 100644 --- a/tests/testflows/ldap/role_mapping/tests/user_dn_detection.py +++ b/tests/testflows/ldap/role_mapping/tests/user_dn_detection.py @@ -33,7 +33,7 @@ def check_config(self, entries, valid=True, ldap_server="openldap1", user="user1 @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_BaseDN("1.0") ) def config_invalid_base_dn(self): """Check when invalid `base_dn` is specified in the user_dn_detection section. @@ -62,7 +62,7 @@ def config_invalid_base_dn(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_BaseDN("1.0") ) def config_empty_base_dn(self): """Check when empty `base_dn` is specified in the user_dn_detection section. @@ -90,7 +90,7 @@ def config_empty_base_dn(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_BaseDN("1.0") ) def config_missing_base_dn(self): """Check when missing `base_dn` is specified in the user_dn_detection section. @@ -145,7 +145,7 @@ def config_invalid_search_filter(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_SearchFilter("1.0") ) def config_missing_search_filter(self): """Check when missing `search_filter` is specified in the user_dn_detection section. @@ -172,7 +172,7 @@ def config_missing_search_filter(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_SearchFilter("1.0") ) def config_empty_search_filter(self): """Check when empty `search_filter` is specified in the user_dn_detection section. @@ -200,7 +200,8 @@ def config_empty_search_filter(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_BaseDN("1.0"), + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_SearchFilter("1.0") ) def config_valid(self): """Check valid config with valid user_dn_detection section. @@ -228,7 +229,8 @@ def config_valid(self): @TestScenario @Tags("config") @Requirements( - # FIXME + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_BaseDN("1.0"), + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_SearchFilter("1.0") ) def config_valid_tls_connection(self): """Check valid config with valid user_dn_detection section when @@ -256,6 +258,9 @@ def config_valid_tls_connection(self): check_config(entries=entries, valid=True, ldap_server="openldap2", user="user2", password="user2") @TestOutline(Scenario) +@Requirements( + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection_Scope("1.0") +) @Examples("scope base_dn", [ ("base", "cn=user1,ou=users,dc=company,dc=com"), ("one_level","ou=users,dc=company,dc=com"), @@ -399,9 +404,6 @@ def setup_different_bind_dn_and_user_dn(self, uid, map_by, user_dn_detection): role_mappings=role_mappings, restart=True) @TestScenario -@Requirements( - # FIXME: -) def map_roles_by_user_dn_when_base_dn_and_user_dn_are_different(self): """Check the case when we map roles using user_dn then the first user has uid of second user and second user @@ -429,9 +431,6 @@ def map_roles_by_user_dn_when_base_dn_and_user_dn_are_different(self): assert f"GRANT role0_{uid} TO second_user" in r.output, error() @TestScenario -@Requirements( - # FIXME: -) def map_roles_by_bind_dn_when_base_dn_and_user_dn_are_different(self): """Check the case when we map roles by bind_dn when bind_dn and user_dn are different. @@ -457,7 +456,7 @@ def map_roles_by_bind_dn_when_base_dn_and_user_dn_are_different(self): @TestFeature @Name("user dn detection") @Requirements( - #RQ_SRS_014_LDAP_UserDNDetection("1.0") + RQ_SRS_014_LDAP_RoleMapping_Configuration_Server_UserDNDetection("1.0") ) def feature(self): """Check LDAP user DN detection. diff --git a/tests/testflows/regression.py b/tests/testflows/regression.py index 21e65ef73c5..2547463a91d 100755 --- a/tests/testflows/regression.py +++ b/tests/testflows/regression.py @@ -29,7 +29,7 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None): run_scenario(pool, tasks, Feature(test=load("map_type.regression", "regression")), args) run_scenario(pool, tasks, Feature(test=load("window_functions.regression", "regression")), args) run_scenario(pool, tasks, Feature(test=load("datetime64_extended_range.regression", "regression")), args) - # run_scenario(pool, tasks, Feature(test=load("kerberos.regression", "regression")), args) + #run_scenario(pool, tasks, Feature(test=load("kerberos.regression", "regression")), args) finally: join(tasks) diff --git a/website/css/blog.css b/website/css/blog.css index 064dbf3d975..089856b8e00 100644 --- a/website/css/blog.css +++ b/website/css/blog.css @@ -11,14 +11,6 @@ body.blog .dropdown-item:focus { background: #eee; } -.comment-even { - background: #fff; -} - -.comment-odd, .comments-bg { - background: #f8f9fa; -} - @media (prefers-color-scheme: dark) { body.blog .dropdown-item { color: #fff !important; @@ -33,12 +25,4 @@ body.blog .dropdown-item:focus { .blog .social-icon { background: #444451; } - - .comment-even { - background: #111; - } - - .comment-odd, .comments-bg { - background: #333; - } } diff --git a/website/js/embedd.min.js b/website/js/embedd.min.js deleted file mode 100644 index bda09649faa..00000000000 --- a/website/js/embedd.min.js +++ /dev/null @@ -1,11 +0,0 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=11)}([function(e,t,n){"use strict";function r(e){return"[object Array]"===E.call(e)}function o(e){return"[object ArrayBuffer]"===E.call(e)}function i(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function a(e){return"number"==typeof e}function s(e){return void 0===e}function f(e){return null!==e&&"object"==typeof e}function l(e){return"[object Date]"===E.call(e)}function p(e){return"[object File]"===E.call(e)}function d(e){return"[object Blob]"===E.call(e)}function h(e){return"[object Function]"===E.call(e)}function m(e){return f(e)&&h(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function y(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&void 0!==e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n1)for(var n=1;n=200&&e<300}};c.headers={common:{Accept:"application/json, text/plain, */*"}},o.forEach(["delete","get","head"],function(e){c.headers[e]={}}),o.forEach(["post","put","patch"],function(e){c.headers[e]=o.merge(u)}),e.exports=c}).call(t,n(2))},function(e,t,n){(function(e,n,r,o){!function(e,n){n(t)}(0,function(t){"use strict";function i(e,t){t|=0;for(var n=Math.max(e.length-t,0),r=Array(n),o=0;o-1&&e%1==0&&e<=Ot}function w(e){return null!=e&&b(e.length)&&!g(e)}function x(){}function j(e){return function(){if(null!==e){var t=e;e=null,t.apply(this,arguments)}}}function S(e,t){for(var n=-1,r=Array(e);++n-1&&e%1==0&&eo?0:o+t),n=n>o?o:n,n<0&&(n+=o),o=t>n?0:n-t>>>0,t>>>=0;for(var i=Array(o);++r=r?e:ee(e,t,n)}function ne(e,t){for(var n=e.length;n--&&G(t,e[n],0)>-1;);return n}function re(e,t){for(var n=-1,r=e.length;++n-1;);return n}function oe(e){return e.split("")}function ie(e){return xn.test(e)}function ue(e){return e.match(_n)||[]}function ce(e){return ie(e)?ue(e):oe(e)}function ae(e){return null==e?"":Z(e)}function se(e,t,n){if((e=ae(e))&&(n||void 0===t))return e.replace(Cn,"");if(!e||!(t=Z(t)))return e;var r=ce(e),o=ce(t);return te(r,re(r,o),ne(r,o)+1).join("")}function fe(e){return e=e.toString().replace(In,""),e=e.match(Rn)[2].replace(" ",""),e=e?e.split(Fn):[],e=e.map(function(e){return se(e.replace(Un,""))})}function le(e,t){var n={};X(e,function(e,t){function r(t,n){var r=K(o,function(e){return t[e]});r.push(n),d(e).apply(null,r)}var o,i=p(e),u=!i&&1===e.length||i&&0===e.length;if(Bt(e))o=e.slice(0,-1),e=e[e.length-1],n[t]=o.concat(o.length>0?r:e);else if(u)n[t]=e;else{if(o=fe(e),0===e.length&&!i&&0===o.length)throw new Error("autoInject task functions require explicit parameters.");i||o.pop(),n[t]=o.concat(r)}}),vn(n,t)}function pe(){this.head=this.tail=null,this.length=0}function de(e,t){e.length=1,e.head=e.tail=t}function he(e,t,n){function r(e,t,n){if(null!=n&&"function"!=typeof n)throw new Error("task callback must be a function");if(f.started=!0,Bt(e)||(e=[e]),0===e.length&&f.idle())return ft(function(){f.drain()});for(var r=0,o=e.length;r0&&c.splice(i,1),o.callback.apply(o,arguments),null!=t&&f.error(t,o.data)}u<=f.concurrency-f.buffer&&f.unsaturated(),f.idle()&&f.drain(),f.process()}}if(null==t)t=1;else if(0===t)throw new Error("Concurrency must not be zero");var i=d(e),u=0,c=[],a=!1,s=!1,f={_tasks:new pe,concurrency:t,payload:n,saturated:x,unsaturated:x,buffer:t/4,empty:x,drain:x,error:x,started:!1,paused:!1,push:function(e,t){r(e,!1,t)},kill:function(){f.drain=x,f._tasks.empty()},unshift:function(e,t){r(e,!0,t)},remove:function(e){f._tasks.remove(e)},process:function(){if(!s){for(s=!0;!f.paused&&u2&&(o=i(arguments,1)),r[t]=o,n(e)})},function(e){n(e,r)})}function Pe(e,t){Ne(sn,e,t)}function De(e,t,n){Ne(B(t),e,n)}function He(e,t){if(t=j(t||x),!Bt(e))return t(new TypeError("First argument to race must be an array of functions"));if(!e.length)return t();for(var n=0,r=e.length;nr?1:0}var o=d(t);fn(e,function(e,t){o(e,function(n,r){if(n)return t(n);t(null,{value:e,criteria:r})})},function(e,t){if(e)return n(e);n(null,K(t.sort(r),Ce("value")))})}function Ke(e,t,n){var r=d(e);return ct(function(o,i){function u(){var t=e.name||"anonymous",r=new Error('Callback function "'+t+'" timed out.');r.code="ETIMEDOUT",n&&(r.info=n),a=!0,i(r)}var c,a=!1;o.push(function(){a||(i.apply(null,arguments),clearTimeout(c))}),c=setTimeout(u,t),r.apply(null,o)})}function Ye(e,t,n,r){for(var o=-1,i=gr(yr((t-e)/(n||1)),0),u=Array(i);i--;)u[r?i:++o]=e,e+=n;return u}function Ze(e,t,n,r){var o=d(n);pn(Ye(0,e,1),t,o,r)}function et(e,t,n,r){arguments.length<=3&&(r=n,n=t,t=Bt(e)?[]:{}),r=j(r||x);var o=d(n);sn(e,function(e,n,r){o(t,e,n,r)},function(e){r(e,t)})}function tt(e,t){var n,r=null;t=t||x,Wn(e,function(e,t){d(e)(function(e,o){n=arguments.length>2?i(arguments,1):o,r=e,t(!e)})},function(){t(r,n)})}function nt(e){return function(){return(e.unmemoized||e).apply(null,arguments)}}function rt(e,t,n){n=M(n||x);var r=d(t);if(!e())return n(null);var o=function(t){if(t)return n(t);if(e())return r(o);var u=i(arguments,1);n.apply(null,[null].concat(u))};r(o)}function ot(e,t,n){rt(function(){return!e.apply(this,arguments)},t,n)}var it,ut=function(e){var t=i(arguments,1);return function(){var n=i(arguments);return e.apply(null,t.concat(n))}},ct=function(e){return function(){var t=i(arguments),n=t.pop();e.call(this,t,n)}},at="function"==typeof e&&e,st="object"==typeof n&&"function"==typeof n.nextTick;it=at?e:st?n.nextTick:c;var ft=a(it),lt="function"==typeof Symbol,pt="object"==typeof r&&r&&r.Object===Object&&r,dt="object"==typeof self&&self&&self.Object===Object&&self,ht=pt||dt||Function("return this")(),mt=ht.Symbol,vt=Object.prototype,yt=vt.hasOwnProperty,gt=vt.toString,bt=mt?mt.toStringTag:void 0,wt=Object.prototype,xt=wt.toString,jt="[object Null]",St="[object Undefined]",Et=mt?mt.toStringTag:void 0,kt="[object AsyncFunction]",Tt="[object Function]",Lt="[object GeneratorFunction]",At="[object Proxy]",Ot=9007199254740991,_t={},Ct="function"==typeof Symbol&&Symbol.iterator,Rt=function(e){return Ct&&e[Ct]&&e[Ct]()},Ft="[object Arguments]",Ut=Object.prototype,It=Ut.hasOwnProperty,qt=Ut.propertyIsEnumerable,Mt=k(function(){return arguments}())?k:function(e){return E(e)&&It.call(e,"callee")&&!qt.call(e,"callee")},Bt=Array.isArray,Nt="object"==typeof t&&t&&!t.nodeType&&t,Pt=Nt&&"object"==typeof o&&o&&!o.nodeType&&o,Dt=Pt&&Pt.exports===Nt,Ht=Dt?ht.Buffer:void 0,Vt=Ht?Ht.isBuffer:void 0,zt=Vt||T,$t=9007199254740991,Xt=/^(?:0|[1-9]\d*)$/,Qt={};Qt["[object Float32Array]"]=Qt["[object Float64Array]"]=Qt["[object Int8Array]"]=Qt["[object Int16Array]"]=Qt["[object Int32Array]"]=Qt["[object Uint8Array]"]=Qt["[object Uint8ClampedArray]"]=Qt["[object Uint16Array]"]=Qt["[object Uint32Array]"]=!0,Qt["[object Arguments]"]=Qt["[object Array]"]=Qt["[object ArrayBuffer]"]=Qt["[object Boolean]"]=Qt["[object DataView]"]=Qt["[object Date]"]=Qt["[object Error]"]=Qt["[object Function]"]=Qt["[object Map]"]=Qt["[object Number]"]=Qt["[object Object]"]=Qt["[object RegExp]"]=Qt["[object Set]"]=Qt["[object String]"]=Qt["[object WeakMap]"]=!1;var Wt="object"==typeof t&&t&&!t.nodeType&&t,Jt=Wt&&"object"==typeof o&&o&&!o.nodeType&&o,Gt=Jt&&Jt.exports===Wt,Kt=Gt&&pt.process,Yt=function(){try{var e=Jt&&Jt.require&&Jt.require("util").types;return e||Kt&&Kt.binding&&Kt.binding("util")}catch(e){}}(),Zt=Yt&&Yt.isTypedArray,en=Zt?function(e){return function(t){return e(t)}}(Zt):A,tn=Object.prototype,nn=tn.hasOwnProperty,rn=Object.prototype,on=function(e,t){return function(n){return e(t(n))}}(Object.keys,Object),un=Object.prototype,cn=un.hasOwnProperty,an=P(N,1/0),sn=function(e,t,n){(w(e)?D:an)(e,d(t),n)},fn=H(V),ln=h(fn),pn=z(V),dn=P(pn,1),hn=h(dn),mn=function(e){return function(t,n,r){for(var o=-1,i=Object(t),u=r(t),c=u.length;c--;){var a=u[e?c:++o];if(!1===n(i[a],a,i))break}return t}}(),vn=function(e,t,n){function r(e,t){y.push(function(){a(e,t)})}function o(){if(0===y.length&&0===h)return n(null,p);for(;y.length&&h2&&(r=i(arguments,1)),t){var o={};X(p,function(e,t){o[t]=e}),o[e]=r,m=!0,v=Object.create(null),n(t,o)}else p[e]=r,c(e)});h++;var o=d(t[t.length-1]);t.length>1?o(p,r):o(r)}}function s(t){var n=[];return X(e,function(e,r){Bt(e)&&G(e,t,0)>=0&&n.push(r)}),n}"function"==typeof t&&(n=t,t=null),n=j(n||x);var f=R(e),l=f.length;if(!l)return n(null);t||(t=l);var p={},h=0,m=!1,v=Object.create(null),y=[],g=[],b={};X(e,function(t,n){if(!Bt(t))return r(n,[t]),void g.push(n);var o=t.slice(0,t.length-1),i=o.length;if(0===i)return r(n,t),void g.push(n);b[n]=i,$(o,function(c){if(!e[c])throw new Error("async.auto task `"+n+"` has a non-existent dependency `"+c+"` in "+o.join(", "));u(c,function(){0===--i&&r(n,t)})})}),function(){for(var e,t=0;g.length;)e=g.pop(),t++,$(s(e),function(e){0==--b[e]&&g.push(e)});if(t!==l)throw new Error("async.auto cannot execute tasks due to a recursive dependency")}(),o()},yn="[object Symbol]",gn=1/0,bn=mt?mt.prototype:void 0,wn=bn?bn.toString:void 0,xn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),jn="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",Sn="\\ud83c[\\udffb-\\udfff]",En="(?:\\ud83c[\\udde6-\\uddff]){2}",kn="[\\ud800-\\udbff][\\udc00-\\udfff]",Tn="(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?",Ln="(?:\\u200d(?:"+["[^\\ud800-\\udfff]",En,kn].join("|")+")[\\ufe0e\\ufe0f]?"+Tn+")*",An="[\\ufe0e\\ufe0f]?"+Tn+Ln,On="(?:"+["[^\\ud800-\\udfff]"+jn+"?",jn,En,kn,"[\\ud800-\\udfff]"].join("|")+")",_n=RegExp(Sn+"(?="+Sn+")|"+On+An,"g"),Cn=/^\s+|\s+$/g,Rn=/^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m,Fn=/,/,Un=/(=.+)?(\s*)$/,In=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;pe.prototype.removeLink=function(e){return e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev,e.prev=e.next=null,this.length-=1,e},pe.prototype.empty=function(){for(;this.head;)this.shift();return this},pe.prototype.insertAfter=function(e,t){t.prev=e,t.next=e.next,e.next?e.next.prev=t:this.tail=t,e.next=t,this.length+=1},pe.prototype.insertBefore=function(e,t){t.prev=e.prev,t.next=e,e.prev?e.prev.next=t:this.head=t,e.prev=t,this.length+=1},pe.prototype.unshift=function(e){this.head?this.insertBefore(this.head,e):de(this,e)},pe.prototype.push=function(e){this.tail?this.insertAfter(this.tail,e):de(this,e)},pe.prototype.shift=function(){return this.head&&this.removeLink(this.head)},pe.prototype.pop=function(){return this.tail&&this.removeLink(this.tail)},pe.prototype.toArray=function(){for(var e=Array(this.length),t=this.head,n=0;n=o.priority;)o=o.next;for(var i=0,u=e.length;it)return!1;var n=t-e,r=Math.floor(n/60),o=Math.floor(r/60),i=Math.floor(o/24);return 1===i?"1 day ago":i>0?i+" days ago":1===o?"1 hour ago":o>0?o+" hours ago":1===r?"1 minute ago":r>0?r+" minutes ago":"a few seconds ago"}function u(e){function t(e,t){if(!e)throw new Error("No URL has been specified");if(s[e])return void t(null,s[e]);f.default.get(e).then(function(n){s[e]=n.data,t(null,n.data)}).catch(t)}function n(t){var n=t.sub,r=t.id;return n&&r?e.base+"/r/"+n+"/comments/"+r+".json":!(n||!r)&&e.base+r}function r(e,r){var o=e.hits.filter(function(e){return!!e.num_comments});a.default.map(o.slice(0,10),function(e,r){var o=e.id,i=e.subreddit;if("undefined"===o)throw new Error("No ID specified");t(n({sub:i,id:o}),r)},r)}function o(t){var n=t.comment,r=t.op,i=t.depth,u=i||0,c=e.commentFmt(n);if(c.depth=u,c.subreddit=r.subreddit,r.permalink&&(c.permalink=e.base+r.permalink,c.thread=e.base+r.permalink+n.id),n.children&&n.children.length>0){var a=u+1;c.hasReplies=!0,c.replies=n.children.reduce(function(e,t){return t.author&&e.push(o({comment:t,op:r,depth:a})),e},[]),c.loadMore=c.replies.length>4}return c}function i(t,n){n(null,t.map(function(t){var n=e.threadFmt(t),r=n.children.reduce(function(e,t){return t.author&&e.push(o({comment:t,op:n})),e},[]);return{op:n,comments:r}}))}function u(t,n){var r=function e(n,r,o){if(o>t.length-1)return{score:n,threads:t.length,comments:r,multiple:function(){return this.threads>1}};var i=t[o];return e(n+=i.op.points,r.concat(i.comments),o+1)}(0,[],0),o=r.comments.sort(function(e,t){return t.score-e.score}),i=e.limit||o.length;r.comments=o.slice(0,i),r.next=o.slice(i),r.hasMore=!!r.next.length,n(null,r)}if(!e)throw new Error("No spec object has been specified");if(!e.submitUrl)throw new Error("submitUrl isnt defined");if(!e.dataFmt)throw new Error("dataFmt method isnt defined");if(!e.commentFmt)throw new Error("commentFmt method isnt defined");if(!e.threadFmt)throw new Error("threadFmt method isnt defined");0===e.limit&&(e.limit=null);var c={},s={};return c.submitUrl=e.submitUrl,c.hasComments=function(n){a.default.waterfall([a.default.apply(t,e.query),e.dataFmt],function(e,t){if(e)throw new Error(e);var r=t.hits.filter(function(e){return!!e.num_comments});n(null,!!r.length)})},c.getComments=function(n){a.default.waterfall([a.default.apply(t,e.query),e.dataFmt,r,i,u],n)},c}Object.defineProperty(t,"__esModule",{value:!0}),t.decode=o,t.parseDate=i,t.embeddConstructor=u;var c=n(4),a=r(c),s=n(17),f=r(s)},function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r comment}}{{/comments}}",r,{comment:d});if(u.insertAdjacentHTML("beforeend",a),!r.hasMore){var s=document.querySelector(".embedd-container .more-btn");s?s.style.display="none":window.removeEventListener("scroll",n,!1)}t()}function u(e){e.target.parentNode.parentNode.parentNode.classList.toggle("closed")}function a(e){function t(e,n){e&&3!==n?e instanceof Text||"block"===f(e)?t(e.nextSibling,n):(e.style.display="block",t(e.nextSibling,n+1)):r.querySelector(".viewMore").style.display="none"}var n=e.currentTarget,r=n.parentElement;t(r.querySelector(".children").firstChild,0)}function f(e){return e.currentStyle?e.currentStyle.display:window.getComputedStyle(e,null).getPropertyValue("display")}var h={},m=document.currentScript,v=(m.parentNode,document.getElementById("embedd-comments"));if(v)return h.config={element:v,url:location.protocol+"//"+location.host+location.pathname,dark:!1,service:"hn",serviceName:"HackerNews",both:!0,loadMore:!0,infiniteScroll:!1,limit:5,debug:!1},"string"==typeof h.config.element&&(h.config.element=document.querySelector(h.config.element)),h.config.element.className="embedd-container",h.config.loadMore&&h.config.infiniteScroll&&(h.config.loadMore=!1),h.clients={},h.config.both&&(h.clients.reddit=(0,l.default)(h.config),h.clients.hn=(0,s.default)(h.config)),h.config.both||"reddit"!==h.config.service||(h.clients.reddit=(0,l.default)(h.config)),h.config.both||"hn"!==h.config.service||(h.clients.hn=(0,s.default)(h.config)),h.init=function(){var t=h.clients,n=t.reddit,o=t.hn,u=h.clients[h.config.service],c={};o&&(c.hasHn=o.hasComments),n&&(c.hasReddit=n.hasComments),c.data=u.getComments,i.default.series(c,function(t,n){if(t)throw new Error(t);n.submitUrl=u.submitUrl,h=e(h,n),r(h)})},h})().init()},function(e,t,n){(function(e){function r(e,t){this._id=e,this._clearFn=t}var o=Function.prototype.apply;t.setTimeout=function(){return new r(o.call(setTimeout,window,arguments),clearTimeout)},t.setInterval=function(){return new r(o.call(setInterval,window,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},r.prototype.unref=r.prototype.ref=function(){},r.prototype.close=function(){this._clearFn.call(window,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(13),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n(1))},function(e,t,n){(function(e,t){!function(e,n){"use strict";function r(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n"'`=\/]/g,function(e){return g[e]})}function a(t,n){function o(e){if("string"==typeof e&&(e=e.split(w,2)),!m(e)||2!==e.length)throw new Error("Invalid tags: "+e);i=new RegExp(r(e[0])+"\\s*"),c=new RegExp("\\s*"+r(e[1])),a=new RegExp("\\s*"+r("}"+e[1]))}if(!t)return[];var i,c,a,p=[],d=[],h=[],v=!1,y=!1;o(n||e.tags);for(var g,E,k,T,L,A,O=new l(t);!O.eos();){if(g=O.pos,k=O.scanUntil(i))for(var _=0,C=k.length;_0?i[i.length-1][4]:r;break;default:o.push(t)}return r}function l(e){this.string=e,this.tail=e,this.pos=0}function p(e,t){this.view=e,this.cache={".":this.view},this.parent=t}function d(){this.cache={}}var h=Object.prototype.toString,m=Array.isArray||function(e){return"[object Array]"===h.call(e)},v=RegExp.prototype.test,y=/\S/,g={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},b=/\s*/,w=/\s+/,x=/\s*=/,j=/\s*\}/,S=/#|\^|\/|>|\{|&|=|!/;l.prototype.eos=function(){return""===this.tail},l.prototype.scan=function(e){var t=this.tail.match(e);if(!t||0!==t.index)return"";var n=t[0];return this.tail=this.tail.substring(n.length),this.pos+=n.length,n},l.prototype.scanUntil=function(e){var t,n=this.tail.search(e);switch(n){case-1:t=this.tail,this.tail="";break;case 0:t="";break;default:t=this.tail.substring(0,n),this.tail=this.tail.substring(n)}return this.pos+=t.length,t},p.prototype.push=function(e){return new p(e,this)},p.prototype.lookup=function(e){var n,r=this.cache;if(r.hasOwnProperty(e))n=r[e];else{for(var i,u,c=this,a=!1;c;){if(e.indexOf(".")>0)for(n=c.view,i=e.split("."),u=0;null!=n&&u"===i?u=this.renderPartial(o,t,n,r):"&"===i?u=this.unescapedValue(o,t):"name"===i?u=this.escapedValue(o,t):"text"===i&&(u=this.rawValue(o)),void 0!==u&&(c+=u);return c},d.prototype.renderSection=function(e,n,r,o){function i(e){return u.render(e,n,r)}var u=this,c="",a=n.lookup(e[1]);if(a){if(m(a))for(var s=0,f=a.length;s - * @license MIT - */ -e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new u,response:new u}}var o=n(3),i=n(0),u=n(28),c=n(29);r.prototype.request=function(e){"string"==typeof e&&(e=i.merge({url:arguments[0]},arguments[1])),e=i.merge(o,{method:"get"},this.defaults,e),e.method=e.method.toLowerCase();var t=[c,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},i.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(i.merge(n||{},{method:e,url:t}))}}),i.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(i.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(8);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(0);e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(o.isURLSearchParams(t))i=t.toString();else{var u=[];o.forEach(t,function(e,t){null!==e&&void 0!==e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),u.push(r(t)+"="+r(e))}))}),i=u.join("&")}return i&&(e+=(-1===e.indexOf("?")?"?":"&")+i),e}},function(e,t,n){"use strict";var r=n(0),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,u={};return e?(r.forEach(e.split("\n"),function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(u[t]&&o.indexOf(t)>=0)return;u[t]="set-cookie"===t?(u[t]?u[t]:[]).concat([n]):u[t]?u[t]+", "+n:n}}),u):u}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,i,u){var c=[];c.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&c.push("expires="+new Date(n).toGMTString()),r.isString(o)&&c.push("path="+o),r.isString(i)&&c.push("domain="+i),!0===u&&c.push("secure"),document.cookie=c.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(0);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(0),i=n(30),u=n(9),c=n(3),a=n(31),s=n(32);e.exports=function(e){return r(e),e.baseURL&&!a(e.url)&&(e.url=s(e.baseURL,e.url)),e.headers=e.headers||{},e.data=i(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]}),(e.adapter||c.adapter)(e).then(function(t){return r(e),t.data=i(t.data,t.headers,e.transformResponse),t},function(t){return u(t)||(r(e),t&&t.response&&(t.response.data=i(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t,n){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t,n){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(10);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e;return{token:new r(function(t){e=t}),cancel:e}},e.exports=r},function(e,t,n){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t,n){"use strict";function r(e){if(!e)throw new Error("The Reddit constructor requires a spec object");var t=e.url,n=e.limit,r={};return r.base="https://www.reddit.com",r.searchQs="/search.json?q=url:",r.query=r.base+r.searchQs+t,r.submitUrl="https://www.reddit.com/submit",r.limit=n,r.dataFmt=function(e,t){e.hits=e.data.children.map(function(e){return e=e.data}),t(null,e)},r.commentFmt=function(e){return{author:e.author,author_link:"https://www.reddit.com/user/"+e.author,body_html:(0,o.decode)(e.body_html),created:(0,o.parseDate)(e.created_utc),id:e.id,score:e.score,replies:null,hasReplies:!1,isEven:function(){return this.depth%2==0},isOdd:function(){return this.depth%2==1},lowScore:function(){return this.score<0}}},r.threadFmt=function(e){var t=function e(t){return t.points=t.score,t.replies&&(t.children=t.replies.data.children.map(function(t){return t=t.data,t.replies&&(t.children=e(t)),t})),t},n=e[0].data.children[0].data;return n.points=n.score,n.children=e[1].data.children.map(function(e){return e=e.data,t(e)}),n},(0,o.embeddConstructor)(r)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var o=n(5)},function(e,t){e.exports='
\n {{#data}}\n
\n {{#score}}\n

{{score}} upvotes {{#multiple}}over {{threads}} threads{{/multiple}} on {{config.serviceName}}

\n {{/score}}\n {{^score}}\n \n Start discussion on {{config.serviceName}}\n \n {{/score}}\n
\n\n {{#config.both}}\n {{#hasReddit}}\n {{#hasHn}}\n
\n \n\n \n
\n {{/hasHn}}\n {{/hasReddit}}\n {{/config.both}}\n\n
\n {{#comments}}\n {{> comment}}\n {{/comments}}\n
\n\n {{#config.loadMore}}\n
\n \n
\n {{/config.loadMore}}\n\n {{/data}}\n
\n'},function(e,t){e.exports='
\n\n \n\n {{#body_html}}\n\n {{& body_html}}\n {{/body_html}}\n\n \n\n {{#hasReplies}}\n
\n {{#replies}}\n {{> comment}}\n {{/replies}}\n\n {{#loadMore}}\n \n {{/loadMore}}\n
\n\n {{/hasReplies}}\n\n
\n'}]); diff --git a/website/templates/blog/content.html b/website/templates/blog/content.html index cd1af29c752..b14616608a6 100644 --- a/website/templates/blog/content.html +++ b/website/templates/blog/content.html @@ -63,21 +63,5 @@ {% endfor %} {% endif %} -{% if not page.meta.is_index and language == 'en' %} - {## end row ##} - {## end container ##} -
-
-
-
-
-
-
-
-
-
{## new container ##} -
{## new row ##} - -{% endif %} {% include "templates/blog/footer.html" %} diff --git a/website/templates/index/community.html b/website/templates/index/community.html index 86f2259b486..a71e4097a68 100644 --- a/website/templates/index/community.html +++ b/website/templates/index/community.html @@ -66,7 +66,7 @@
-