mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 01:25:21 +00:00
Merge branch 'master' into separate-counter-for-rss-in-memory-tracker
This commit is contained in:
commit
c9353cbae8
@ -104,6 +104,7 @@ if [ -n "$MAKE_DEB" ]; then
|
||||
fi
|
||||
|
||||
mv ./programs/clickhouse* /output
|
||||
[ -x ./programs/self-extracting/clickhouse ] && mv ./programs/self-extracting/clickhouse /output
|
||||
mv ./src/unit_tests_dbms /output ||: # may not exist for some binary builds
|
||||
find . -name '*.so' -print -exec mv '{}' /output \;
|
||||
find . -name '*.so.*' -print -exec mv '{}' /output \;
|
||||
|
@ -69,6 +69,8 @@ function download
|
||||
wget_with_retry "$BINARY_URL_TO_DOWNLOAD"
|
||||
|
||||
chmod +x clickhouse
|
||||
# clickhouse may be compressed - run once to decompress
|
||||
./clickhouse ||:
|
||||
ln -s ./clickhouse ./clickhouse-server
|
||||
ln -s ./clickhouse ./clickhouse-client
|
||||
|
||||
|
@ -1218,13 +1218,25 @@ Result:
|
||||
└────────────────────────────┴────────────────────────────────┘
|
||||
```
|
||||
|
||||
## parseDateTime64BestEffortUS
|
||||
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetime64besteffort), except that this function prefers US date format (`MM/DD/YYYY` etc.) in case of ambiguity.
|
||||
|
||||
## parseDateTime64BestEffortOrNull
|
||||
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetime64besteffort) except that it returns `NULL` when it encounters a date format that cannot be processed.
|
||||
|
||||
## parseDateTime64BestEffortOrZero
|
||||
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetimebesteffort) except that it returns zero date or zero date time when it encounters a date format that cannot be processed.
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetime64besteffort) except that it returns zero date or zero date time when it encounters a date format that cannot be processed.
|
||||
|
||||
## parseDateTime64BestEffortUSOrNull
|
||||
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetime64besteffort), except that this function prefers US date format (`MM/DD/YYYY` etc.) in case of ambiguity and returns `NULL` when it encounters a date format that cannot be processed.
|
||||
|
||||
## parseDateTime64BestEffortUSOrZero
|
||||
|
||||
Same as for [parseDateTime64BestEffort](#parsedatetime64besteffort), except that this function prefers US date format (`MM/DD/YYYY` etc.) in case of ambiguity and returns zero date or zero date time when it encounters a date format that cannot be processed.
|
||||
|
||||
|
||||
## toLowCardinality
|
||||
|
@ -8,6 +8,7 @@ sidebar_label: Сборка на Mac OS X
|
||||
:::info "Вам не нужно собирать ClickHouse самостоятельно"
|
||||
Вы можете установить предварительно собранный ClickHouse, как описано в [Быстром старте](https://clickhouse.com/#quick-start).
|
||||
Следуйте инструкциям по установке для `macOS (Intel)` или `macOS (Apple Silicon)`.
|
||||
:::
|
||||
|
||||
Сборка должна запускаться с x86_64 (Intel) на macOS версии 10.15 (Catalina) и выше в последней версии компилятора Xcode's native AppleClang, Homebrew's vanilla Clang или в GCC-компиляторах.
|
||||
|
||||
@ -90,6 +91,7 @@ $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/
|
||||
|
||||
:::info "Note"
|
||||
Вам понадобится команда `sudo`.
|
||||
:::
|
||||
|
||||
1. Создайте файл `/Library/LaunchDaemons/limit.maxfiles.plist` и поместите в него следующее:
|
||||
|
||||
|
@ -49,6 +49,7 @@ PostgreSQL массивы конвертируются в массивы ClickHo
|
||||
|
||||
:::info "Внимание"
|
||||
Будьте внимательны, в PostgreSQL массивы, созданные как `type_name[]`, являются многомерными и могут содержать в себе разное количество измерений в разных строках одной таблицы. Внутри ClickHouse допустимы только многомерные массивы с одинаковым кол-вом измерений во всех строках таблицы.
|
||||
:::
|
||||
|
||||
Поддерживает несколько реплик, которые должны быть перечислены через `|`. Например:
|
||||
|
||||
|
@ -40,6 +40,7 @@ ORDER BY (CounterID, StartDate, intHash32(UserID));
|
||||
|
||||
:::info "Info"
|
||||
Не рекомендуется делать слишком гранулированное партиционирование – то есть задавать партиции по столбцу, в котором будет слишком большой разброс значений (речь идет о порядке более тысячи партиций). Это приведет к скоплению большого числа файлов и файловых дескрипторов в системе, что может значительно снизить производительность запросов `SELECT`.
|
||||
:::
|
||||
|
||||
Чтобы получить набор кусков и партиций таблицы, можно воспользоваться системной таблицей [system.parts](../../../engines/table-engines/mergetree-family/custom-partitioning-key.md#system_tables-parts). В качестве примера рассмотрим таблицу `visits`, в которой задано партиционирование по месяцам. Выполним `SELECT` для таблицы `system.parts`:
|
||||
|
||||
@ -80,6 +81,7 @@ WHERE table = 'visits'
|
||||
|
||||
:::info "Info"
|
||||
Названия кусков для таблиц старого типа образуются следующим образом: `20190117_20190123_2_2_0` (минимальная дата _ максимальная дата _ номер минимального блока _ номер максимального блока _ уровень).
|
||||
:::
|
||||
|
||||
Как видно из примера выше, таблица содержит несколько отдельных кусков для одной и той же партиции (например, куски `201901_1_3_1` и `201901_1_9_2` принадлежат партиции `201901`). Это означает, что эти куски еще не были объединены – в файловой системе они хранятся отдельно. После того как будет выполнено автоматическое слияние данных (выполняется примерно спустя 10 минут после вставки данных), исходные куски будут объединены в один более крупный кусок и помечены как неактивные.
|
||||
|
||||
|
@ -14,3 +14,4 @@ sidebar_position: 10
|
||||
|
||||
:::info "Забавный факт"
|
||||
Спустя годы после того, как ClickHouse получил свое название, принцип комбинирования двух слов, каждое из которых имеет подходящий смысл, был признан лучшим способом назвать базу данных в [исследовании Andy Pavlo](https://www.cs.cmu.edu/~pavlo/blog/2020/03/on-naming-a-database-management-system.html), Associate Professor of Databases в Carnegie Mellon University. ClickHouse разделил награду "за лучшее название СУБД" с Postgres.
|
||||
:::
|
@ -20,5 +20,6 @@ sidebar_label: Общие вопросы
|
||||
|
||||
:::info "Если вы не нашли то, что искали:"
|
||||
Загляните в другие категории F.A.Q. или поищите в остальных разделах документации, ориентируясь по оглавлению слева.
|
||||
:::
|
||||
|
||||
[Original article](https://clickhouse.com/docs/ru/faq/general/) <!--hide-->
|
||||
|
@ -60,3 +60,4 @@ sidebar_position: 8
|
||||
- Ориентируйтесь на показатели, собранные при работе с реальными данными.
|
||||
- Проверяйте производительность в процессе CI.
|
||||
- Измеряйте и анализируйте всё, что только возможно.
|
||||
:::
|
||||
|
@ -15,5 +15,6 @@ sidebar_label: Интеграция
|
||||
|
||||
:::info "Если вы не нашли то, что искали"
|
||||
Загляните в другие подразделы F.A.Q. или поищите в остальных разделах документации, ориентируйтесь по оглавлению слева.
|
||||
:::
|
||||
|
||||
[Original article](https://clickhouse.com/docs/ru/faq/integration/)
|
||||
|
@ -14,5 +14,6 @@ sidebar_label: Операции
|
||||
|
||||
:::info "Если вы не нашли то, что искали"
|
||||
Загляните в другие подразделы F.A.Q. или поищите в остальных разделах документации, ориентируйтесь по оглавлению слева.
|
||||
:::
|
||||
|
||||
[Original article](https://clickhouse.com/docs/en/faq/operations/)
|
||||
|
@ -293,6 +293,7 @@ $ clickhouse-client --query "SELECT COUNT(*) FROM datasets.trips_mergetree"
|
||||
:::info "Info"
|
||||
Если вы собираетесь выполнять запросы, приведенные ниже, то к имени таблицы
|
||||
нужно добавить имя базы, `datasets.trips_mergetree`.
|
||||
:::
|
||||
|
||||
## Результаты на одном сервере {#rezultaty-na-odnom-servere}
|
||||
|
||||
|
@ -157,6 +157,7 @@ $ clickhouse-client --query "SELECT COUNT(*) FROM datasets.ontime"
|
||||
:::info "Info"
|
||||
Если вы собираетесь выполнять запросы, приведенные ниже, то к имени таблицы
|
||||
нужно добавить имя базы, `datasets.ontime`.
|
||||
:::
|
||||
|
||||
## Запросы: {#zaprosy}
|
||||
|
||||
|
@ -99,6 +99,7 @@ ClickHouse предоставляет возможность аутентифи
|
||||
|
||||
:::info ""
|
||||
Ещё раз отметим, что кроме `users.xml`, необходимо также включить Kerberos в `config.xml`.
|
||||
:::
|
||||
|
||||
### Настройка Kerberos через SQL {#enabling-kerberos-using-sql}
|
||||
|
||||
|
@ -174,6 +174,7 @@ ClickHouse проверяет условия для `min_part_size` и `min_part
|
||||
|
||||
:::info "Примечание"
|
||||
Жесткое ограничение настраивается с помощью системных инструментов.
|
||||
:::
|
||||
|
||||
**Пример**
|
||||
|
||||
@ -706,6 +707,7 @@ ClickHouse поддерживает динамическое изменение
|
||||
|
||||
:::info "Примечание"
|
||||
Параметры этих настроек могут быть изменены во время выполнения запросов и вступят в силу немедленно. Запросы, которые уже запущены, выполнятся без изменений.
|
||||
:::
|
||||
|
||||
Возможные значения:
|
||||
|
||||
@ -726,6 +728,7 @@ ClickHouse поддерживает динамическое изменение
|
||||
|
||||
:::info "Примечание"
|
||||
Параметры этих настроек могут быть изменены во время выполнения запросов и вступят в силу немедленно. Запросы, которые уже запущены, выполнятся без изменений.
|
||||
:::
|
||||
|
||||
Возможные значения:
|
||||
|
||||
@ -746,6 +749,7 @@ ClickHouse поддерживает динамическое изменение
|
||||
|
||||
:::info "Примечание"
|
||||
Параметры этих настроек могут быть изменены во время выполнения запросов и вступят в силу немедленно. Запросы, которые уже запущены, выполнятся без изменений.
|
||||
:::
|
||||
|
||||
Возможные значения:
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
:::info "Замечание"
|
||||
Даже если `parts_to_do = 0`, для реплицированной таблицы возможна ситуация, когда мутация ещё не завершена из-за долго выполняющейся операции `INSERT`, которая добавляет данные, которые нужно будет мутировать.
|
||||
:::
|
||||
|
||||
Если во время мутации какого-либо куска возникли проблемы, заполняются следующие столбцы:
|
||||
|
||||
|
@ -8,6 +8,7 @@ sidebar_position: 141
|
||||
|
||||
:::info "Примечание"
|
||||
Чтобы эта функция работала должным образом, исходные данные должны быть отсортированы. В [материализованном представлении](../../../sql-reference/statements/create/view.md#materialized) вместо нее рекомендуется использовать [deltaSumTimestamp](../../../sql-reference/aggregate-functions/reference/deltasumtimestamp.md#agg_functions-deltasumtimestamp).
|
||||
:::
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
|
@ -20,6 +20,7 @@ intervalLengthSum(start, end)
|
||||
|
||||
:::info "Примечание"
|
||||
Аргументы должны быть одного типа. В противном случае ClickHouse сгенерирует исключение.
|
||||
:::
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
|
@ -26,6 +26,7 @@ sidebar_label: Nullable
|
||||
|
||||
:::info "Info"
|
||||
Почти всегда использование `Nullable` снижает производительность, учитывайте это при проектировании своих баз.
|
||||
:::
|
||||
|
||||
## Поиск NULL {#finding-null}
|
||||
|
||||
|
@ -464,6 +464,7 @@ SOURCE(ODBC(
|
||||
|
||||
:::info "Примечание"
|
||||
Поля `table` и `query` не могут быть использованы вместе. Также обязательно должен быть один из источников данных: `table` или `query`.
|
||||
:::
|
||||
|
||||
ClickHouse получает от ODBC-драйвера информацию о квотировании и квотирует настройки в запросах к драйверу, поэтому имя таблицы нужно указывать в соответствии с регистром имени таблицы в базе данных.
|
||||
|
||||
@ -543,6 +544,7 @@ SOURCE(MYSQL(
|
||||
:::info "Примечание"
|
||||
Поля `table` или `where` не могут быть использованы вместе с полем `query`. Также обязательно должен быть один из источников данных: `table` или `query`.
|
||||
Явный параметр `secure` отсутствует. Автоматически поддержана работа в обоих случаях: когда установка SSL-соединения необходима и когда нет.
|
||||
:::
|
||||
|
||||
MySQL можно подключить на локальном хосте через сокеты, для этого необходимо задать `host` и `socket`.
|
||||
|
||||
@ -633,6 +635,7 @@ SOURCE(CLICKHOUSE(
|
||||
|
||||
:::info "Примечание"
|
||||
Поля `table` или `where` не могут быть использованы вместе с полем `query`. Также обязательно должен быть один из источников данных: `table` или `query`.
|
||||
:::
|
||||
|
||||
### MongoDB {#dicts-external_dicts_dict_sources-mongodb}
|
||||
|
||||
@ -748,6 +751,7 @@ SOURCE(REDIS(
|
||||
|
||||
:::info "Примечание"
|
||||
Поля `column_family` или `where` не могут быть использованы вместе с полем `query`. Также обязательно должен быть один из источников данных: `column_family` или `query`.
|
||||
:::
|
||||
|
||||
### PostgreSQL {#dicts-external_dicts_dict_sources-postgresql}
|
||||
|
||||
@ -804,3 +808,4 @@ SOURCE(POSTGRESQL(
|
||||
|
||||
:::info "Примечание"
|
||||
Поля `table` или `where` не могут быть использованы вместе с полем `query`. Также обязательно должен быть один из источников данных: `table` или `query`.
|
||||
:::
|
||||
|
@ -86,6 +86,7 @@ geohashesInBox(longitude_min, latitude_min, longitude_max, latitude_max, precisi
|
||||
|
||||
:::info "Замечание"
|
||||
Все передаваемые координаты должны быть одного и того же типа: либо `Float32`, либо `Float64`.
|
||||
:::
|
||||
|
||||
**Возвращаемые значения**
|
||||
|
||||
@ -96,6 +97,7 @@ geohashesInBox(longitude_min, latitude_min, longitude_max, latitude_max, precisi
|
||||
|
||||
:::info "Замечание"
|
||||
Если возвращаемый массив содержит свыше 10 000 000 элементов, функция сгенерирует исключение.
|
||||
:::
|
||||
|
||||
**Пример**
|
||||
|
||||
|
@ -1140,13 +1140,25 @@ FORMAT PrettyCompactMonoBlock;
|
||||
└────────────────────────────┴────────────────────────────────┘
|
||||
```
|
||||
|
||||
## parseDateTime64BestEffortOrNull {#parsedatetime32besteffortornull}
|
||||
## parseDateTime64BestEffortUS {#parsedatetime64besteffortus}
|
||||
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но разница состоит в том, что в она предполагает американский формат даты (`MM/DD/YYYY` etc.) в случае неоднозначности.
|
||||
|
||||
## parseDateTime64BestEffortOrNull {#parsedatetime64besteffortornull}
|
||||
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но возвращает `NULL`, если формат даты не может быть обработан.
|
||||
|
||||
## parseDateTime64BestEffortOrZero {#parsedatetime64besteffortorzero}
|
||||
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetimebesteffort), но возвращает нулевую дату и время, если формат даты не может быть обработан.
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но возвращает нулевую дату и время, если формат даты не может быть обработан.
|
||||
|
||||
## parseDateTime64BestEffortUSOrNull {#parsedatetime64besteffortusornull}
|
||||
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но разница состоит в том, что в она предполагает американский формат даты (`MM/DD/YYYY` etc.) в случае неоднозначности и возвращает `NULL`, если формат даты не может быть обработан.
|
||||
|
||||
## parseDateTime64BestEffortUSOrZero {#parsedatetime64besteffortusorzero}
|
||||
|
||||
Работает аналогично функции [parseDateTime64BestEffort](#parsedatetime64besteffort), но разница состоит в том, что в она предполагает американский формат даты (`MM/DD/YYYY` etc.) в случае неоднозначности и возвращает нулевую дату и время, если формат даты не может быть обработан.
|
||||
|
||||
## toLowCardinality {#tolowcardinality}
|
||||
|
||||
@ -1197,6 +1209,7 @@ SELECT toLowCardinality('1');
|
||||
|
||||
:::info "Примечание"
|
||||
Возвращаемое значение — это временная метка в UTC, а не в часовом поясе `DateTime64`.
|
||||
:::
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
|
@ -25,7 +25,7 @@ ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN
|
||||
- [CONSTRAINT](../../../sql-reference/statements/alter/constraint.md)
|
||||
- [TTL](../../../sql-reference/statements/alter/ttl.md)
|
||||
|
||||
:::note
|
||||
:::note
|
||||
Запрос `ALTER TABLE` поддерживается только для таблиц типа `*MergeTree`, а также `Merge` и `Distributed`. Запрос имеет несколько вариантов.
|
||||
:::
|
||||
Следующие запросы `ALTER` управляют представлениями:
|
||||
@ -77,5 +77,6 @@ ALTER TABLE [db.]table MATERIALIZE INDEX name IN PARTITION partition_name
|
||||
|
||||
:::info "Примечание"
|
||||
Для всех запросов `ALTER` при `replication_alter_partitions_sync = 2` и неактивности некоторых реплик больше времени, заданного настройкой `replication_wait_for_inactive_replica_timeout`, генерируется исключение `UNFINISHED`.
|
||||
:::
|
||||
|
||||
Для запросов `ALTER TABLE ... UPDATE|DELETE` синхронность выполнения определяется настройкой [mutations_sync](../../../operations/settings/settings.md#mutations_sync).
|
||||
|
@ -56,6 +56,7 @@ CREATE USER [IF NOT EXISTS | OR REPLACE] name1 [ON CLUSTER cluster_name1]
|
||||
|
||||
:::info "Внимание"
|
||||
ClickHouse трактует конструкцию `user_name@'address'` как имя пользователя целиком. То есть технически вы можете создать несколько пользователей с одинаковыми `user_name`, но разными частями конструкции после `@`, но лучше так не делать.
|
||||
:::
|
||||
|
||||
## Секция GRANTEES {#grantees}
|
||||
|
||||
|
@ -88,6 +88,7 @@ LIVE-представления работают по тому же принци
|
||||
- `LIVE VIEW` не обновляется, если в исходном запросе используются несколько таблиц.
|
||||
|
||||
В случаях, когда `LIVE VIEW` не обновляется автоматически, чтобы обновлять его принудительно с заданной периодичностью, используйте [WITH REFRESH](#live-view-with-refresh).
|
||||
:::
|
||||
|
||||
### Отслеживание изменений LIVE-представлений {#live-view-monitoring}
|
||||
|
||||
|
@ -30,6 +30,7 @@ ClickHouse не оповещает клиента. Чтобы включить
|
||||
|
||||
:::info "Примечание"
|
||||
Если значение настройки `replication_alter_partitions_sync` равно `2` и некоторые реплики не активны больше времени, заданного настройкой `replication_wait_for_inactive_replica_timeout`, то генерируется исключение `UNFINISHED`.
|
||||
:::
|
||||
|
||||
## Выражение BY {#by-expression}
|
||||
|
||||
|
@ -368,6 +368,7 @@ SHOW ACCESS
|
||||
|
||||
:::info "Note"
|
||||
По запросу `SHOW CLUSTER name` вы получите содержимое таблицы system.clusters для этого кластера.
|
||||
:::
|
||||
|
||||
### Синтаксис {#show-cluster-syntax}
|
||||
|
||||
|
@ -19,3 +19,4 @@ TRUNCATE TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
|
||||
:::info "Примечание"
|
||||
Если значение настройки `replication_alter_partitions_sync` равно `2` и некоторые реплики не активны больше времени, заданного настройкой `replication_wait_for_inactive_replica_timeout`, то генерируется исключение `UNFINISHED`.
|
||||
:::
|
||||
|
@ -104,3 +104,4 @@ WATCH lv EVENTS LIMIT 1;
|
||||
|
||||
:::info "Примечание"
|
||||
При отслеживании [LIVE VIEW](./create/view.md#live-view) через интерфейс HTTP следует использовать формат [JSONEachRowWithProgress](../../interfaces/formats.md#jsoneachrowwithprogress). Постоянные сообщения об изменениях будут добавлены в поток вывода для поддержания активности долговременного HTTP-соединения до тех пор, пока результат запроса изменяется. Проомежуток времени между сообщениями об изменениях управляется настройкой[live_view_heartbeat_interval](./create/view.md#live-view-settings).
|
||||
:::
|
@ -28,6 +28,7 @@ postgresql('host:port', 'database', 'table', 'user', 'password'[, `schema`])
|
||||
|
||||
:::info "Примечание"
|
||||
В запросах `INSERT` для того чтобы отличить табличную функцию `postgresql(...)` от таблицы со списком имен столбцов вы должны указывать ключевые слова `FUNCTION` или `TABLE FUNCTION`. См. примеры ниже.
|
||||
:::
|
||||
|
||||
## Особенности реализации {#implementation-details}
|
||||
|
||||
@ -43,6 +44,7 @@ PostgreSQL массивы конвертируются в массивы ClickHo
|
||||
|
||||
:::info "Примечание"
|
||||
Будьте внимательны, в PostgreSQL массивы, созданные как `type_name[]`, являются многомерными и могут содержать в себе разное количество измерений в разных строках одной таблицы. Внутри ClickHouse допустипы только многомерные массивы с одинаковым кол-вом измерений во всех строках таблицы.
|
||||
:::
|
||||
|
||||
Поддерживает несколько реплик, которые должны быть перечислены через `|`. Например:
|
||||
|
||||
|
@ -26,13 +26,13 @@ std::unique_ptr<HTTPRequestHandler> LibraryBridgeHandlerFactory::createRequestHa
|
||||
if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
{
|
||||
if (uri.getPath() == "/extdict_ping")
|
||||
return std::make_unique<LibraryBridgeExistsHandler>(keep_alive_timeout, getContext());
|
||||
return std::make_unique<ExternalDictionaryLibraryBridgeExistsHandler>(keep_alive_timeout, getContext());
|
||||
}
|
||||
|
||||
if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
{
|
||||
if (uri.getPath() == "/extdict_request")
|
||||
return std::make_unique<LibraryBridgeRequestHandler>(keep_alive_timeout, getContext());
|
||||
return std::make_unique<ExternalDictionaryLibraryBridgeRequestHandler>(keep_alive_timeout, getContext());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
#include <Poco/Net/HTTPServerResponse.h>
|
||||
#include <Poco/Net/HTMLForm.h>
|
||||
@ -78,18 +79,39 @@ static void writeData(Block data, OutputFormatPtr format)
|
||||
executor.execute();
|
||||
}
|
||||
|
||||
LibraryBridgeRequestHandler::LibraryBridgeRequestHandler(size_t keep_alive_timeout_, ContextPtr context_)
|
||||
ExternalDictionaryLibraryBridgeRequestHandler::ExternalDictionaryLibraryBridgeRequestHandler(size_t keep_alive_timeout_, ContextPtr context_)
|
||||
: WithContext(context_)
|
||||
, log(&Poco::Logger::get("LibraryBridgeRequestHandler"))
|
||||
, log(&Poco::Logger::get("ExternalDictionaryLibraryBridgeRequestHandler"))
|
||||
, keep_alive_timeout(keep_alive_timeout_)
|
||||
{
|
||||
}
|
||||
|
||||
void LibraryBridgeRequestHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
|
||||
void ExternalDictionaryLibraryBridgeRequestHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
|
||||
{
|
||||
LOG_TRACE(log, "Request URI: {}", request.getURI());
|
||||
HTMLForm params(getContext()->getSettingsRef(), request);
|
||||
|
||||
size_t version;
|
||||
|
||||
if (!params.has("version"))
|
||||
version = 0; /// assumed version for too old servers which do not send a version
|
||||
else
|
||||
{
|
||||
String version_str = params.get("version");
|
||||
if (!tryParse(version, version_str))
|
||||
{
|
||||
processError(response, "Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != LIBRARY_BRIDGE_PROTOCOL_VERSION)
|
||||
{
|
||||
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
|
||||
processError(response, "Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.has("method"))
|
||||
{
|
||||
processError(response, "No 'method' in request URL");
|
||||
@ -340,14 +362,14 @@ void LibraryBridgeRequestHandler::handleRequest(HTTPServerRequest & request, HTT
|
||||
}
|
||||
}
|
||||
|
||||
LibraryBridgeExistsHandler::LibraryBridgeExistsHandler(size_t keep_alive_timeout_, ContextPtr context_)
|
||||
ExternalDictionaryLibraryBridgeExistsHandler::ExternalDictionaryLibraryBridgeExistsHandler(size_t keep_alive_timeout_, ContextPtr context_)
|
||||
: WithContext(context_)
|
||||
, keep_alive_timeout(keep_alive_timeout_)
|
||||
, log(&Poco::Logger::get("LibraryBridgeExistsHandler"))
|
||||
, log(&Poco::Logger::get("ExternalDictionaryLibraryBridgeExistsHandler"))
|
||||
{
|
||||
}
|
||||
|
||||
void LibraryBridgeExistsHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
|
||||
void ExternalDictionaryLibraryBridgeExistsHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -361,6 +383,7 @@ void LibraryBridgeExistsHandler::handleRequest(HTTPServerRequest & request, HTTP
|
||||
}
|
||||
|
||||
std::string dictionary_id = params.get("dictionary_id");
|
||||
|
||||
auto library_handler = ExternalDictionaryLibraryHandlerFactory::instance().get(dictionary_id);
|
||||
|
||||
String res = library_handler ? "1" : "0";
|
||||
|
@ -9,7 +9,6 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
||||
/// Handler for requests to Library Dictionary Source, returns response in RowBinary format.
|
||||
/// When a library dictionary source is created, it sends 'extDict_libNew' request to library bridge (which is started on first
|
||||
/// request to it, if it was not yet started). On this request a new sharedLibrayHandler is added to a
|
||||
@ -17,10 +16,10 @@ namespace DB
|
||||
/// names of dictionary attributes, sample block to parse block of null values, block of null values. Everything is
|
||||
/// passed in binary format and is urlencoded. When dictionary is cloned, a new handler is created.
|
||||
/// Each handler is unique to dictionary.
|
||||
class LibraryBridgeRequestHandler : public HTTPRequestHandler, WithContext
|
||||
class ExternalDictionaryLibraryBridgeRequestHandler : public HTTPRequestHandler, WithContext
|
||||
{
|
||||
public:
|
||||
LibraryBridgeRequestHandler(size_t keep_alive_timeout_, ContextPtr context_);
|
||||
ExternalDictionaryLibraryBridgeRequestHandler(size_t keep_alive_timeout_, ContextPtr context_);
|
||||
|
||||
void handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) override;
|
||||
|
||||
@ -32,10 +31,10 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class LibraryBridgeExistsHandler : public HTTPRequestHandler, WithContext
|
||||
class ExternalDictionaryLibraryBridgeExistsHandler : public HTTPRequestHandler, WithContext
|
||||
{
|
||||
public:
|
||||
LibraryBridgeExistsHandler(size_t keep_alive_timeout_, ContextPtr context_);
|
||||
ExternalDictionaryLibraryBridgeExistsHandler(size_t keep_alive_timeout_, ContextPtr context_);
|
||||
|
||||
void handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) override;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <DataTypes/DataTypeFactory.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Parsers/ParserQueryWithOutput.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
@ -14,6 +15,7 @@
|
||||
#include <Poco/NumberParser.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <base/scope_guard.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Common/quoteString.h>
|
||||
#include "getIdentifierQuote.h"
|
||||
#include "validateODBCConnectionString.h"
|
||||
@ -80,6 +82,27 @@ void ODBCColumnsInfoHandler::handleRequest(HTTPServerRequest & request, HTTPServ
|
||||
LOG_WARNING(log, fmt::runtime(message));
|
||||
};
|
||||
|
||||
size_t version;
|
||||
|
||||
if (!params.has("version"))
|
||||
version = 0; /// assumed version for too old servers which do not send a version
|
||||
else
|
||||
{
|
||||
String version_str = params.get("version");
|
||||
if (!tryParse(version, version_str))
|
||||
{
|
||||
process_error("Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != XDBC_BRIDGE_PROTOCOL_VERSION)
|
||||
{
|
||||
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
|
||||
process_error("Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.has("table"))
|
||||
{
|
||||
process_error("No 'table' param in request URL");
|
||||
|
@ -5,11 +5,13 @@
|
||||
#include <DataTypes/DataTypeFactory.h>
|
||||
#include <Server/HTTP/HTMLForm.h>
|
||||
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Parsers/ParserQueryWithOutput.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
#include <Poco/Net/HTTPServerResponse.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <base/scope_guard.h>
|
||||
#include "getIdentifierQuote.h"
|
||||
@ -32,6 +34,27 @@ void IdentifierQuoteHandler::handleRequest(HTTPServerRequest & request, HTTPServ
|
||||
LOG_WARNING(log, fmt::runtime(message));
|
||||
};
|
||||
|
||||
size_t version;
|
||||
|
||||
if (!params.has("version"))
|
||||
version = 0; /// assumed version for too old servers which do not send a version
|
||||
else
|
||||
{
|
||||
String version_str = params.get("version");
|
||||
if (!tryParse(version, version_str))
|
||||
{
|
||||
process_error("Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != XDBC_BRIDGE_PROTOCOL_VERSION)
|
||||
{
|
||||
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
|
||||
process_error("Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.has("connection_string"))
|
||||
{
|
||||
process_error("No 'connection_string' in request URL");
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <QueryPipeline/QueryPipeline.h>
|
||||
#include <Processors/Executors/CompletedPipelineExecutor.h>
|
||||
#include <Processors/Formats/IInputFormat.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <Server/HTTP/HTMLForm.h>
|
||||
#include <Common/config.h>
|
||||
@ -55,6 +56,28 @@ void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse
|
||||
HTMLForm params(getContext()->getSettingsRef(), request);
|
||||
LOG_TRACE(log, "Request URI: {}", request.getURI());
|
||||
|
||||
size_t version;
|
||||
|
||||
if (!params.has("version"))
|
||||
version = 0; /// assumed version for too old servers which do not send a version
|
||||
else
|
||||
{
|
||||
String version_str = params.get("version");
|
||||
if (!tryParse(version, version_str))
|
||||
{
|
||||
processError(response, "Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != XDBC_BRIDGE_PROTOCOL_VERSION)
|
||||
{
|
||||
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
|
||||
processError(response, "Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (mode == "read")
|
||||
params.read(request.getStream());
|
||||
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
#include <Server/HTTP/HTMLForm.h>
|
||||
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
#include <Poco/Net/HTTPServerResponse.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include "validateODBCConnectionString.h"
|
||||
#include "ODBCPooledConnectionFactory.h"
|
||||
@ -40,6 +42,28 @@ void SchemaAllowedHandler::handleRequest(HTTPServerRequest & request, HTTPServer
|
||||
LOG_WARNING(log, fmt::runtime(message));
|
||||
};
|
||||
|
||||
size_t version;
|
||||
|
||||
if (!params.has("version"))
|
||||
version = 0; /// assumed version for too old servers which do not send a version
|
||||
else
|
||||
{
|
||||
String version_str = params.get("version");
|
||||
if (!tryParse(version, version_str))
|
||||
{
|
||||
process_error("Unable to parse 'version' string in request URL: '" + version_str + "' Check if the server and library-bridge have the same version.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != XDBC_BRIDGE_PROTOCOL_VERSION)
|
||||
{
|
||||
/// backwards compatibility is considered unnecessary for now, just let the user know that the server and the bridge must be upgraded together
|
||||
process_error("Server and library-bridge have different versions: '" + std::to_string(version) + "' vs. '" + std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION) + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!params.has("connection_string"))
|
||||
{
|
||||
process_error("No 'connection_string' in request URL");
|
||||
|
@ -31,16 +31,10 @@ ExternalDictionaryLibraryBridgeHelper::ExternalDictionaryLibraryBridgeHelper(
|
||||
const Block & sample_block_,
|
||||
const Field & dictionary_id_,
|
||||
const LibraryInitData & library_data_)
|
||||
: IBridgeHelper(context_->getGlobalContext())
|
||||
, log(&Poco::Logger::get("ExternalDictionaryLibraryBridgeHelper"))
|
||||
: LibraryBridgeHelper(context_->getGlobalContext())
|
||||
, sample_block(sample_block_)
|
||||
, config(context_->getConfigRef())
|
||||
, http_timeout(context_->getGlobalContext()->getSettingsRef().http_receive_timeout.value)
|
||||
, library_data(library_data_)
|
||||
, dictionary_id(dictionary_id_)
|
||||
, bridge_host(config.getString("library_bridge.host", DEFAULT_HOST))
|
||||
, bridge_port(config.getUInt("library_bridge.port", DEFAULT_PORT))
|
||||
, http_timeouts(ConnectionTimeouts::getHTTPTimeouts(context_))
|
||||
{
|
||||
}
|
||||
|
||||
@ -65,28 +59,13 @@ Poco::URI ExternalDictionaryLibraryBridgeHelper::getMainURI() const
|
||||
Poco::URI ExternalDictionaryLibraryBridgeHelper::createRequestURI(const String & method) const
|
||||
{
|
||||
auto uri = getMainURI();
|
||||
uri.addQueryParameter("version", std::to_string(LIBRARY_BRIDGE_PROTOCOL_VERSION));
|
||||
uri.addQueryParameter("dictionary_id", toString(dictionary_id));
|
||||
uri.addQueryParameter("method", method);
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
Poco::URI ExternalDictionaryLibraryBridgeHelper::createBaseURI() const
|
||||
{
|
||||
Poco::URI uri;
|
||||
uri.setHost(bridge_host);
|
||||
uri.setPort(bridge_port);
|
||||
uri.setScheme("http");
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
void ExternalDictionaryLibraryBridgeHelper::startBridge(std::unique_ptr<ShellCommand> cmd) const
|
||||
{
|
||||
getContext()->addBridgeCommand(std::move(cmd));
|
||||
}
|
||||
|
||||
|
||||
bool ExternalDictionaryLibraryBridgeHelper::bridgeHandShake()
|
||||
{
|
||||
String result;
|
||||
@ -225,6 +204,14 @@ QueryPipeline ExternalDictionaryLibraryBridgeHelper::loadAll()
|
||||
}
|
||||
|
||||
|
||||
static String getDictIdsString(const std::vector<UInt64> & ids)
|
||||
{
|
||||
WriteBufferFromOwnString out;
|
||||
writeVectorBinary(ids, out);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
QueryPipeline ExternalDictionaryLibraryBridgeHelper::loadIds(const std::vector<uint64_t> & ids)
|
||||
{
|
||||
startBridgeSync();
|
||||
@ -283,13 +270,4 @@ QueryPipeline ExternalDictionaryLibraryBridgeHelper::loadBase(const Poco::URI &
|
||||
return QueryPipeline(std::move(source));
|
||||
}
|
||||
|
||||
|
||||
String ExternalDictionaryLibraryBridgeHelper::getDictIdsString(const std::vector<UInt64> & ids)
|
||||
{
|
||||
WriteBufferFromOwnString out;
|
||||
writeVectorBinary(ids, out);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
#include <Interpreters/Context.h>
|
||||
#include <IO/ReadWriteBufferFromHTTP.h>
|
||||
#include <Poco/Logger.h>
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <BridgeHelper/IBridgeHelper.h>
|
||||
#include <BridgeHelper/LibraryBridgeHelper.h>
|
||||
#include <QueryPipeline/QueryPipeline.h>
|
||||
|
||||
|
||||
@ -14,7 +13,8 @@ namespace DB
|
||||
|
||||
class Pipe;
|
||||
|
||||
class ExternalDictionaryLibraryBridgeHelper : public IBridgeHelper
|
||||
// Class to access the external dictionary part of the clickhouse-library-bridge.
|
||||
class ExternalDictionaryLibraryBridgeHelper : public LibraryBridgeHelper
|
||||
{
|
||||
|
||||
public:
|
||||
@ -25,7 +25,6 @@ public:
|
||||
String dict_attributes;
|
||||
};
|
||||
|
||||
static constexpr inline size_t DEFAULT_PORT = 9012;
|
||||
static constexpr inline auto PING_HANDLER = "/extdict_ping";
|
||||
static constexpr inline auto MAIN_HANDLER = "/extdict_request";
|
||||
|
||||
@ -56,26 +55,6 @@ protected:
|
||||
|
||||
bool bridgeHandShake() override;
|
||||
|
||||
void startBridge(std::unique_ptr<ShellCommand> cmd) const override;
|
||||
|
||||
String serviceAlias() const override { return "clickhouse-library-bridge"; }
|
||||
|
||||
String serviceFileName() const override { return serviceAlias(); }
|
||||
|
||||
size_t getDefaultPort() const override { return DEFAULT_PORT; }
|
||||
|
||||
bool startBridgeManually() const override { return false; }
|
||||
|
||||
String configPrefix() const override { return "library_bridge"; }
|
||||
|
||||
const Poco::Util::AbstractConfiguration & getConfig() const override { return config; }
|
||||
|
||||
Poco::Logger * getLog() const override { return log; }
|
||||
|
||||
Poco::Timespan getHTTPTimeout() const override { return http_timeout; }
|
||||
|
||||
Poco::URI createBaseURI() const override;
|
||||
|
||||
QueryPipeline loadBase(const Poco::URI & uri, ReadWriteBufferFromHTTP::OutStreamCallback out_stream_callback = {});
|
||||
|
||||
bool executeRequest(const Poco::URI & uri, ReadWriteBufferFromHTTP::OutStreamCallback out_stream_callback = {}) const;
|
||||
@ -94,20 +73,10 @@ private:
|
||||
|
||||
Poco::URI createRequestURI(const String & method) const;
|
||||
|
||||
static String getDictIdsString(const std::vector<UInt64> & ids);
|
||||
|
||||
Poco::Logger * log;
|
||||
const Block sample_block;
|
||||
const Poco::Util::AbstractConfiguration & config;
|
||||
const Poco::Timespan http_timeout;
|
||||
|
||||
LibraryInitData library_data;
|
||||
Field dictionary_id;
|
||||
std::string bridge_host;
|
||||
size_t bridge_port;
|
||||
bool library_initialized = false;
|
||||
ConnectionTimeouts http_timeouts;
|
||||
Poco::Net::HTTPBasicCredentials credentials{};
|
||||
};
|
||||
|
||||
}
|
||||
|
34
src/BridgeHelper/LibraryBridgeHelper.cpp
Normal file
34
src/BridgeHelper/LibraryBridgeHelper.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "LibraryBridgeHelper.h"
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
LibraryBridgeHelper::LibraryBridgeHelper(ContextPtr context_)
|
||||
: IBridgeHelper(context_)
|
||||
, config(context_->getConfigRef())
|
||||
, log(&Poco::Logger::get("LibraryBridgeHelper"))
|
||||
, http_timeout(context_->getGlobalContext()->getSettingsRef().http_receive_timeout.value)
|
||||
, bridge_host(config.getString("library_bridge.host", DEFAULT_HOST))
|
||||
, bridge_port(config.getUInt("library_bridge.port", DEFAULT_PORT))
|
||||
, http_timeouts(ConnectionTimeouts::getHTTPTimeouts(context_))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LibraryBridgeHelper::startBridge(std::unique_ptr<ShellCommand> cmd) const
|
||||
{
|
||||
getContext()->addBridgeCommand(std::move(cmd));
|
||||
}
|
||||
|
||||
|
||||
Poco::URI LibraryBridgeHelper::createBaseURI() const
|
||||
{
|
||||
Poco::URI uri;
|
||||
uri.setHost(bridge_host);
|
||||
uri.setPort(bridge_port);
|
||||
uri.setScheme("http");
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
}
|
51
src/BridgeHelper/LibraryBridgeHelper.h
Normal file
51
src/BridgeHelper/LibraryBridgeHelper.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <Interpreters/Context.h>
|
||||
#include <IO/ReadWriteBufferFromHTTP.h>
|
||||
#include <Poco/Logger.h>
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <BridgeHelper/IBridgeHelper.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
// Common base class to access the clickhouse-library-bridge.
|
||||
class LibraryBridgeHelper : public IBridgeHelper
|
||||
{
|
||||
protected:
|
||||
explicit LibraryBridgeHelper(ContextPtr context_);
|
||||
|
||||
void startBridge(std::unique_ptr<ShellCommand> cmd) const override;
|
||||
|
||||
String serviceAlias() const override { return "clickhouse-library-bridge"; }
|
||||
|
||||
String serviceFileName() const override { return serviceAlias(); }
|
||||
|
||||
size_t getDefaultPort() const override { return DEFAULT_PORT; }
|
||||
|
||||
bool startBridgeManually() const override { return false; }
|
||||
|
||||
String configPrefix() const override { return "library_bridge"; }
|
||||
|
||||
const Poco::Util::AbstractConfiguration & getConfig() const override { return config; }
|
||||
|
||||
Poco::Logger * getLog() const override { return log; }
|
||||
|
||||
Poco::Timespan getHTTPTimeout() const override { return http_timeout; }
|
||||
|
||||
Poco::URI createBaseURI() const override;
|
||||
|
||||
static constexpr inline size_t DEFAULT_PORT = 9012;
|
||||
|
||||
const Poco::Util::AbstractConfiguration & config;
|
||||
Poco::Logger * log;
|
||||
const Poco::Timespan http_timeout;
|
||||
std::string bridge_host;
|
||||
size_t bridge_port;
|
||||
ConnectionTimeouts http_timeouts;
|
||||
Poco::Net::HTTPBasicCredentials credentials{};
|
||||
};
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <Common/BridgeProtocolVersion.h>
|
||||
#include <Common/ShellCommand.h>
|
||||
#include <Common/logger_useful.h>
|
||||
#include <IO/ConnectionTimeoutsContext.h>
|
||||
@ -86,6 +87,7 @@ protected:
|
||||
{
|
||||
auto uri = createBaseURI();
|
||||
uri.setPath(MAIN_HANDLER);
|
||||
uri.addQueryParameter("version", std::to_string(XDBC_BRIDGE_PROTOCOL_VERSION));
|
||||
return uri;
|
||||
}
|
||||
|
||||
@ -163,6 +165,7 @@ protected:
|
||||
{
|
||||
auto uri = createBaseURI();
|
||||
uri.setPath(COL_INFO_HANDLER);
|
||||
uri.addQueryParameter("version", std::to_string(XDBC_BRIDGE_PROTOCOL_VERSION));
|
||||
return uri;
|
||||
}
|
||||
|
||||
@ -184,6 +187,7 @@ protected:
|
||||
|
||||
auto uri = createBaseURI();
|
||||
uri.setPath(SCHEMA_ALLOWED_HANDLER);
|
||||
uri.addQueryParameter("version", std::to_string(XDBC_BRIDGE_PROTOCOL_VERSION));
|
||||
uri.addQueryParameter("connection_string", getConnectionString());
|
||||
|
||||
ReadWriteBufferFromHTTP buf(uri, Poco::Net::HTTPRequest::HTTP_POST, {}, ConnectionTimeouts::getHTTPTimeouts(getContext()), credentials);
|
||||
@ -204,6 +208,7 @@ protected:
|
||||
|
||||
auto uri = createBaseURI();
|
||||
uri.setPath(IDENTIFIER_QUOTE_HANDLER);
|
||||
uri.addQueryParameter("version", std::to_string(XDBC_BRIDGE_PROTOCOL_VERSION));
|
||||
uri.addQueryParameter("connection_string", getConnectionString());
|
||||
|
||||
ReadWriteBufferFromHTTP buf(uri, Poco::Net::HTTPRequest::HTTP_POST, {}, ConnectionTimeouts::getHTTPTimeouts(getContext()), credentials);
|
||||
|
14
src/Common/BridgeProtocolVersion.h
Normal file
14
src/Common/BridgeProtocolVersion.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
// Version of protocol between clickhouse-server and clickhouse-library-bridge. Increment if you change it in a non-compatible way.
|
||||
static constexpr size_t LIBRARY_BRIDGE_PROTOCOL_VERSION = 1;
|
||||
|
||||
// Version of protocol between clickhouse-server and clickhouse-xdbc-bridge. Increment if you change it in a non-compatible way.
|
||||
static constexpr size_t XDBC_BRIDGE_PROTOCOL_VERSION = 1;
|
||||
|
||||
}
|
@ -103,6 +103,9 @@ REGISTER_FUNCTION(Conversion)
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffort>();
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffortOrZero>();
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffortOrNull>();
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffortUS>();
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffortUSOrZero>();
|
||||
factory.registerFunction<FunctionParseDateTime64BestEffortUSOrNull>();
|
||||
|
||||
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalNanosecond, PositiveMonotonicity>>();
|
||||
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalMicrosecond, PositiveMonotonicity>>();
|
||||
|
@ -1336,9 +1336,18 @@ struct ConvertThroughParsing
|
||||
}
|
||||
else if constexpr (parsing_mode == ConvertFromStringParsingMode::BestEffortUS)
|
||||
{
|
||||
time_t res;
|
||||
parsed = tryParseDateTimeBestEffortUS(res, read_buffer, *local_time_zone, *utc_time_zone);
|
||||
convertFromTime<ToDataType>(vec_to[i],res);
|
||||
if constexpr (to_datetime64)
|
||||
{
|
||||
DateTime64 res = 0;
|
||||
parsed = tryParseDateTime64BestEffortUS(res, col_to->getScale(), read_buffer, *local_time_zone, *utc_time_zone);
|
||||
vec_to[i] = res;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_t res;
|
||||
parsed = tryParseDateTimeBestEffortUS(res, read_buffer, *local_time_zone, *utc_time_zone);
|
||||
convertFromTime<ToDataType>(vec_to[i],res);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2525,6 +2534,9 @@ struct NameParseDateTime32BestEffortOrNull { static constexpr auto name = "parse
|
||||
struct NameParseDateTime64BestEffort { static constexpr auto name = "parseDateTime64BestEffort"; };
|
||||
struct NameParseDateTime64BestEffortOrZero { static constexpr auto name = "parseDateTime64BestEffortOrZero"; };
|
||||
struct NameParseDateTime64BestEffortOrNull { static constexpr auto name = "parseDateTime64BestEffortOrNull"; };
|
||||
struct NameParseDateTime64BestEffortUS { static constexpr auto name = "parseDateTime64BestEffortUS"; };
|
||||
struct NameParseDateTime64BestEffortUSOrZero { static constexpr auto name = "parseDateTime64BestEffortUSOrZero"; };
|
||||
struct NameParseDateTime64BestEffortUSOrNull { static constexpr auto name = "parseDateTime64BestEffortUSOrNull"; };
|
||||
|
||||
|
||||
using FunctionParseDateTimeBestEffort = FunctionConvertFromString<
|
||||
@ -2555,6 +2567,14 @@ using FunctionParseDateTime64BestEffortOrZero = FunctionConvertFromString<
|
||||
using FunctionParseDateTime64BestEffortOrNull = FunctionConvertFromString<
|
||||
DataTypeDateTime64, NameParseDateTime64BestEffortOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffort>;
|
||||
|
||||
using FunctionParseDateTime64BestEffortUS = FunctionConvertFromString<
|
||||
DataTypeDateTime64, NameParseDateTime64BestEffortUS, ConvertFromStringExceptionMode::Throw, ConvertFromStringParsingMode::BestEffortUS>;
|
||||
using FunctionParseDateTime64BestEffortUSOrZero = FunctionConvertFromString<
|
||||
DataTypeDateTime64, NameParseDateTime64BestEffortUSOrZero, ConvertFromStringExceptionMode::Zero, ConvertFromStringParsingMode::BestEffortUS>;
|
||||
using FunctionParseDateTime64BestEffortUSOrNull = FunctionConvertFromString<
|
||||
DataTypeDateTime64, NameParseDateTime64BestEffortUSOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffortUS>;
|
||||
|
||||
|
||||
class ExecutableFunctionCast : public IExecutableFunction
|
||||
{
|
||||
public:
|
||||
|
@ -697,4 +697,9 @@ bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & i
|
||||
return parseDateTime64BestEffortImpl<bool, false>(res, scale, in, local_time_zone, utc_time_zone);
|
||||
}
|
||||
|
||||
bool tryParseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone)
|
||||
{
|
||||
return parseDateTime64BestEffortImpl<bool, true>(res, scale, in, local_time_zone, utc_time_zone);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ class ReadBuffer;
|
||||
*
|
||||
* DD/MM/YY
|
||||
* DD/MM/YYYY - when '/' separator is used, these are the only possible forms
|
||||
* Note that American style is not supported.
|
||||
*
|
||||
* hh:mm:ss - when ':' separator is used, it is always time
|
||||
* hh:mm - it can be specified without seconds
|
||||
@ -61,7 +60,7 @@ bool tryParseDateTimeBestEffort(time_t & res, ReadBuffer & in, const DateLUTImpl
|
||||
void parseDateTimeBestEffortUS(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
bool tryParseDateTimeBestEffortUS(time_t & res, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
void parseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
void parseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
bool tryParseDateTime64BestEffort(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
|
||||
void parseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
bool tryParseDateTime64BestEffortUS(DateTime64 & res, UInt32 scale, ReadBuffer & in, const DateLUTImpl & local_time_zone, const DateLUTImpl & utc_time_zone);
|
||||
}
|
||||
|
@ -1179,15 +1179,21 @@ class TestSuite:
|
||||
def is_shebang(line: str) -> bool:
|
||||
return line.startswith("#!")
|
||||
|
||||
def find_tag_line(file):
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
if line and not is_shebang(line):
|
||||
return line
|
||||
return ''
|
||||
|
||||
def load_tags_from_file(filepath):
|
||||
comment_sign = get_comment_sign(filepath)
|
||||
with open(filepath, "r", encoding="utf-8") as file:
|
||||
try:
|
||||
line = file.readline()
|
||||
if is_shebang(line):
|
||||
line = file.readline()
|
||||
line = find_tag_line(file)
|
||||
except UnicodeDecodeError:
|
||||
return []
|
||||
return parse_tags_from_line(line, get_comment_sign(filepath))
|
||||
return parse_tags_from_line(line, comment_sign)
|
||||
|
||||
all_tags = {}
|
||||
start_time = datetime.now()
|
||||
|
@ -6,10 +6,10 @@ CREATE TABLE t_part_log_has_merge_type_table
|
||||
UserID UInt64,
|
||||
Comment String
|
||||
)
|
||||
ENGINE = MergeTree()
|
||||
ENGINE = MergeTree()
|
||||
ORDER BY tuple()
|
||||
TTL event_time + INTERVAL 3 MONTH
|
||||
SETTINGS min_bytes_for_wide_part = 0, materialize_ttl_recalculate_only = true;
|
||||
SETTINGS min_bytes_for_wide_part = 0, materialize_ttl_recalculate_only = true, max_number_of_merges_with_ttl_in_pool = 100;
|
||||
|
||||
INSERT INTO t_part_log_has_merge_type_table VALUES (now(), 1, 'username1');
|
||||
INSERT INTO t_part_log_has_merge_type_table VALUES (now() - INTERVAL 4 MONTH, 2, 'username2');
|
||||
@ -20,7 +20,7 @@ SYSTEM FLUSH LOGS;
|
||||
|
||||
SELECT
|
||||
event_type,
|
||||
merge_reason
|
||||
merge_reason
|
||||
FROM
|
||||
system.part_log
|
||||
WHERE
|
||||
|
@ -0,0 +1,12 @@
|
||||
parseDateTime64BestEffortUS
|
||||
s a
|
||||
|
||||
01-02-1930 12:00:00 1930-01-02 12:00:00.000
|
||||
12.02.1930 12:00:00 1930-12-02 12:00:00.000
|
||||
13/02/1930 12:00:00 1930-02-13 12:00:00.000
|
||||
02/25/1930 12:00:00 1930-02-25 12:00:00.000
|
||||
|
||||
parseDateTime64BestEffortUSOrNull
|
||||
\N
|
||||
parseDateTime64BestEffortUSOrZero
|
||||
1970-01-01 00:00:00.000
|
@ -0,0 +1,22 @@
|
||||
SELECT 'parseDateTime64BestEffortUS';
|
||||
|
||||
SELECT
|
||||
s,
|
||||
parseDateTime64BestEffortUS(s,3,'UTC') AS a
|
||||
FROM
|
||||
(
|
||||
SELECT arrayJoin([
|
||||
'01-02-1930 12:00:00',
|
||||
'12.02.1930 12:00:00',
|
||||
'13/02/1930 12:00:00',
|
||||
'02/25/1930 12:00:00'
|
||||
]) AS s)
|
||||
FORMAT PrettySpaceNoEscapes;
|
||||
|
||||
SELECT '';
|
||||
|
||||
SELECT 'parseDateTime64BestEffortUSOrNull';
|
||||
SELECT parseDateTime64BestEffortUSOrNull('01/45/1925 16:00:00',3,'UTC');
|
||||
|
||||
SELECT 'parseDateTime64BestEffortUSOrZero';
|
||||
SELECT parseDateTime64BestEffortUSOrZero('01/45/1925 16:00:00',3,'UTC');
|
Loading…
Reference in New Issue
Block a user