Merge branch 'master' of github.com:yandex/ClickHouse

This commit is contained in:
Ivan Blinkov 2018-11-01 16:24:11 +03:00
commit 8ccc06b5ac
130 changed files with 1611 additions and 758 deletions

6
.gitignore vendored
View File

@ -9,7 +9,10 @@
# auto generated files # auto generated files
*.logrt *.logrt
dbms/src/Storages/System/StorageSystemContributors.generated.cpp
/build /build
/build_*
/docs/build /docs/build
/docs/edit /docs/edit
/docs/tools/venv/ /docs/tools/venv/
@ -243,3 +246,6 @@ website/presentations
website/package-lock.json website/package-lock.json
.DS_Store .DS_Store
*/.DS_Store */.DS_Store
# Ignore files for locally disabled tests
/dbms/tests/queries/**/*.disabled

View File

@ -0,0 +1 @@
* Настройка `enable_optimize_predicate_expression` выключена по-умолчанию.

View File

@ -1,117 +1,129 @@
## ClickHouse release 18.14.11, 2018-10-29
### Исправления ошибок:
* Исправлена ошибка `Block structure mismatch in UNION stream: different number of columns` в запросах с LIMIT. [#2156](https://github.com/yandex/ClickHouse/issues/2156)
* Исправлены ошибки при слиянии данных в таблицах, содержащих массивы внутри Nested структур. [#3397](https://github.com/yandex/ClickHouse/pull/3397)
* Исправлен неправильный результат запросов при выключенной настройке `merge_tree_uniform_read_distribution` (включена по умолчанию). [#3429](https://github.com/yandex/ClickHouse/pull/3429)
* Исправлена ошибка при вставке в Distributed таблицу в формате Native. [#3411](https://github.com/yandex/ClickHouse/issues/3411)
## ClickHouse release 18.14.10, 2018-10-23
* Настройка `compile_expressions` (JIT компиляция выражений) выключена по умолчанию. [#3410](https://github.com/yandex/ClickHouse/pull/3410)
* Настройка `enable_optimize_predicate_expression` выключена по умолчанию.
## ClickHouse release 18.14.9, 2018-10-16 ## ClickHouse release 18.14.9, 2018-10-16
### Новые возможности: ### Новые возможности:
* Модификатор `WITH CUBE` для `GROUP BY` (также доступен синтаксис: `GROUP BY CUBE(...)`). * Модификатор `WITH CUBE` для `GROUP BY` (также доступен синтаксис: `GROUP BY CUBE(...)`). [#3172](https://github.com/yandex/ClickHouse/pull/3172)
* Добавлена функция `formatDateTime`. [Alexandr Krasheninnikov]() * Добавлена функция `formatDateTime`. [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/2770)
* Добавлен движок таблиц `JDBC` и табличная функция `jdbc` (для работы требуется установка clickhouse-jdbc-bridge). [Alexandr Krasheninnikov]() * Добавлен движок таблиц `JDBC` и табличная функция `jdbc` (для работы требуется установка clickhouse-jdbc-bridge). [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/3210)
* Добавлены функции для работы с ISO номером недели: `toISOWeek`, `toISOYear`, `toStartOfISOYear`. * Добавлены функции для работы с ISO номером недели: `toISOWeek`, `toISOYear`, `toStartOfISOYear`, а также `toDayOfYear`. [#3146](https://github.com/yandex/ClickHouse/pull/3146)
* Добавлена функция `toDayOfYear`. * Добавлена возможность использования столбцов типа `Nullable` для таблиц типа `MySQL`, `ODBC`. [#3362](https://github.com/yandex/ClickHouse/pull/3362)
* Добавлена возможность использования столбцов типа `Nullable` для таблиц типа `MySQL`, `ODBC`. * Возможность чтения вложенных структур данных как вложенных объектов в формате `JSONEachRow`. Добавлена настройка `input_format_import_nested_json`. [Veloman Yunkan](https://github.com/yandex/ClickHouse/pull/3144)
* Возможность чтения вложенных структур данных как вложенных объектов в формате `JSONEachRow`. Добавлена настройка `input_format_import_nested_json`. [Veloman Yunkan](). * Возможность параллельной обработки многих `MATERIALIZED VIEW` при вставке данных. Настройка `parallel_view_processing`. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3208)
* Возможность параллельной обработки многих `MATERIALIZED VIEW` при вставке данных. Настройка `parallel_view_processing`. [Marek Vavruša](). * Добавлен запрос `SYSTEM FLUSH LOGS` (форсированный сброс логов в системные таблицы, такие как например, `query_log`) [#3321](https://github.com/yandex/ClickHouse/pull/3321)
* Добавлен запрос `SYSTEM FLUSH LOGS` (форсированный сброс логов в системные таблицы, такие как например, `query_log`). * Возможность использования предопределённых макросов `database` и `table` в объявлении `Replicated` таблиц. [#3251](https://github.com/yandex/ClickHouse/pull/3251)
* Возможность использования предопределённых макросов `database` и `table` в объявлении `Replicated` таблиц. * Добавлена возможность чтения значения типа `Decimal` в инженерной нотации (с указанием десятичной экспоненты). [#3153](https://github.com/yandex/ClickHouse/pull/3153)
* Добавлена возможность чтения значения типа `Decimal` в инженерной нотации (с указанием десятичной экспоненты).
### Экспериментальные возможности: ### Экспериментальные возможности:
* Оптимизация GROUP BY для типов данных `LowCardinality`. * Оптимизация GROUP BY для типов данных `LowCardinality` [#3138](https://github.com/yandex/ClickHouse/pull/3138)
* Оптимизации вычисления выражений для типов данных `LowCardinality`. * Оптимизации вычисления выражений для типов данных `LowCardinality` [#3200](https://github.com/yandex/ClickHouse/pull/3200)
### Улучшения: ### Улучшения:
* Существенно уменьшено потребление памяти для запросов с `ORDER BY` и `LIMIT`. Настройка `max_bytes_before_remerge_sort`. * Существенно уменьшено потребление памяти для запросов с `ORDER BY` и `LIMIT`. Настройка `max_bytes_before_remerge_sort`. [#3205](https://github.com/yandex/ClickHouse/pull/3205)
* При отсутствии указания типа `JOIN` (`LEFT`, `INNER`, ...), подразумевается `INNER JOIN`. * При отсутствии указания типа `JOIN` (`LEFT`, `INNER`, ...), подразумевается `INNER JOIN`. [#3147](https://github.com/yandex/ClickHouse/pull/3147)
* Корректная работа квалифицированных звёздочек в запросах с `JOIN`. [Winter Zhang]() * Корректная работа квалифицированных звёздочек в запросах с `JOIN`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3202)
* Движок таблиц `ODBC` корректно выбирает способ квотирования идентификаторов в SQL диалекте удалённой СУБД. [Alexandr Krasheninnikov]() * Движок таблиц `ODBC` корректно выбирает способ квотирования идентификаторов в SQL диалекте удалённой СУБД. [Alexandr Krasheninnikov](https://github.com/yandex/ClickHouse/pull/3210)
* Настройка `compile_expressions` (JIT компиляция выражений) включена по-умолчанию. * Настройка `compile_expressions` (JIT компиляция выражений) включена по-умолчанию.
* Исправлено поведение при одновременном DROP DATABASE/TABLE IF EXISTS и CREATE DATABASE/TABLE IF NOT EXISTS. Ранее запрос `CREATE DATABASE ... IF NOT EXISTS` мог выдавать сообщение об ошибке вида "File ... already exists", а запросы `CREATE TABLE ... IF NOT EXISTS` и `DROP TABLE IF EXISTS` могли выдавать сообщение `Table ... is creating or attaching right now`. * Исправлено поведение при одновременном DROP DATABASE/TABLE IF EXISTS и CREATE DATABASE/TABLE IF NOT EXISTS. Ранее запрос `CREATE DATABASE ... IF NOT EXISTS` мог выдавать сообщение об ошибке вида "File ... already exists", а запросы `CREATE TABLE ... IF NOT EXISTS` и `DROP TABLE IF EXISTS` могли выдавать сообщение `Table ... is creating or attaching right now`. [#3101](https://github.com/yandex/ClickHouse/pull/3101)
* Выражения LIKE и IN с константной правой частью пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. * Выражения LIKE и IN с константной правой частью пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. [#3182](https://github.com/yandex/ClickHouse/pull/3182)
* Сравнения с константными выражениями в секции WHERE пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. Ранее пробрасывались только сравнения с константами. * Сравнения с константными выражениями в секции WHERE пробрасываются на удалённый сервер при запросах из таблиц типа MySQL и ODBC. Ранее пробрасывались только сравнения с константами. [#3182](https://github.com/yandex/ClickHouse/pull/3182)
* Корректное вычисление ширины строк в терминале для `Pretty` форматов, в том числе для строк с иероглифами. [Amos Bird](). * Корректное вычисление ширины строк в терминале для `Pretty` форматов, в том числе для строк с иероглифами. [Amos Bird](https://github.com/yandex/ClickHouse/pull/3257).
* Возможность указания `ON CLUSTER` для запросов `ALTER UPDATE`. * Возможность указания `ON CLUSTER` для запросов `ALTER UPDATE`.
* Увеличена производительность чтения данных в формате `JSONEachRow`. * Увеличена производительность чтения данных в формате `JSONEachRow`. [#3332](https://github.com/yandex/ClickHouse/pull/3332)
* Добавлены синонимы функций `LENGTH`, `CHARACTER_LENGTH` для совместимости. Функция `CONCAT` стала регистронезависимой. * Добавлены синонимы функций `LENGTH`, `CHARACTER_LENGTH` для совместимости. Функция `CONCAT` стала регистронезависимой. [#3306](https://github.com/yandex/ClickHouse/pull/3306)
* Добавлен синоним `TIMESTAMP` для типа `DateTime`. * Добавлен синоним `TIMESTAMP` для типа `DateTime`. [#3390](https://github.com/yandex/ClickHouse/pull/3390)
* В логах сервера всегда присутствует место для query_id, даже если строчка лога не относится к запросу. Это сделано для более простого парсинга текстовых логов сервера сторонними инструментами. * В логах сервера всегда присутствует место для query_id, даже если строчка лога не относится к запросу. Это сделано для более простого парсинга текстовых логов сервера сторонними инструментами.
* Логгирование потребления памяти запросом при превышении очередной отметки целого числа гигабайт. * Логгирование потребления памяти запросом при превышении очередной отметки целого числа гигабайт. [#3205](https://github.com/yandex/ClickHouse/pull/3205)
* Добавлен режим совместимости для случая, когда клиентская библиотека, работающая по Native протоколу, по ошибке отправляет меньшее количество столбцов, чем сервер ожидает для запроса INSERT. Такой сценарий был возможен при использовании библиотеки clickhouse-cpp. Ранее этот сценарий приводил к падению сервера. * Добавлен режим совместимости для случая, когда клиентская библиотека, работающая по Native протоколу, по ошибке отправляет меньшее количество столбцов, чем сервер ожидает для запроса INSERT. Такой сценарий был возможен при использовании библиотеки clickhouse-cpp. Ранее этот сценарий приводил к падению сервера. [#3171](https://github.com/yandex/ClickHouse/pull/3171)
* В `clickhouse-copier`, в задаваемом пользователем выражении WHERE, появилась возможность использовать алиас `partition_key` (для дополнительной фильтрации по партициям исходной таблицы). Это полезно, если схема партиционирования изменяется при копировании, но изменяется незначительно. * В `clickhouse-copier`, в задаваемом пользователем выражении WHERE, появилась возможность использовать алиас `partition_key` (для дополнительной фильтрации по партициям исходной таблицы). Это полезно, если схема партиционирования изменяется при копировании, но изменяется незначительно. [#3166](https://github.com/yandex/ClickHouse/pull/3166)
* Рабочий поток движка `Kafka` перенесён в фоновый пул потоков для того, чтобы автоматически уменьшать скорость чтения данных при большой нагрузке. [Marek Vavruša](). * Рабочий поток движка `Kafka` перенесён в фоновый пул потоков для того, чтобы автоматически уменьшать скорость чтения данных при большой нагрузке. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3215).
* Поддержка чтения значений типа `Tuple` и `Nested` структур как `struct` в формате `Cap'n'Proto` [Marek Vavruša](). * Поддержка чтения значений типа `Tuple` и `Nested` структур как `struct` в формате `Cap'n'Proto` [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3216).
* В список доменов верхнего уровня для функции `firstSignificantSubdomain` добавлен домен `biz` [decaseal](). * В список доменов верхнего уровня для функции `firstSignificantSubdomain` добавлен домен `biz` [decaseal](https://github.com/yandex/ClickHouse/pull/3219).
* В конфигурации внешних словарей, пустое значение `null_value` интерпретируется, как значение типа данных по-умоланию. * В конфигурации внешних словарей, пустое значение `null_value` интерпретируется, как значение типа данных по-умоланию. [#3330](https://github.com/yandex/ClickHouse/pull/3330)
* Поддержка функций `intDiv`, `intDivOrZero` для `Decimal`. * Поддержка функций `intDiv`, `intDivOrZero` для `Decimal`. [b48402e8](https://github.com/yandex/ClickHouse/commit/b48402e8712e2b9b151e0eef8193811d433a1264)
* Поддержка типов `Date`, `DateTime`, `UUID`, `Decimal` в качестве ключа для агрегатной функции `sumMap`. * Поддержка типов `Date`, `DateTime`, `UUID`, `Decimal` в качестве ключа для агрегатной функции `sumMap`. [#3281](https://github.com/yandex/ClickHouse/pull/3281)
* Поддержка типа данных `Decimal` во внешних словарях. * Поддержка типа данных `Decimal` во внешних словарях. [#3324](https://github.com/yandex/ClickHouse/pull/3324)
* Поддержка типа данных `Decimal` в таблицах типа `SummingMergeTree`. * Поддержка типа данных `Decimal` в таблицах типа `SummingMergeTree`. [#3348](https://github.com/yandex/ClickHouse/pull/3348)
* Добавлена специализация для `UUID` в функции `if`. * Добавлена специализация для `UUID` в функции `if`. [#3366](https://github.com/yandex/ClickHouse/pull/3366)
* Уменьшено количество системных вызовов `open`, `close` при чтении из таблиц семейства `MergeTree`. * Уменьшено количество системных вызовов `open`, `close` при чтении из таблиц семейства `MergeTree` [#3283](https://github.com/yandex/ClickHouse/pull/3283).
* Возможность выполнения запроса `TRUNCATE TABLE` на любой реплике (запрос пробрасывается на реплику-лидера). [Kirill Shvakov]() * Возможность выполнения запроса `TRUNCATE TABLE` на любой реплике (запрос пробрасывается на реплику-лидера). [Kirill Shvakov](https://github.com/yandex/ClickHouse/pull/3375)
### Исправление ошибок: ### Исправление ошибок:
* Исправлена ошибка в работе таблиц типа `Dictionary` для словарей типа `range_hashed`. Ошибка возникла в версии 18.12.17. * Исправлена ошибка в работе таблиц типа `Dictionary` для словарей типа `range_hashed`. Ошибка возникла в версии 18.12.17. [#1702](https://github.com/yandex/ClickHouse/pull/1702)
* Исправлена ошибка при загрузке словарей типа `range_hashed` (сообщение `Unsupported type Nullable(...)`). Ошибка возникла в версии 18.12.17. * Исправлена ошибка при загрузке словарей типа `range_hashed` (сообщение `Unsupported type Nullable(...)`). Ошибка возникла в версии 18.12.17. [#3362](https://github.com/yandex/ClickHouse/pull/3362)
* Исправлена некорректная работа функции `pointInPolygon` из-за накопления погрешности при вычислениях для полигонов с большим количеством близко расположенных вершин. * Исправлена некорректная работа функции `pointInPolygon` из-за накопления погрешности при вычислениях для полигонов с большим количеством близко расположенных вершин. [#3331](https://github.com/yandex/ClickHouse/pull/3331) [#3341](https://github.com/yandex/ClickHouse/pull/3341)
* Если после слияния кусков данных, у результирующего куска чексумма отличается от результата того же слияния на другой реплике, то результат слияния удаляется, и вместо этого кусок скачивается с другой реплики (это правильное поведение). Но после скачивания куска, он не мог добавиться в рабочий набор из-за ошибки, что кусок уже существует (так как кусок после слияния удалялся не сразу, а с задержкой). Это приводило к циклическим попыткам скачивания одних и тех же данных. * Если после слияния кусков данных, у результирующего куска чексумма отличается от результата того же слияния на другой реплике, то результат слияния удаляется, и вместо этого кусок скачивается с другой реплики (это правильное поведение). Но после скачивания куска, он не мог добавиться в рабочий набор из-за ошибки, что кусок уже существует (так как кусок после слияния удалялся не сразу, а с задержкой). Это приводило к циклическим попыткам скачивания одних и тех же данных. [#3194](https://github.com/yandex/ClickHouse/pull/3194)
* Исправлен некорректный учёт общего потребления оперативной памяти запросами (что приводило к неправильной работе настройки `max_memory_usage_for_all_queries` и неправильному значению метрики `MemoryTracking`). Ошибка возникла в версии 18.12.13. [Marek Vavruša]() * Исправлен некорректный учёт общего потребления оперативной памяти запросами (что приводило к неправильной работе настройки `max_memory_usage_for_all_queries` и неправильному значению метрики `MemoryTracking`). Ошибка возникла в версии 18.12.13. [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3344)
* Исправлена работоспособность запросов `CREATE TABLE ... ON CLUSTER ... AS SELECT ...` Ошибка возникла в версии 18.12.13. * Исправлена работоспособность запросов `CREATE TABLE ... ON CLUSTER ... AS SELECT ...` Ошибка возникла в версии 18.12.13. [#3247](https://github.com/yandex/ClickHouse/pull/3247)
* Исправлена лишняя подготовка структуры данных для `JOIN` на сервере-инициаторе запроса, если `JOIN` выполняется только на удалённых серверах. * Исправлена лишняя подготовка структуры данных для `JOIN` на сервере-инициаторе запроса, если `JOIN` выполняется только на удалённых серверах. [#3340](https://github.com/yandex/ClickHouse/pull/3340)
* Исправлены ошибки в движке `Kafka`: неработоспособность после исключения при начале чтения данных; блокировка при завершении [Marek Vavruša](). * Исправлены ошибки в движке `Kafka`: неработоспособность после исключения при начале чтения данных; блокировка при завершении [Marek Vavruša](https://github.com/yandex/ClickHouse/pull/3215).
* Для таблиц `Kafka` не передавался опциональный параметр `schema` (схема формата `Cap'n'Proto`). [Vojtech Splichal] * Для таблиц `Kafka` не передавался опциональный параметр `schema` (схема формата `Cap'n'Proto`). [Vojtech Splichal](https://github.com/yandex/ClickHouse/pull/3150)
* Если ансамбль серверов ZooKeeper содержит серверы, которые принимают соединение, но сразу же разрывают его вместо ответа на рукопожатие, то ClickHouse выбирает для соединения другой сервер. Ранее в этом случае возникала ошибка `Cannot read all data. Bytes read: 0. Bytes expected: 4.` и сервер не мог стартовать. * Если ансамбль серверов ZooKeeper содержит серверы, которые принимают соединение, но сразу же разрывают его вместо ответа на рукопожатие, то ClickHouse выбирает для соединения другой сервер. Ранее в этом случае возникала ошибка `Cannot read all data. Bytes read: 0. Bytes expected: 4.` и сервер не мог стартовать. [8218cf3a](https://github.com/yandex/ClickHouse/commit/8218cf3a5f39a43401953769d6d12a0bb8d29da9)
* Если ансамбль серверов ZooKeeper содержит серверы, для которых DNS запрос возвращает ошибку, то такие серверы пропускаются. * Если ансамбль серверов ZooKeeper содержит серверы, для которых DNS запрос возвращает ошибку, то такие серверы пропускаются. [17b8e209](https://github.com/yandex/ClickHouse/commit/17b8e209221061325ad7ba0539f03c6e65f87f29)
* Исправлено преобразование типов между `Date` и `DateTime` при вставке данных в формате `VALUES` (в случае, когда `input_format_values_interpret_expressions = 1`). Ранее преобразование производилось между числовым значением количества дней с начала unix эпохи и unix timestamp, что приводило к неожиданным результатам. * Исправлено преобразование типов между `Date` и `DateTime` при вставке данных в формате `VALUES` (в случае, когда `input_format_values_interpret_expressions = 1`). Ранее преобразование производилось между числовым значением количества дней с начала unix эпохи и unix timestamp, что приводило к неожиданным результатам. [#3229](https://github.com/yandex/ClickHouse/pull/3229)
* Исправление преобразования типов между `Decimal` и целыми числами. * Исправление преобразования типов между `Decimal` и целыми числами. [#3211](https://github.com/yandex/ClickHouse/pull/3211)
* Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang]() * Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3231)
* Настройка `enable_optimize_predicate_expression` выключена по-умолчанию. * Исправлена ошибка парсинга формата CSV с числами с плавающей запятой, если используется разделитель CSV не по-умолчанию, такой как например, `;` [#3155](https://github.com/yandex/ClickHouse/pull/3155).
* Исправлена ошибка парсинга формата CSV с числами с плавающей запятой, если используется разделитель CSV не по-умолчанию, такой как например, `;`. * Исправлена функция `arrayCumSumNonNegative` (она не накапливает отрицательные значения, если аккумулятор становится меньше нуля). [Aleksey Studnev](https://github.com/yandex/ClickHouse/pull/3163)
* Испоавлена функция `arrayCumSumNonNegative` (она не накапливает отрицательные значения, если аккумулятор становится меньше нуля). * Исправлена работа `Merge` таблицы поверх `Distributed` таблиц при использовании `PREWHERE`. [#3165](https://github.com/yandex/ClickHouse/pull/3165)
* Исправлена работа `Merge` таблицы поверх `Distributed` таблиц при использовании `PREWHERE`. * Исправления ошибок в запросе `ALTER UPDATE`.
* Исправления ошибок в запросе ALTER UPDATE. * Исправления ошибок в табличной функции `odbc`, которые возникли в версии 18.12. [#3197](https://github.com/yandex/ClickHouse/pull/3197)
* Исправления ошибок в табличной функции `odbc`, которые возникли в версии 18.12. * Исправлена работа агрегатных функций с комбинаторами `StateArray`. [#3188](https://github.com/yandex/ClickHouse/pull/3188)
* Исправлена работа агрегатных функций с комбинаторами `StateArray`. * Исправлено падение при делении значения типа `Decimal` на ноль. [69dd6609](https://github.com/yandex/ClickHouse/commit/69dd6609193beb4e7acd3e6ad216eca0ccfb8179)
* Исправлено падение при делении значения типа `Decimal` на ноль. * Исправлен вывод типов для операций с использованием аргументов типа `Decimal` и целых чисел. [#3224](https://github.com/yandex/ClickHouse/pull/3224)
* Исправлен вывод типов для операций с использованием аргументов типа `Decimal` и целых чисел. * Исправлен segfault при `GROUP BY` по `Decimal128`. [3359ba06](https://github.com/yandex/ClickHouse/commit/3359ba06c39fcd05bfdb87d6c64154819621e13a)
* Исправлен segfault при `GROUP BY` по `Decimal128`. * Настройка `log_query_threads` (логгирование информации о каждом потоке исполнения запроса) теперь имеет эффект только если настройка `log_queries` (логгирование информации о запросах) выставлена в 1. Так как настройка `log_query_threads` включена по-умолчанию, ранее информация о потоках логгировалась даже если логгирование запросов выключено. [#3241](https://github.com/yandex/ClickHouse/pull/3241)
* Настройка `log_query_threads` (логгирование информации о каждом потоке исполнения запроса) теперь имеет эффект только если настройка `log_queries` (логгирование информации о запросах) выставлена в 1. Так как настройка `log_query_threads` включена по-умолчанию, ранее информация о потоках логгировалась даже если логгирование запросов выключено. * Исправлена ошибка в распределённой работе агрегатной функции quantiles (сообщение об ошибке вида `Not found column quantile...`). [292a8855](https://github.com/yandex/ClickHouse/commit/292a885533b8e3b41ce8993867069d14cbd5a664)
* Исправлена ошибка в распределённой работе агрегатной функции quantiles (сообщение об ошибке вида `Not found column quantile...`). * Исправлена проблема совместимости при одновременной работе на кластере серверов версии 18.12.17 и более старых, приводящая к тому, что при распределённых запросах с GROUP BY по ключам одновременно фиксированной и не фиксированной длины, при условии, что количество данных в процессе агрегации большое, могли возвращаться не до конца агрегированные данные (одни и те же ключи агрегации в двух разных строках). [#3254](https://github.com/yandex/ClickHouse/pull/3254)
* Исправлена проблема совместимости при одновременной работе на кластере серверов версии 18.12.17 и более старых, приводящая к тому, что при распределённых запросах с GROUP BY по ключам одновременно фиксированной и не фиксированной длины, при условии, что количество данных в процессе агрегации большое, могли возвращаться не до конца агрегированные данные (одни и те же ключи агрегации в двух разных строках). * Исправлена обработка подстановок в `clickhouse-performance-test`, если запрос содержит только часть из объявленных в тесте подстановок. [#3263](https://github.com/yandex/ClickHouse/pull/3263)
* Исправлена обработка подстановок в `clickhouse-performance-test`, если запрос содержит только часть из объявленных в тесте подстановок. * Исправлена ошибка при использовании `FINAL` совместно с `PREWHERE`. [#3298](https://github.com/yandex/ClickHouse/pull/3298)
* Исправлена ошибка при использовании `FINAL` совместно с `PREWHERE`. * Исправлена ошибка при использовании `PREWHERE` над столбцами, добавленными при `ALTER`. [#3298](https://github.com/yandex/ClickHouse/pull/3298)
* Исправлена ошибка при использовании `PREWHERE` над столбцами, добавленными при `ALTER`. * Добавлена проверка отсутствия `arrayJoin` для `DEFAULT`, `MATERIALIZED` выражений. Ранее наличие `arrayJoin` приводило к ошибке при вставке данных. [#3337](https://github.com/yandex/ClickHouse/pull/3337)
* Добавлена проверка отсутствия `arrayJoin` для `DEFAULT`, `MATERIALIZED` выражений. Ранее наличие `arrayJoin` приводило к ошибке при вставке данных. * Добавлена проверка отсутствия `arrayJoin` в секции `PREWHERE`. Ранее это приводило к сообщениям вида `Size ... doesn't match` или `Unknown compression method` при выполнении запросов. [#3357](https://github.com/yandex/ClickHouse/pull/3357)
* Добавлена проверка отсутствия `arrayJoin` в секции `PREWHERE`. Ранее это приводило к сообщениям вида `Size ... doesn't match` или `Unknown compression method` при выполнении запросов. * Исправлен segfault, который мог возникать в редких случаях после оптимизации - замены цепочек AND из равенства выражения константам на соответствующее выражение IN. [liuyimin-bytedance](https://github.com/yandex/ClickHouse/pull/3339).
* Исправлен segfault, который мог возникать в редких случаях после оптимизации - замены цепочек AND из равенства выражения константам на соответствующее выражение IN. [liuyimin](). * Мелкие исправления `clickhouse-benchmark`: ранее информация о клиенте не передавалась на сервер; более корректный подсчёт числа выполненных запросов при завершении работы и для ограничения числа итераций. [#3351](https://github.com/yandex/ClickHouse/pull/3351) [#3352](https://github.com/yandex/ClickHouse/pull/3352)
* Мелкие исправления `clickhouse-benchmark`: ранее информация о клиенте не передавалась на сервер; более корректный подсчёт числа выполненных запросов при завершении работы и для ограничения числа итераций.
### Обратно несовместимые изменения: ### Обратно несовместимые изменения:
* Удалена настройка `allow_experimental_decimal_type`. Тип данных `Decimal` доступен для использования по-умолчанию. * Удалена настройка `allow_experimental_decimal_type`. Тип данных `Decimal` доступен для использования по-умолчанию. [#3329](https://github.com/yandex/ClickHouse/pull/3329)
## ClickHouse release 18.12.17, 2018-09-16 ## ClickHouse release 18.12.17, 2018-09-16
### Новые возможности: ### Новые возможности:
* `invalidate_query` (возможность задать запрос для проверки необходимости обновления внешнего словаря) реализована для источника `clickhouse`. * `invalidate_query` (возможность задать запрос для проверки необходимости обновления внешнего словаря) реализована для источника `clickhouse`. [#3126](https://github.com/yandex/ClickHouse/pull/3126)
* Добавлена возможность использования типов данных `UInt*`, `Int*`, `DateTime` (наравне с типом `Date`) в качестве ключа внешнего словаря типа `range_hashed`, определяющего границы диапазонов. Возможность использования NULL в качестве обозначения открытого диапазона. [Vasily Nemkov]() * Добавлена возможность использования типов данных `UInt*`, `Int*`, `DateTime` (наравне с типом `Date`) в качестве ключа внешнего словаря типа `range_hashed`, определяющего границы диапазонов. Возможность использования `NULL` в качестве обозначения открытого диапазона. [Vasily Nemkov](https://github.com/yandex/ClickHouse/pull/3123)
* Для типа `Decimal` добавлена поддержка агрегатных функций `var*`, `stddev*`. * Для типа `Decimal` добавлена поддержка агрегатных функций `var*`, `stddev*`. [#3129](https://github.com/yandex/ClickHouse/pull/3129)
* Для типа `Decimal` добавлена поддержка математических функций (`exp`, `sin` и т. п.) * Для типа `Decimal` добавлена поддержка математических функций (`exp`, `sin` и т. п.) [#3129](https://github.com/yandex/ClickHouse/pull/3129)
* В таблицу `system.part_log` добавлен столбец `partition_id`. * В таблицу `system.part_log` добавлен столбец `partition_id`. [#3089](https://github.com/yandex/ClickHouse/pull/3089)
### Исправление ошибок: ### Исправление ошибок:
* Исправлена работа `Merge` таблицы поверх `Distributed` таблиц. [Winter Zhang]() * Исправлена работа `Merge` таблицы поверх `Distributed` таблиц. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3159)
* Исправлена несовместимость (лишняя зависимость от версии `glibc`), приводящая к невозможности запуска ClickHouse на `Ubuntu Precise` и более старых. Несовместимость возникла в версии 18.12.13. * Исправлена несовместимость (лишняя зависимость от версии `glibc`), приводящая к невозможности запуска ClickHouse на `Ubuntu Precise` и более старых. Несовместимость возникла в версии 18.12.13. [#3130](https://github.com/yandex/ClickHouse/pull/3130)
* Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang]() * Исправлены ошибки в работе настройки `enable_optimize_predicate_expression`. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3107)
* Исправлено незначительное нарушение обратной совместимости, проявляющееся при одновременной работе на кластере реплик версий до 18.12.13 и создании новой реплики таблицы на сервере более новой версии (выдаётся сообщение `Can not clone replica, because the ... updated to new ClickHouse version`, что полностью логично, но не должно было происходить). * Исправлено незначительное нарушение обратной совместимости, проявляющееся при одновременной работе на кластере реплик версий до 18.12.13 и создании новой реплики таблицы на сервере более новой версии (выдаётся сообщение `Can not clone replica, because the ... updated to new ClickHouse version`, что полностью логично, но не должно было происходить). [#3122](https://github.com/yandex/ClickHouse/pull/3122)
### Обратно несовместимые изменения: ### Обратно несовместимые изменения:
* Настройка `enable_optimize_predicate_expression` включена по-умолчанию, что конечно очень оптимистично. При возникновении ошибок анализа запроса, связанных с поиском имён столбцов, следует выставить `enable_optimize_predicate_expression` в 0. [Winter Zhang]() * Настройка `enable_optimize_predicate_expression` включена по-умолчанию, что конечно очень оптимистично. При возникновении ошибок анализа запроса, связанных с поиском имён столбцов, следует выставить `enable_optimize_predicate_expression` в 0. [Winter Zhang](https://github.com/yandex/ClickHouse/pull/3107)
## ClickHouse release 18.12.14, 2018-09-13 ## ClickHouse release 18.12.14, 2018-09-13

View File

@ -2,14 +2,11 @@
ClickHouse is an open-source column-oriented database management system that allows generating analytical data reports in real time. ClickHouse is an open-source column-oriented database management system that allows generating analytical data reports in real time.
🎤🥂 **ClickHouse Meetup in [Amsterdam on November 15](https://events.yandex.com/events/meetings/15-11-2018/)** 🍰🔥🐻
## Useful Links ## Useful Links
* [Official website](https://clickhouse.yandex/) has quick high-level overview of ClickHouse on main page. * [Official website](https://clickhouse.yandex/) has quick high-level overview of ClickHouse on main page.
* [Tutorial](https://clickhouse.yandex/tutorial.html) shows how to set up and query small ClickHouse cluster. * [Tutorial](https://clickhouse.yandex/tutorial.html) shows how to set up and query small ClickHouse cluster.
* [Documentation](https://clickhouse.yandex/docs/en/) provides more in-depth information. * [Documentation](https://clickhouse.yandex/docs/en/) provides more in-depth information.
* [Contacts](https://clickhouse.yandex/#contacts) can help to get your questions answered if there are any. * [Contacts](https://clickhouse.yandex/#contacts) can help to get your questions answered if there are any.
## Upcoming Meetups
* [Beijing on October 28](http://www.clickhouse.com.cn/topic/5ba0e3f99d28dfde2ddc62a1)
* [Amsterdam on November 15](https://events.yandex.com/events/meetings/15-11-2018/)

View File

@ -86,4 +86,4 @@ if (ENABLE_ODBC)
endif () endif ()
endif () endif ()
message (STATUS "Using odbc: ${ODBC_INCLUDE_DIRECTORIES} : ${ODBC_LIBRARIES}") message (STATUS "Using odbc=${ODBC_FOUND}: ${ODBC_INCLUDE_DIRECTORIES} : ${ODBC_LIBRARIES}")

View File

@ -116,10 +116,10 @@ endif ()
if (Poco_MongoDB_LIBRARY) if (Poco_MongoDB_LIBRARY)
set (USE_POCO_MONGODB 1) set (USE_POCO_MONGODB 1)
endif () endif ()
if (Poco_DataODBC_LIBRARY) if (Poco_DataODBC_LIBRARY AND ODBC_FOUND)
set (USE_POCO_DATAODBC 1) set (USE_POCO_DATAODBC 1)
endif () endif ()
if (Poco_SQLODBC_LIBRARY) if (Poco_SQLODBC_LIBRARY AND ODBC_FOUND)
set (USE_POCO_SQLODBC 1) set (USE_POCO_SQLODBC 1)
endif () endif ()

2
contrib/ssl vendored

@ -1 +1 @@
Subproject commit de02224a42c69e3d8c9112c82018816f821878d0 Subproject commit 919f6f1331d500bfdd26f8bbbf88e92c0119879b

View File

@ -6,18 +6,12 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/find_vectorclass.cmake)
set (CONFIG_VERSION ${CMAKE_CURRENT_BINARY_DIR}/src/Common/config_version.h) set (CONFIG_VERSION ${CMAKE_CURRENT_BINARY_DIR}/src/Common/config_version.h)
set (CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/src/Common/config.h) set (CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/src/Common/config.h)
set (CONFIG_BUILD ${CMAKE_CURRENT_BINARY_DIR}/src/Common/config_build.cpp)
include (cmake/version.cmake) include (cmake/version.cmake)
message (STATUS "Will build ${VERSION_FULL}") message (STATUS "Will build ${VERSION_FULL}")
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/Common/config.h.in ${CONFIG_COMMON}) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/Common/config.h.in ${CONFIG_COMMON})
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/Common/config_version.h.in ${CONFIG_VERSION}) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/Common/config_version.h.in ${CONFIG_VERSION})
get_property (BUILD_COMPILE_DEFINITIONS DIRECTORY ${ClickHouse_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
get_property (BUILD_INCLUDE_DIRECTORIES DIRECTORY ${ClickHouse_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
string (TIMESTAMP BUILD_DATE "%Y-%m-%d" UTC)
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/Common/config_build.cpp.in ${CONFIG_BUILD})
if (NOT MSVC) if (NOT MSVC)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
endif () endif ()

View File

@ -76,7 +76,8 @@ struct ConnectionParameters
timeouts = ConnectionTimeouts( timeouts = ConnectionTimeouts(
Poco::Timespan(config.getInt("connect_timeout", DBMS_DEFAULT_CONNECT_TIMEOUT_SEC), 0), Poco::Timespan(config.getInt("connect_timeout", DBMS_DEFAULT_CONNECT_TIMEOUT_SEC), 0),
Poco::Timespan(config.getInt("receive_timeout", DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC), 0), Poco::Timespan(config.getInt("receive_timeout", DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC), 0),
Poco::Timespan(config.getInt("send_timeout", DBMS_DEFAULT_SEND_TIMEOUT_SEC), 0)); Poco::Timespan(config.getInt("send_timeout", DBMS_DEFAULT_SEND_TIMEOUT_SEC), 0),
Poco::Timespan(config.getInt("tcp_keep_alive_timeout", 0), 0));
} }
}; };

View File

@ -63,6 +63,8 @@ namespace ErrorCodes
extern const int TOO_BIG_AST; extern const int TOO_BIG_AST;
extern const int UNEXPECTED_AST_STRUCTURE; extern const int UNEXPECTED_AST_STRUCTURE;
extern const int SYNTAX_ERROR;
extern const int UNKNOWN_TABLE; extern const int UNKNOWN_TABLE;
extern const int UNKNOWN_FUNCTION; extern const int UNKNOWN_FUNCTION;
extern const int UNKNOWN_IDENTIFIER; extern const int UNKNOWN_IDENTIFIER;
@ -109,6 +111,8 @@ static Poco::Net::HTTPResponse::HTTPStatus exceptionCodeToHTTPStatus(int excepti
exception_code == ErrorCodes::TOO_BIG_AST || exception_code == ErrorCodes::TOO_BIG_AST ||
exception_code == ErrorCodes::UNEXPECTED_AST_STRUCTURE) exception_code == ErrorCodes::UNEXPECTED_AST_STRUCTURE)
return HTTPResponse::HTTP_BAD_REQUEST; return HTTPResponse::HTTP_BAD_REQUEST;
else if (exception_code == ErrorCodes::SYNTAX_ERROR)
return HTTPResponse::HTTP_BAD_REQUEST;
else if (exception_code == ErrorCodes::UNKNOWN_TABLE || else if (exception_code == ErrorCodes::UNKNOWN_TABLE ||
exception_code == ErrorCodes::UNKNOWN_FUNCTION || exception_code == ErrorCodes::UNKNOWN_FUNCTION ||
exception_code == ErrorCodes::UNKNOWN_IDENTIFIER || exception_code == ErrorCodes::UNKNOWN_IDENTIFIER ||

View File

@ -121,6 +121,9 @@ void TCPHandler::runImpl()
while (1) while (1)
{ {
/// Restore context of request.
query_context = connection_context;
/// We are waiting for a packet from the client. Thus, every `POLL_INTERVAL` seconds check whether we need to shut down. /// We are waiting for a packet from the client. Thus, every `POLL_INTERVAL` seconds check whether we need to shut down.
while (!static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000) && !server.isCancelled()) while (!static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000) && !server.isCancelled())
; ;
@ -145,9 +148,6 @@ void TCPHandler::runImpl()
try try
{ {
/// Restore context of request.
query_context = connection_context;
/// If a user passed query-local timeouts, reset socket to initial state at the end of the query /// If a user passed query-local timeouts, reset socket to initial state at the end of the query
SCOPE_EXIT({state.timeout_setter.reset();}); SCOPE_EXIT({state.timeout_setter.reset();});

View File

@ -1,6 +1,5 @@
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h> #include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <TableFunctions/ITableFunction.h> #include <TableFunctions/ITableFunction.h>
#include <TableFunctions/TableFunctionFactory.h> #include <TableFunctions/TableFunctionFactory.h>

View File

@ -77,6 +77,17 @@ void Connection::connect()
socket->setReceiveTimeout(timeouts.receive_timeout); socket->setReceiveTimeout(timeouts.receive_timeout);
socket->setSendTimeout(timeouts.send_timeout); socket->setSendTimeout(timeouts.send_timeout);
socket->setNoDelay(true); socket->setNoDelay(true);
if (timeouts.tcp_keep_alive_timeout.totalSeconds())
{
socket->setKeepAlive(true);
socket->setOption(IPPROTO_TCP,
#if defined(TCP_KEEPALIVE)
TCP_KEEPALIVE
#else
TCP_KEEPIDLE // __APPLE__
#endif
, timeouts.tcp_keep_alive_timeout);
}
in = std::make_shared<ReadBufferFromPocoSocket>(*socket); in = std::make_shared<ReadBufferFromPocoSocket>(*socket);
out = std::make_shared<WriteBufferFromPocoSocket>(*socket); out = std::make_shared<WriteBufferFromPocoSocket>(*socket);

View File

@ -462,6 +462,8 @@ XMLDocumentPtr ConfigProcessor::processConfig(
std::string include_from_path; std::string include_from_path;
if (node) if (node)
{ {
/// if we include_from env or zk.
doIncludesRecursive(config, nullptr, node, zk_node_cache, contributing_zk_paths);
include_from_path = node->innerText(); include_from_path = node->innerText();
} }
else else

View File

@ -1,4 +0,0 @@
#pragma once
#include <vector>
extern const char * auto_config_build[];

View File

@ -33,9 +33,6 @@ RemoteBlockOutputStream::RemoteBlockOutputStream(Connection & connection_, const
if (Protocol::Server::Data == packet.type) if (Protocol::Server::Data == packet.type)
{ {
header = packet.block; header = packet.block;
if (!header)
throw Exception("Logical error: empty block received as table structure", ErrorCodes::LOGICAL_ERROR);
break; break;
} }
else if (Protocol::Server::Exception == packet.type) else if (Protocol::Server::Exception == packet.type)
@ -58,7 +55,8 @@ RemoteBlockOutputStream::RemoteBlockOutputStream(Connection & connection_, const
void RemoteBlockOutputStream::write(const Block & block) void RemoteBlockOutputStream::write(const Block & block)
{ {
assertBlocksHaveEqualStructure(block, header, "RemoteBlockOutputStream"); if (header)
assertBlocksHaveEqualStructure(block, header, "RemoteBlockOutputStream");
try try
{ {

View File

@ -156,7 +156,7 @@ DictionarySourcePtr DictionarySourceFactory::create(
{ {
#if USE_POCO_SQLODBC || USE_POCO_DATAODBC #if USE_POCO_SQLODBC || USE_POCO_DATAODBC
const auto & global_config = context.getConfigRef(); const auto & global_config = context.getConfigRef();
BridgeHelperPtr bridge = std::make_shared<XDBCBridgeHelper<ODBCBridgeMixin>>(global_config, context.getSettings().http_connection_timeout, config.getString(config_prefix + ".odbc.connection_string")); BridgeHelperPtr bridge = std::make_shared<XDBCBridgeHelper<ODBCBridgeMixin>>(global_config, context.getSettings().http_receive_timeout, config.getString(config_prefix + ".odbc.connection_string"));
return std::make_unique<XDBCDictionarySource>(dict_struct, config, config_prefix + ".odbc", sample_block, context, bridge); return std::make_unique<XDBCDictionarySource>(dict_struct, config, config_prefix + ".odbc", sample_block, context, bridge);
#else #else
throw Exception{"Dictionary source of type `odbc` is disabled because poco library was built without ODBC support.", throw Exception{"Dictionary source of type `odbc` is disabled because poco library was built without ODBC support.",
@ -167,7 +167,7 @@ DictionarySourcePtr DictionarySourceFactory::create(
{ {
throw Exception{"Dictionary source of type `jdbc` is disabled until consistent support for nullable fields.", throw Exception{"Dictionary source of type `jdbc` is disabled until consistent support for nullable fields.",
ErrorCodes::SUPPORT_IS_DISABLED}; ErrorCodes::SUPPORT_IS_DISABLED};
// BridgeHelperPtr bridge = std::make_shared<XDBCBridgeHelper<JDBCBridgeMixin>>(config, context.getSettings().http_connection_timeout, config.getString(config_prefix + ".connection_string")); // BridgeHelperPtr bridge = std::make_shared<XDBCBridgeHelper<JDBCBridgeMixin>>(config, context.getSettings().http_receive_timeout, config.getString(config_prefix + ".connection_string"));
// return std::make_unique<XDBCDictionarySource>(dict_struct, config, config_prefix + ".jdbc", sample_block, context, bridge); // return std::make_unique<XDBCDictionarySource>(dict_struct, config, config_prefix + ".jdbc", sample_block, context, bridge);
} }
else if ("executable" == source_type) else if ("executable" == source_type)

View File

@ -2,6 +2,7 @@
#include <Interpreters/evaluateConstantExpression.h> #include <Interpreters/evaluateConstantExpression.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/convertFieldToType.h> #include <Interpreters/convertFieldToType.h>
#include <DataTypes/DataTypeArray.h>
#include <Parsers/TokenIterator.h> #include <Parsers/TokenIterator.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Formats/ValuesRowInputStream.h> #include <Formats/ValuesRowInputStream.h>
@ -29,6 +30,20 @@ namespace ErrorCodes
} }
bool is_array_type_compatible(const DataTypeArray & type, const Field & value)
{
if (type.getNestedType()->isNullable())
return true;
const Array & array = DB::get<const Array &>(value);
size_t size = array.size();
for (size_t i = 0; i < size; ++i)
if (array[i].isNull())
return false;
return true;
}
ValuesRowInputStream::ValuesRowInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_, const FormatSettings & format_settings) ValuesRowInputStream::ValuesRowInputStream(ReadBuffer & istr_, const Block & header_, const Context & context_, const FormatSettings & format_settings)
: istr(istr_), header(header_), context(std::make_unique<Context>(context_)), format_settings(format_settings) : istr(istr_), header(header_), context(std::make_unique<Context>(context_)), format_settings(format_settings)
{ {
@ -116,14 +131,15 @@ bool ValuesRowInputStream::read(MutableColumns & columns)
std::pair<Field, DataTypePtr> value_raw = evaluateConstantExpression(ast, *context); std::pair<Field, DataTypePtr> value_raw = evaluateConstantExpression(ast, *context);
Field value = convertFieldToType(value_raw.first, type, value_raw.second.get()); Field value = convertFieldToType(value_raw.first, type, value_raw.second.get());
if (value.isNull()) const auto * array_type = typeid_cast<const DataTypeArray *>(&type);
/// Check that we are indeed allowed to insert a NULL.
if ((value.isNull() && !type.isNullable()) || (array_type && !is_array_type_compatible(*array_type, value)))
{ {
/// Check that we are indeed allowed to insert a NULL. throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value)
if (!type.isNullable()) + ", that is out of range of type " + type.getName()
throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value) + ", at: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)),
+ ", that is out of range of type " + type.getName() ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE};
+ ", at: " + String(prev_istr_position, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, istr.buffer().end() - prev_istr_position)),
ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE};
} }
columns[i]->insert(value); columns[i]->insert(value);

View File

@ -784,6 +784,9 @@ public:
} }
else if constexpr (to_decimal) else if constexpr (to_decimal)
{ {
if (!arguments[1].column)
throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
UInt64 scale = extractToDecimalScale(arguments[1]); UInt64 scale = extractToDecimalScale(arguments[1]);
if constexpr (std::is_same_v<Name, NameToDecimal32>) if constexpr (std::is_same_v<Name, NameToDecimal32>)

View File

@ -288,7 +288,10 @@ bool PreparedFunctionImpl::defaultImplementationForConstantArguments(Block & blo
const ColumnWithTypeAndName & column = block.getByPosition(args[arg_num]); const ColumnWithTypeAndName & column = block.getByPosition(args[arg_num]);
if (arguments_to_remain_constants.end() != std::find(arguments_to_remain_constants.begin(), arguments_to_remain_constants.end(), arg_num)) if (arguments_to_remain_constants.end() != std::find(arguments_to_remain_constants.begin(), arguments_to_remain_constants.end(), arg_num))
temporary_block.insert(column); if (column.column->empty())
temporary_block.insert({column.column->cloneResized(1), column.type, column.name});
else
temporary_block.insert(column);
else else
{ {
have_converted_columns = true; have_converted_columns = true;
@ -311,7 +314,15 @@ bool PreparedFunctionImpl::defaultImplementationForConstantArguments(Block & blo
executeWithoutLowCardinalityColumns(temporary_block, temporary_argument_numbers, arguments_size, temporary_block.rows()); executeWithoutLowCardinalityColumns(temporary_block, temporary_argument_numbers, arguments_size, temporary_block.rows());
block.getByPosition(result).column = ColumnConst::create(temporary_block.getByPosition(arguments_size).column, input_rows_count); ColumnPtr result_column;
/// extremely rare case, when we have function with completely const arguments
/// but some of them produced by non isDeterministic function
if (temporary_block.getByPosition(arguments_size).column->size() > 1)
result_column = temporary_block.getByPosition(arguments_size).column->cloneResized(1);
else
result_column = temporary_block.getByPosition(arguments_size).column;
block.getByPosition(result).column = ColumnConst::create(result_column, input_rows_count);
return true; return true;
} }

View File

@ -11,6 +11,7 @@ struct ConnectionTimeouts
Poco::Timespan connection_timeout; Poco::Timespan connection_timeout;
Poco::Timespan send_timeout; Poco::Timespan send_timeout;
Poco::Timespan receive_timeout; Poco::Timespan receive_timeout;
Poco::Timespan tcp_keep_alive_timeout;
ConnectionTimeouts() = default; ConnectionTimeouts() = default;
@ -19,7 +20,19 @@ struct ConnectionTimeouts
const Poco::Timespan & receive_timeout_) const Poco::Timespan & receive_timeout_)
: connection_timeout(connection_timeout_), : connection_timeout(connection_timeout_),
send_timeout(send_timeout_), send_timeout(send_timeout_),
receive_timeout(receive_timeout_) receive_timeout(receive_timeout_),
tcp_keep_alive_timeout(0)
{
}
ConnectionTimeouts(const Poco::Timespan & connection_timeout_,
const Poco::Timespan & send_timeout_,
const Poco::Timespan & receive_timeout_,
const Poco::Timespan & tcp_keep_alive_timeout_)
: connection_timeout(connection_timeout_),
send_timeout(send_timeout_),
receive_timeout(receive_timeout_),
tcp_keep_alive_timeout(tcp_keep_alive_timeout_)
{ {
} }
@ -35,19 +48,20 @@ struct ConnectionTimeouts
{ {
return ConnectionTimeouts(saturate(connection_timeout, limit), return ConnectionTimeouts(saturate(connection_timeout, limit),
saturate(send_timeout, limit), saturate(send_timeout, limit),
saturate(receive_timeout, limit)); saturate(receive_timeout, limit),
saturate(tcp_keep_alive_timeout, limit));
} }
/// Timeouts for the case when we have just single attempt to connect. /// Timeouts for the case when we have just single attempt to connect.
static ConnectionTimeouts getTCPTimeoutsWithoutFailover(const Settings & settings) static ConnectionTimeouts getTCPTimeoutsWithoutFailover(const Settings & settings)
{ {
return ConnectionTimeouts(settings.connect_timeout, settings.send_timeout, settings.receive_timeout); return ConnectionTimeouts(settings.connect_timeout, settings.send_timeout, settings.receive_timeout, settings.tcp_keep_alive_timeout);
} }
/// Timeouts for the case when we will try many addresses in a loop. /// Timeouts for the case when we will try many addresses in a loop.
static ConnectionTimeouts getTCPTimeoutsWithFailover(const Settings & settings) static ConnectionTimeouts getTCPTimeoutsWithFailover(const Settings & settings)
{ {
return ConnectionTimeouts(settings.connect_timeout_with_failover_ms, settings.send_timeout, settings.receive_timeout); return ConnectionTimeouts(settings.connect_timeout_with_failover_ms, settings.send_timeout, settings.receive_timeout, settings.tcp_keep_alive_timeout);
} }
static ConnectionTimeouts getHTTPTimeouts(const Settings & settings) static ConnectionTimeouts getHTTPTimeouts(const Settings & settings)

View File

@ -568,8 +568,8 @@ void ActionsVisitor::makeSet(const ASTFunction * node, const Block & sample_bloc
/// and the table has the type Set (a previously prepared set). /// and the table has the type Set (a previously prepared set).
if (identifier) if (identifier)
{ {
auto database_table = getDatabaseAndTableNameFromIdentifier(*identifier); DatabaseAndTableWithAlias database_table(*identifier);
StoragePtr table = context.tryGetTable(database_table.first, database_table.second); StoragePtr table = context.tryGetTable(database_table.database, database_table.table);
if (table) if (table)
{ {

View File

@ -0,0 +1,64 @@
#pragma once
#include <Parsers/ASTQueryWithTableAndOutput.h>
#include <Parsers/ASTRenameQuery.h>
namespace DB
{
/// Visits AST nodes, add default database to DDLs if not set.
class AddDefaultDatabaseVisitor
{
public:
AddDefaultDatabaseVisitor(const String & default_database_)
: default_database(default_database_)
{}
void visit(ASTPtr & ast) const
{
visitChildren(ast);
if (!tryVisit<ASTQueryWithTableAndOutput>(ast) &&
!tryVisit<ASTRenameQuery>(ast))
{}
}
private:
const String default_database;
void visit(ASTQueryWithTableAndOutput * node, ASTPtr &) const
{
if (node->database.empty())
node->database = default_database;
}
void visit(ASTRenameQuery * node, ASTPtr &) const
{
for (ASTRenameQuery::Element & elem : node->elements)
{
if (elem.from.database.empty())
elem.from.database = default_database;
if (elem.to.database.empty())
elem.to.database = default_database;
}
}
void visitChildren(ASTPtr & ast) const
{
for (auto & child : ast->children)
visit(child);
}
template <typename T>
bool tryVisit(ASTPtr & ast) const
{
if (T * t = dynamic_cast<T *>(ast.get()))
{
visit(t, ast);
return true;
}
return false;
}
};
}

View File

@ -12,6 +12,7 @@
#include <DataStreams/IProfilingBlockInputStream.h> #include <DataStreams/IProfilingBlockInputStream.h>
#include <Interpreters/executeQuery.h> #include <Interpreters/executeQuery.h>
#include <Interpreters/Cluster.h> #include <Interpreters/Cluster.h>
#include <Interpreters/AddDefaultDatabaseVisitor.h>
#include <Common/DNSResolver.h> #include <Common/DNSResolver.h>
#include <Common/Macros.h> #include <Common/Macros.h>
#include <Common/getFQDNOrHostName.h> #include <Common/getFQDNOrHostName.h>
@ -39,6 +40,7 @@ namespace DB
namespace ErrorCodes namespace ErrorCodes
{ {
extern const int LOGICAL_ERROR;
extern const int UNKNOWN_ELEMENT_IN_CONFIG; extern const int UNKNOWN_ELEMENT_IN_CONFIG;
extern const int INVALID_CONFIG_PARAMETER; extern const int INVALID_CONFIG_PARAMETER;
extern const int UNKNOWN_FORMAT_VERSION; extern const int UNKNOWN_FORMAT_VERSION;
@ -1135,7 +1137,7 @@ private:
}; };
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & context, const NameSet & query_databases) BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & context, NameSet && query_databases)
{ {
/// Remove FORMAT <fmt> and INTO OUTFILE <file> if exists /// Remove FORMAT <fmt> and INTO OUTFILE <file> if exists
ASTPtr query_ptr = query_ptr_->clone(); ASTPtr query_ptr = query_ptr_->clone();
@ -1163,30 +1165,56 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont
ClusterPtr cluster = context.getCluster(query->cluster); ClusterPtr cluster = context.getCluster(query->cluster);
DDLWorker & ddl_worker = context.getDDLWorker(); DDLWorker & ddl_worker = context.getDDLWorker();
DDLLogEntry entry;
entry.query = queryToString(query_ptr);
entry.initiator = ddl_worker.getCommonHostID();
/// Check database access rights, assume that all servers have the same users config /// Check database access rights, assume that all servers have the same users config
NameSet databases_to_check_access_rights; NameSet databases_to_access;
const String & current_database = context.getCurrentDatabase();
Cluster::AddressesWithFailover shards = cluster->getShardsAddresses(); Cluster::AddressesWithFailover shards = cluster->getShardsAddresses();
std::vector<HostID> hosts;
bool use_shard_default_db = false;
bool use_local_default_db = false;
for (const auto & shard : shards) for (const auto & shard : shards)
{ {
for (const auto & addr : shard) for (const auto & addr : shard)
{ {
entry.hosts.emplace_back(addr); hosts.emplace_back(addr);
/// Expand empty database name to shards' default database name /// Expand empty database name to shards' default (o current) database name
for (const String & database : query_databases) for (const String & database : query_databases)
databases_to_check_access_rights.emplace(database.empty() ? addr.default_database : database); {
if (database.empty())
{
bool has_shard_default_db = !addr.default_database.empty();
use_shard_default_db |= has_shard_default_db;
use_local_default_db |= !has_shard_default_db;
databases_to_access.emplace(has_shard_default_db ? addr.default_database : current_database );
}
else
databases_to_access.emplace(database);
}
} }
} }
for (const String & database : databases_to_check_access_rights) if (use_shard_default_db && use_local_default_db)
context.checkDatabaseAccessRights(database.empty() ? context.getCurrentDatabase() : database); throw Exception("Mixed local default DB and shard default DB in DDL query", ErrorCodes::NOT_IMPLEMENTED);
if (databases_to_access.empty())
throw Exception("No databases to access in distributed DDL query", ErrorCodes::LOGICAL_ERROR);
for (const String & database : databases_to_access)
context.checkDatabaseAccessRights(database);
if (use_local_default_db)
{
AddDefaultDatabaseVisitor visitor(current_database);
visitor.visit(query_ptr);
}
DDLLogEntry entry;
entry.hosts = std::move(hosts);
entry.query = queryToString(query_ptr);
entry.initiator = ddl_worker.getCommonHostID();
String node_path = ddl_worker.enqueueQuery(entry); String node_path = ddl_worker.enqueueQuery(entry);
BlockIO io; BlockIO io;

View File

@ -20,7 +20,7 @@ struct DDLTask;
/// Pushes distributed DDL query to the queue /// Pushes distributed DDL query to the queue
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context, const NameSet & query_databases); BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context, NameSet && query_databases);
class DDLWorker class DDLWorker

View File

@ -0,0 +1,245 @@
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Interpreters/Context.h>
#include <Common/typeid_cast.h>
#include <Parsers/IAST.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTSubquery.h>
namespace DB
{
/// Checks that ast is ASTIdentifier and remove num_qualifiers_to_strip components from left.
/// Example: 'database.table.name' -> (num_qualifiers_to_strip = 2) -> 'name'.
void stripIdentifier(DB::ASTPtr & ast, size_t num_qualifiers_to_strip)
{
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(ast.get());
if (!identifier)
throw DB::Exception("ASTIdentifier expected for stripIdentifier", DB::ErrorCodes::LOGICAL_ERROR);
if (num_qualifiers_to_strip)
{
size_t num_components = identifier->children.size();
/// plain column
if (num_components - num_qualifiers_to_strip == 1)
{
DB::String node_alias = identifier->tryGetAlias();
ast = identifier->children.back();
if (!node_alias.empty())
ast->setAlias(node_alias);
}
else
/// nested column
{
identifier->children.erase(identifier->children.begin(), identifier->children.begin() + num_qualifiers_to_strip);
DB::String new_name;
for (const auto & child : identifier->children)
{
if (!new_name.empty())
new_name += '.';
new_name += static_cast<const ASTIdentifier &>(*child.get()).name;
}
identifier->name = new_name;
}
}
}
/// Get the number of components of identifier which are correspond to 'alias.', 'table.' or 'databas.table.' from names.
size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier,
const DatabaseAndTableWithAlias & names)
{
size_t num_qualifiers_to_strip = 0;
auto get_identifier_name = [](const ASTPtr & ast) { return static_cast<const ASTIdentifier &>(*ast).name; };
/// It is compound identifier
if (!identifier.children.empty())
{
size_t num_components = identifier.children.size();
/// database.table.column
if (num_components >= 3
&& !names.database.empty()
&& get_identifier_name(identifier.children[0]) == names.database
&& get_identifier_name(identifier.children[1]) == names.table)
{
num_qualifiers_to_strip = 2;
}
/// table.column or alias.column. If num_components > 2, it is like table.nested.column.
if (num_components >= 2
&& ((!names.table.empty() && get_identifier_name(identifier.children[0]) == names.table)
|| (!names.alias.empty() && get_identifier_name(identifier.children[0]) == names.alias)))
{
num_qualifiers_to_strip = 1;
}
}
return num_qualifiers_to_strip;
}
DatabaseAndTableWithAlias::DatabaseAndTableWithAlias(const ASTIdentifier & identifier, const String & current_database)
{
database = current_database;
table = identifier.name;
alias = identifier.tryGetAlias();
if (!identifier.children.empty())
{
if (identifier.children.size() != 2)
throw Exception("Logical error: number of components in table expression not equal to two", ErrorCodes::LOGICAL_ERROR);
const ASTIdentifier * db_identifier = typeid_cast<const ASTIdentifier *>(identifier.children[0].get());
const ASTIdentifier * table_identifier = typeid_cast<const ASTIdentifier *>(identifier.children[1].get());
if (!db_identifier || !table_identifier)
throw Exception("Logical error: identifiers expected", ErrorCodes::LOGICAL_ERROR);
database = db_identifier->name;
table = table_identifier->name;
}
}
DatabaseAndTableWithAlias::DatabaseAndTableWithAlias(const ASTTableExpression & table_expression, const String & current_database)
{
if (table_expression.database_and_table_name)
{
const auto * identifier = typeid_cast<const ASTIdentifier *>(table_expression.database_and_table_name.get());
if (!identifier)
throw Exception("Logical error: identifier expected", ErrorCodes::LOGICAL_ERROR);
*this = DatabaseAndTableWithAlias(*identifier, current_database);
}
else if (table_expression.table_function)
alias = table_expression.table_function->tryGetAlias();
else if (table_expression.subquery)
alias = table_expression.subquery->tryGetAlias();
else
throw Exception("Logical error: no known elements in ASTTableExpression", ErrorCodes::LOGICAL_ERROR);
}
String DatabaseAndTableWithAlias::getQualifiedNamePrefix() const
{
if (alias.empty() && table.empty())
return "";
return (!alias.empty() ? alias : (database + '.' + table)) + '.';
}
void DatabaseAndTableWithAlias::makeQualifiedName(const ASTPtr & ast) const
{
if (auto identifier = typeid_cast<ASTIdentifier *>(ast.get()))
{
String prefix = getQualifiedNamePrefix();
identifier->name.insert(identifier->name.begin(), prefix.begin(), prefix.end());
Names qualifiers;
if (!alias.empty())
qualifiers.push_back(alias);
else
{
qualifiers.push_back(database);
qualifiers.push_back(table);
}
for (const auto & qualifier : qualifiers)
identifier->children.emplace_back(std::make_shared<ASTIdentifier>(qualifier));
}
}
std::vector<const ASTTableExpression *> getSelectTablesExpression(const ASTSelectQuery & select_query)
{
if (!select_query.tables)
return {};
std::vector<const ASTTableExpression *> tables_expression;
for (const auto & child : select_query.tables->children)
{
ASTTablesInSelectQueryElement * tables_element = static_cast<ASTTablesInSelectQueryElement *>(child.get());
if (tables_element->table_expression)
tables_expression.emplace_back(static_cast<const ASTTableExpression *>(tables_element->table_expression.get()));
}
return tables_expression;
}
static const ASTTableExpression * getTableExpression(const ASTSelectQuery & select, size_t table_number)
{
if (!select.tables)
return {};
ASTTablesInSelectQuery & tables_in_select_query = static_cast<ASTTablesInSelectQuery &>(*select.tables);
if (tables_in_select_query.children.size() <= table_number)
return {};
ASTTablesInSelectQueryElement & tables_element =
static_cast<ASTTablesInSelectQueryElement &>(*tables_in_select_query.children[table_number]);
if (!tables_element.table_expression)
return {};
return static_cast<const ASTTableExpression *>(tables_element.table_expression.get());
}
std::vector<DatabaseAndTableWithAlias> getDatabaseAndTables(const ASTSelectQuery & select_query, const String & current_database)
{
std::vector<const ASTTableExpression *> tables_expression = getSelectTablesExpression(select_query);
std::vector<DatabaseAndTableWithAlias> database_and_table_with_aliases;
database_and_table_with_aliases.reserve(tables_expression.size());
for (const auto & table_expression : tables_expression)
database_and_table_with_aliases.emplace_back(DatabaseAndTableWithAlias(*table_expression, current_database));
return database_and_table_with_aliases;
}
std::optional<DatabaseAndTableWithAlias> getDatabaseAndTable(const ASTSelectQuery & select, size_t table_number)
{
const ASTTableExpression * table_expression = getTableExpression(select, table_number);
if (!table_expression)
return {};
ASTPtr database_and_table_name = table_expression->database_and_table_name;
if (!database_and_table_name)
return {};
const ASTIdentifier * identifier = typeid_cast<const ASTIdentifier *>(database_and_table_name.get());
if (!identifier)
return {};
return *identifier;
}
ASTPtr getTableFunctionOrSubquery(const ASTSelectQuery & select, size_t table_number)
{
const ASTTableExpression * table_expression = getTableExpression(select, table_number);
if (table_expression)
{
#if 1 /// TODO: It hides some logical error in InterpreterSelectQuery & distributed tables
if (table_expression->database_and_table_name)
{
if (table_expression->database_and_table_name->children.empty())
return table_expression->database_and_table_name;
if (table_expression->database_and_table_name->children.size() == 2)
return table_expression->database_and_table_name->children[1];
}
#endif
if (table_expression->table_function)
return table_expression->table_function;
if (table_expression->subquery)
return static_cast<const ASTSubquery *>(table_expression->subquery.get())->children[0];
}
return nullptr;
}
}

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <Core/Types.h> #include <Core/Types.h>
namespace DB namespace DB
@ -9,16 +10,21 @@ namespace DB
class IAST; class IAST;
using ASTPtr = std::shared_ptr<IAST>; using ASTPtr = std::shared_ptr<IAST>;
class ASTSelectQuery;
class ASTIdentifier; class ASTIdentifier;
struct ASTTableExpression; struct ASTTableExpression;
/// Extracts database name (and/or alias) from table expression or identifier
struct DatabaseAndTableWithAlias struct DatabaseAndTableWithAlias
{ {
String database; String database;
String table; String table;
String alias; String alias;
DatabaseAndTableWithAlias(const ASTIdentifier & identifier, const String & current_database = "");
DatabaseAndTableWithAlias(const ASTTableExpression & table_expression, const String & current_database);
/// "alias." or "database.table." if alias is empty /// "alias." or "database.table." if alias is empty
String getQualifiedNamePrefix() const; String getQualifiedNamePrefix() const;
@ -28,12 +34,13 @@ struct DatabaseAndTableWithAlias
void stripIdentifier(DB::ASTPtr & ast, size_t num_qualifiers_to_strip); void stripIdentifier(DB::ASTPtr & ast, size_t num_qualifiers_to_strip);
DatabaseAndTableWithAlias getTableNameWithAliasFromTableExpression(const ASTTableExpression & table_expression,
const String & current_database);
size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier, size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier,
const DatabaseAndTableWithAlias & names); const DatabaseAndTableWithAlias & names);
std::pair<String, String> getDatabaseAndTableNameFromIdentifier(const ASTIdentifier & identifier); std::vector<DatabaseAndTableWithAlias> getDatabaseAndTables(const ASTSelectQuery & select_query, const String & current_database);
std::optional<DatabaseAndTableWithAlias> getDatabaseAndTable(const ASTSelectQuery & select, size_t table_number);
std::vector<const ASTTableExpression *> getSelectTablesExpression(const ASTSelectQuery & select_query);
ASTPtr getTableFunctionOrSubquery(const ASTSelectQuery & select, size_t table_number);
} }

View File

@ -206,8 +206,14 @@ void ExpressionAction::prepare(Block & sample_block, const Settings & settings)
if (auto * prepared_function = dynamic_cast<PreparedFunctionImpl *>(function.get())) if (auto * prepared_function = dynamic_cast<PreparedFunctionImpl *>(function.get()))
prepared_function->createLowCardinalityResultCache(settings.max_threads); prepared_function->createLowCardinalityResultCache(settings.max_threads);
bool compile_expressions = false;
#if USE_EMBEDDED_COMPILER
compile_expressions = settings.compile_expressions;
#endif
/// If all arguments are constants, and function is suitable to be executed in 'prepare' stage - execute function. /// If all arguments are constants, and function is suitable to be executed in 'prepare' stage - execute function.
if (all_const && function_base->isSuitableForConstantFolding()) /// But if we compile expressions compiled version of this function maybe placed in cache,
/// so we don't want to unfold non deterministic functions
if (all_const && function_base->isSuitableForConstantFolding() && (!compile_expressions || function_base->isDeterministic()))
{ {
function->execute(sample_block, arguments, result_position, sample_block.rows()); function->execute(sample_block, arguments, result_position, sample_block.rows());
@ -671,7 +677,8 @@ void ExpressionActions::addImpl(ExpressionAction action, Names & new_names)
new_names.push_back(action.result_name); new_names.push_back(action.result_name);
new_names.insert(new_names.end(), action.array_joined_columns.begin(), action.array_joined_columns.end()); new_names.insert(new_names.end(), action.array_joined_columns.begin(), action.array_joined_columns.end());
if (action.type == ExpressionAction::APPLY_FUNCTION) /// Compiled functions are custom functions and them don't need building
if (action.type == ExpressionAction::APPLY_FUNCTION && !action.is_function_compiled)
{ {
if (sample_block.has(action.result_name)) if (sample_block.has(action.result_name))
throw Exception("Column '" + action.result_name + "' already exists", ErrorCodes::DUPLICATE_COLUMN); throw Exception("Column '" + action.result_name + "' already exists", ErrorCodes::DUPLICATE_COLUMN);

View File

@ -59,7 +59,7 @@
#include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
#include <Parsers/queryToString.h> #include <Parsers/queryToString.h>
#include <Interpreters/interpretSubquery.h> #include <Interpreters/interpretSubquery.h>
#include <Interpreters/evaluateQualified.h> #include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Interpreters/QueryNormalizer.h> #include <Interpreters/QueryNormalizer.h>
#include <Interpreters/QueryAliasesVisitor.h> #include <Interpreters/QueryAliasesVisitor.h>
@ -172,36 +172,26 @@ ExpressionAnalyzer::ExpressionAnalyzer(
if (!storage && select_query) if (!storage && select_query)
{ {
auto select_database = select_query->database(); if (auto db_and_table = getDatabaseAndTable(*select_query, 0))
auto select_table = select_query->table(); storage = context.tryGetTable(db_and_table->database, db_and_table->table);
if (select_table
&& !typeid_cast<const ASTSelectWithUnionQuery *>(select_table.get())
&& !typeid_cast<const ASTFunction *>(select_table.get()))
{
String database = select_database
? typeid_cast<const ASTIdentifier &>(*select_database).name
: "";
const String & table = typeid_cast<const ASTIdentifier &>(*select_table).name;
storage = context.tryGetTable(database, table);
}
} }
if (storage && source_columns.empty()) if (storage)
{ {
auto physical_columns = storage->getColumns().getAllPhysical(); auto physical_columns = storage->getColumns().getAllPhysical();
if (source_columns.empty()) if (source_columns.empty())
source_columns.swap(physical_columns); source_columns.swap(physical_columns);
else else
{
source_columns.insert(source_columns.end(), physical_columns.begin(), physical_columns.end()); source_columns.insert(source_columns.end(), physical_columns.begin(), physical_columns.end());
removeDuplicateColumns(source_columns);
if (select_query)
{
const auto & storage_aliases = storage->getColumns().aliases;
source_columns.insert(source_columns.end(), storage_aliases.begin(), storage_aliases.end());
} }
} }
else
removeDuplicateColumns(source_columns);
addAliasColumns(); removeDuplicateColumns(source_columns);
translateQualifiedNames(); translateQualifiedNames();
@ -275,55 +265,14 @@ bool ExpressionAnalyzer::isRemoteStorage() const
} }
static std::vector<ASTTableExpression> getTableExpressions(const ASTPtr & query)
{
ASTSelectQuery * select_query = typeid_cast<ASTSelectQuery *>(query.get());
std::vector<ASTTableExpression> table_expressions;
if (select_query && select_query->tables)
{
for (const auto & element : select_query->tables->children)
{
ASTTablesInSelectQueryElement & select_element = static_cast<ASTTablesInSelectQueryElement &>(*element);
if (select_element.table_expression)
table_expressions.emplace_back(static_cast<ASTTableExpression &>(*select_element.table_expression));
}
}
return table_expressions;
}
void ExpressionAnalyzer::translateQualifiedNames() void ExpressionAnalyzer::translateQualifiedNames()
{ {
if (!select_query || !select_query->tables || select_query->tables->children.empty()) if (!select_query || !select_query->tables || select_query->tables->children.empty())
return; return;
std::vector<DatabaseAndTableWithAlias> tables; std::vector<DatabaseAndTableWithAlias> tables = getDatabaseAndTables(*select_query, context.getCurrentDatabase());
std::vector<ASTTableExpression> tables_expression = getTableExpressions(query);
LogAST log; LogAST log;
for (const auto & table_expression : tables_expression)
{
auto table = getTableNameWithAliasFromTableExpression(table_expression, context.getCurrentDatabase());
{ /// debug print
size_t depth = 0;
DumpASTNode dump(table_expression, log.stream(), depth, "getTableNames");
if (table_expression.database_and_table_name)
DumpASTNode(*table_expression.database_and_table_name, log.stream(), depth);
if (table_expression.table_function)
DumpASTNode(*table_expression.table_function, log.stream(), depth);
if (table_expression.subquery)
DumpASTNode(*table_expression.subquery, log.stream(), depth);
dump.print("getTableNameWithAlias", table.database + '.' + table.table + ' ' + table.alias);
}
tables.emplace_back(table);
}
TranslateQualifiedNamesVisitor visitor(source_columns, tables, log.stream()); TranslateQualifiedNamesVisitor visitor(source_columns, tables, log.stream());
visitor.visit(query); visitor.visit(query);
} }
@ -574,8 +523,8 @@ static NamesAndTypesList getNamesAndTypeListFromTableExpression(const ASTTableEx
else if (table_expression.database_and_table_name) else if (table_expression.database_and_table_name)
{ {
const auto & identifier = static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name); const auto & identifier = static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name);
auto database_table = getDatabaseAndTableNameFromIdentifier(identifier); DatabaseAndTableWithAlias database_table(identifier);
const auto & table = context.getTable(database_table.first, database_table.second); const auto & table = context.getTable(database_table.database, database_table.table);
names_and_type_list = table->getSampleBlockNonMaterialized().getNamesAndTypesList(); names_and_type_list = table->getSampleBlockNonMaterialized().getNamesAndTypesList();
} }
@ -602,13 +551,13 @@ void ExpressionAnalyzer::normalizeTree()
TableNamesAndColumnNames table_names_and_column_names; TableNamesAndColumnNames table_names_and_column_names;
if (select_query && select_query->tables && !select_query->tables->children.empty()) if (select_query && select_query->tables && !select_query->tables->children.empty())
{ {
std::vector<ASTTableExpression> tables_expression = getTableExpressions(query); std::vector<const ASTTableExpression *> tables_expression = getSelectTablesExpression(*select_query);
bool first = true; bool first = true;
for (const auto & table_expression : tables_expression) for (const auto * table_expression : tables_expression)
{ {
const auto table_name = getTableNameWithAliasFromTableExpression(table_expression, context.getCurrentDatabase()); DatabaseAndTableWithAlias table_name(*table_expression, context.getCurrentDatabase());
NamesAndTypesList names_and_types = getNamesAndTypeListFromTableExpression(table_expression, context); NamesAndTypesList names_and_types = getNamesAndTypeListFromTableExpression(*table_expression, context);
if (!first) if (!first)
{ {
@ -628,19 +577,6 @@ void ExpressionAnalyzer::normalizeTree()
} }
void ExpressionAnalyzer::addAliasColumns()
{
if (!select_query)
return;
if (!storage)
return;
const auto & storage_aliases = storage->getColumns().aliases;
source_columns.insert(std::end(source_columns), std::begin(storage_aliases), std::end(storage_aliases));
}
void ExpressionAnalyzer::executeScalarSubqueries() void ExpressionAnalyzer::executeScalarSubqueries()
{ {
LogAST log; LogAST log;
@ -1285,19 +1221,24 @@ const ExpressionAnalyzer::AnalyzedJoin::JoinedColumnsList & ExpressionAnalyzer::
if (const ASTTablesInSelectQueryElement * node = select_query_with_join->join()) if (const ASTTablesInSelectQueryElement * node = select_query_with_join->join())
{ {
const auto & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression); const auto & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression);
auto table_name_with_alias = getTableNameWithAliasFromTableExpression(table_expression, context.getCurrentDatabase()); DatabaseAndTableWithAlias table_name_with_alias(table_expression, context.getCurrentDatabase());
auto columns = getNamesAndTypeListFromTableExpression(table_expression, context); auto columns = getNamesAndTypeListFromTableExpression(table_expression, context);
for (auto & column : columns) for (auto & column : columns)
{ {
columns_from_joined_table.emplace_back(column, column.name); JoinedColumn joined_column(column, column.name);
if (source_columns.contains(column.name)) if (source_columns.contains(column.name))
{ {
auto qualified_name = table_name_with_alias.getQualifiedNamePrefix() + column.name; auto qualified_name = table_name_with_alias.getQualifiedNamePrefix() + column.name;
columns_from_joined_table.back().name_and_type.name = qualified_name; joined_column.name_and_type.name = qualified_name;
} }
/// We don't want to select duplicate columns from the joined subquery if they appear
if (std::find(columns_from_joined_table.begin(), columns_from_joined_table.end(), joined_column) == columns_from_joined_table.end())
columns_from_joined_table.push_back(joined_column);
} }
} }
} }
@ -1343,8 +1284,8 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty
if (table_to_join.database_and_table_name) if (table_to_join.database_and_table_name)
{ {
const auto & identifier = static_cast<const ASTIdentifier &>(*table_to_join.database_and_table_name); const auto & identifier = static_cast<const ASTIdentifier &>(*table_to_join.database_and_table_name);
auto database_table = getDatabaseAndTableNameFromIdentifier(identifier); DatabaseAndTableWithAlias database_table(identifier);
StoragePtr table = context.tryGetTable(database_table.first, database_table.second); StoragePtr table = context.tryGetTable(database_table.database, database_table.table);
if (table) if (table)
{ {
@ -1886,8 +1827,8 @@ void ExpressionAnalyzer::collectJoinedColumnsFromJoinOnExpr()
const auto & left_table_expression = static_cast<const ASTTableExpression &>(*left_tables_element->table_expression); const auto & left_table_expression = static_cast<const ASTTableExpression &>(*left_tables_element->table_expression);
const auto & right_table_expression = static_cast<const ASTTableExpression &>(*right_tables_element->table_expression); const auto & right_table_expression = static_cast<const ASTTableExpression &>(*right_tables_element->table_expression);
auto left_source_names = getTableNameWithAliasFromTableExpression(left_table_expression, context.getCurrentDatabase()); DatabaseAndTableWithAlias left_source_names(left_table_expression, context.getCurrentDatabase());
auto right_source_names = getTableNameWithAliasFromTableExpression(right_table_expression, context.getCurrentDatabase()); DatabaseAndTableWithAlias right_source_names(right_table_expression, context.getCurrentDatabase());
/// Stores examples of columns which are only from one table. /// Stores examples of columns which are only from one table.
struct TableBelonging struct TableBelonging
@ -2040,7 +1981,7 @@ void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns)
const auto & table_join = static_cast<const ASTTableJoin &>(*node->table_join); const auto & table_join = static_cast<const ASTTableJoin &>(*node->table_join);
const auto & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression); const auto & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression);
auto joined_table_name = getTableNameWithAliasFromTableExpression(table_expression, context.getCurrentDatabase()); DatabaseAndTableWithAlias joined_table_name(table_expression, context.getCurrentDatabase());
auto add_name_to_join_keys = [&](Names & join_keys, ASTs & join_asts, const ASTPtr & ast, bool right_table) auto add_name_to_join_keys = [&](Names & join_keys, ASTs & join_asts, const ASTPtr & ast, bool right_table)
{ {

View File

@ -259,6 +259,11 @@ private:
JoinedColumn(const NameAndTypePair & name_and_type_, const String & original_name_) JoinedColumn(const NameAndTypePair & name_and_type_, const String & original_name_)
: name_and_type(name_and_type_), original_name(original_name_) {} : name_and_type(name_and_type_), original_name(original_name_) {}
bool operator==(const JoinedColumn & o) const
{
return name_and_type == o.name_and_type && original_name == o.original_name;
}
}; };
using JoinedColumnsList = std::list<JoinedColumn>; using JoinedColumnsList = std::list<JoinedColumn>;
@ -322,9 +327,6 @@ private:
void optimizeIfWithConstantConditionImpl(ASTPtr & current_ast); void optimizeIfWithConstantConditionImpl(ASTPtr & current_ast);
bool tryExtractConstValueFromCondition(const ASTPtr & condition, bool & value) const; bool tryExtractConstValueFromCondition(const ASTPtr & condition, bool & value) const;
/// Adds a list of ALIAS columns from the table.
void addAliasColumns();
/// Replacing scalar subqueries with constant values. /// Replacing scalar subqueries with constant values.
void executeScalarSubqueries(); void executeScalarSubqueries();

View File

@ -139,7 +139,7 @@ private:
* instead of doing a subquery, you just need to read it. * instead of doing a subquery, you just need to read it.
*/ */
auto database_and_table_name = ASTIdentifier::createSpecial(external_table_name); auto database_and_table_name = createDatabaseAndTableNode("", external_table_name);
if (auto ast_table_expr = typeid_cast<ASTTableExpression *>(subquery_or_table_name_or_table_expression.get())) if (auto ast_table_expr = typeid_cast<ASTTableExpression *>(subquery_or_table_name_or_table_expression.get()))
{ {

View File

@ -1,5 +1,6 @@
#include <Interpreters/InJoinSubqueriesPreprocessor.h> #include <Interpreters/InJoinSubqueriesPreprocessor.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Storages/StorageDistributed.h> #include <Storages/StorageDistributed.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTTablesInSelectQuery.h> #include <Parsers/ASTTablesInSelectQuery.h>
@ -81,40 +82,13 @@ void forEachTable(IAST * node, F && f)
StoragePtr tryGetTable(const ASTPtr & database_and_table, const Context & context) StoragePtr tryGetTable(const ASTPtr & database_and_table, const Context & context)
{ {
String database; const ASTIdentifier * id = typeid_cast<const ASTIdentifier *>(database_and_table.get());
String table; if (!id)
throw Exception("Logical error: identifier expected", ErrorCodes::LOGICAL_ERROR);
const ASTIdentifier * id = static_cast<const ASTIdentifier *>(database_and_table.get()); DatabaseAndTableWithAlias db_and_table(*id);
if (id->children.empty()) return context.tryGetTable(db_and_table.database, db_and_table.table);
table = id->name;
else if (id->children.size() == 2)
{
database = static_cast<const ASTIdentifier *>(id->children[0].get())->name;
table = static_cast<const ASTIdentifier *>(id->children[1].get())->name;
}
else
throw Exception("Logical error: unexpected number of components in table expression", ErrorCodes::LOGICAL_ERROR);
return context.tryGetTable(database, table);
}
void replaceDatabaseAndTable(ASTPtr & database_and_table, const String & database_name, const String & table_name)
{
ASTPtr table = ASTIdentifier::createSpecial(table_name);
if (!database_name.empty())
{
ASTPtr database = ASTIdentifier::createSpecial(database_name);
database_and_table = ASTIdentifier::createSpecial(database_name + "." + table_name);
database_and_table->children = {database, table};
}
else
{
database_and_table = ASTIdentifier::createSpecial(table_name);
}
} }
} }
@ -156,7 +130,7 @@ void InJoinSubqueriesPreprocessor::process(ASTSelectQuery * query) const
forEachNonGlobalSubquery(query, [&] (IAST * subquery, IAST * function, IAST * table_join) forEachNonGlobalSubquery(query, [&] (IAST * subquery, IAST * function, IAST * table_join)
{ {
forEachTable(subquery, [&] (ASTPtr & database_and_table) forEachTable(subquery, [&] (ASTPtr & database_and_table)
{ {
StoragePtr storage = tryGetTable(database_and_table, context); StoragePtr storage = tryGetTable(database_and_table, context);
@ -199,7 +173,8 @@ void InJoinSubqueriesPreprocessor::process(ASTSelectQuery * query) const
std::string table; std::string table;
std::tie(database, table) = getRemoteDatabaseAndTableName(*storage); std::tie(database, table) = getRemoteDatabaseAndTableName(*storage);
replaceDatabaseAndTable(database_and_table, database, table); /// TODO: find a way to avoid AST node replacing
database_and_table = createDatabaseAndTableNode(database, table);
} }
else else
throw Exception("InJoinSubqueriesPreprocessor: unexpected value of 'distributed_product_mode' setting", ErrorCodes::LOGICAL_ERROR); throw Exception("InJoinSubqueriesPreprocessor: unexpected value of 'distributed_product_mode' setting", ErrorCodes::LOGICAL_ERROR);

View File

@ -27,7 +27,7 @@ BlockIO InterpreterAlterQuery::execute()
auto & alter = typeid_cast<ASTAlterQuery &>(*query_ptr); auto & alter = typeid_cast<ASTAlterQuery &>(*query_ptr);
if (!alter.cluster.empty()) if (!alter.cluster.empty())
return executeDDLQueryOnCluster(query_ptr, context, {alter.table}); return executeDDLQueryOnCluster(query_ptr, context, {alter.database});
const String & table_name = alter.table; const String & table_name = alter.table;
String database_name = alter.database.empty() ? context.getCurrentDatabase() : alter.database; String database_name = alter.database.empty() ? context.getCurrentDatabase() : alter.database;

View File

@ -487,7 +487,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
if (!create.to_table.empty()) if (!create.to_table.empty())
databases.emplace(create.to_database); databases.emplace(create.to_database);
return executeDDLQueryOnCluster(query_ptr, context, databases); return executeDDLQueryOnCluster(query_ptr, context, std::move(databases));
} }
String path = context.getPath(); String path = context.getPath();

View File

@ -10,7 +10,6 @@
#include <DataStreams/SquashingBlockOutputStream.h> #include <DataStreams/SquashingBlockOutputStream.h>
#include <DataStreams/copyData.h> #include <DataStreams/copyData.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTInsertQuery.h> #include <Parsers/ASTInsertQuery.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>

View File

@ -47,7 +47,7 @@ BlockIO InterpreterRenameQuery::execute()
databases.emplace(elem.to.database); databases.emplace(elem.to.database);
} }
return executeDDLQueryOnCluster(query_ptr, context, databases); return executeDDLQueryOnCluster(query_ptr, context, std::move(databases));
} }
String path = context.getPath(); String path = context.getPath();

View File

@ -34,6 +34,7 @@
#include <Interpreters/InterpreterSelectWithUnionQuery.h> #include <Interpreters/InterpreterSelectWithUnionQuery.h>
#include <Interpreters/InterpreterSetQuery.h> #include <Interpreters/InterpreterSetQuery.h>
#include <Interpreters/ExpressionAnalyzer.h> #include <Interpreters/ExpressionAnalyzer.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Storages/MergeTree/MergeTreeWhereOptimizer.h> #include <Storages/MergeTree/MergeTreeWhereOptimizer.h>
#include <Storages/IStorage.h> #include <Storages/IStorage.h>
@ -49,6 +50,7 @@
#include <Parsers/queryToString.h> #include <Parsers/queryToString.h>
#include <ext/map.h> #include <ext/map.h>
#include <memory> #include <memory>
#include <DataStreams/ConvertingBlockInputStream.h>
namespace DB namespace DB
@ -145,7 +147,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(
max_streams = settings.max_threads; max_streams = settings.max_threads;
const auto & table_expression = query.table(); ASTPtr table_expression = getTableFunctionOrSubquery(query, 0);
if (input) if (input)
{ {
@ -204,7 +206,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(
if (query_analyzer->isRewriteSubqueriesPredicate()) if (query_analyzer->isRewriteSubqueriesPredicate())
{ {
/// remake interpreter_subquery when PredicateOptimizer is rewrite subqueries and main table is subquery /// remake interpreter_subquery when PredicateOptimizer is rewrite subqueries and main table is subquery
if (typeid_cast<ASTSelectWithUnionQuery *>(table_expression.get())) if (table_expression && typeid_cast<ASTSelectWithUnionQuery *>(table_expression.get()))
interpreter_subquery = std::make_unique<InterpreterSelectWithUnionQuery>( interpreter_subquery = std::make_unique<InterpreterSelectWithUnionQuery>(
table_expression, getSubqueryContext(context), required_columns, QueryProcessingStage::Complete, subquery_depth + 1, table_expression, getSubqueryContext(context), required_columns, QueryProcessingStage::Complete, subquery_depth + 1,
only_analyze); only_analyze);
@ -235,29 +237,20 @@ InterpreterSelectQuery::InterpreterSelectQuery(
void InterpreterSelectQuery::getDatabaseAndTableNames(String & database_name, String & table_name) void InterpreterSelectQuery::getDatabaseAndTableNames(String & database_name, String & table_name)
{ {
auto query_database = query.database(); if (auto db_and_table = getDatabaseAndTable(query, 0))
auto query_table = query.table(); {
table_name = db_and_table->table;
database_name = db_and_table->database;
/** If the table is not specified - use the table `system.one`. /// If the database is not specified - use the current database.
* If the database is not specified - use the current database. if (database_name.empty() && !context.tryGetTable("", table_name))
*/ database_name = context.getCurrentDatabase();
if (query_database) }
database_name = typeid_cast<ASTIdentifier &>(*query_database).name; else /// If the table is not specified - use the table `system.one`.
if (query_table)
table_name = typeid_cast<ASTIdentifier &>(*query_table).name;
if (!query_table)
{ {
database_name = "system"; database_name = "system";
table_name = "one"; table_name = "one";
} }
else if (!query_database)
{
if (context.tryGetTable("", table_name))
database_name = "";
else
database_name = context.getCurrentDatabase();
}
} }
@ -883,8 +876,12 @@ void InterpreterSelectQuery::executeFetchColumns(
/// If we need less number of columns that subquery have - update the interpreter. /// If we need less number of columns that subquery have - update the interpreter.
if (required_columns.size() < source_header.columns()) if (required_columns.size() < source_header.columns())
{ {
ASTPtr subquery = getTableFunctionOrSubquery(query, 0);
if (!subquery)
throw Exception("Subquery expected", ErrorCodes::LOGICAL_ERROR);
interpreter_subquery = std::make_unique<InterpreterSelectWithUnionQuery>( interpreter_subquery = std::make_unique<InterpreterSelectWithUnionQuery>(
query.table(), getSubqueryContext(context), required_columns, QueryProcessingStage::Complete, subquery_depth + 1, only_analyze); subquery, getSubqueryContext(context), required_columns, QueryProcessingStage::Complete, subquery_depth + 1, only_analyze);
if (query_analyzer->hasAggregation()) if (query_analyzer->hasAggregation())
interpreter_subquery->ignoreWithTotals(); interpreter_subquery->ignoreWithTotals();
@ -1293,6 +1290,17 @@ void InterpreterSelectQuery::executeUnion(Pipeline & pipeline)
/// If there are still several streams, then we combine them into one /// If there are still several streams, then we combine them into one
if (pipeline.hasMoreThanOneStream()) if (pipeline.hasMoreThanOneStream())
{ {
/// Unify streams in case they have different headers.
auto first_header = pipeline.streams.at(0)->getHeader();
for (size_t i = 1; i < pipeline.streams.size(); ++i)
{
auto & stream = pipeline.streams[i];
auto header = stream->getHeader();
auto mode = ConvertingBlockInputStream::MatchColumnsMode::Name;
if (!blocksHaveEqualStructure(first_header, header))
stream = std::make_shared<ConvertingBlockInputStream>(context, stream, first_header, mode);
}
pipeline.firstStream() = std::make_shared<UnionBlockInputStream<>>(pipeline.streams, pipeline.stream_with_non_joined_data, max_streams); pipeline.firstStream() = std::make_shared<UnionBlockInputStream<>>(pipeline.streams, pipeline.stream_with_non_joined_data, max_streams);
pipeline.stream_with_non_joined_data = nullptr; pipeline.stream_with_non_joined_data = nullptr;
pipeline.streams.resize(1); pipeline.streams.resize(1);
@ -1350,11 +1358,9 @@ bool hasWithTotalsInAnySubqueryInFromClause(const ASTSelectQuery & query)
* In other cases, totals will be computed on the initiating server of the query, and it is not necessary to read the data to the end. * In other cases, totals will be computed on the initiating server of the query, and it is not necessary to read the data to the end.
*/ */
auto query_table = query.table(); if (auto query_table = getTableFunctionOrSubquery(query, 0))
if (query_table)
{ {
auto ast_union = typeid_cast<const ASTSelectWithUnionQuery *>(query_table.get()); if (auto ast_union = typeid_cast<const ASTSelectWithUnionQuery *>(query_table.get()))
if (ast_union)
{ {
for (const auto & elem : ast_union->list_of_selects->children) for (const auto & elem : ast_union->list_of_selects->children)
if (hasWithTotalsInAnySubqueryInFromClause(typeid_cast<const ASTSelectQuery &>(*elem))) if (hasWithTotalsInAnySubqueryInFromClause(typeid_cast<const ASTSelectQuery &>(*elem)))

View File

@ -5,7 +5,6 @@
#include <Interpreters/InterpreterShowProcesslistQuery.h> #include <Interpreters/InterpreterShowProcesslistQuery.h>
#include <Parsers/ASTQueryWithOutput.h> #include <Parsers/ASTQueryWithOutput.h>
#include <Parsers/ASTIdentifier.h>
namespace DB namespace DB

View File

@ -1,6 +1,5 @@
#include <IO/ReadBufferFromString.h> #include <IO/ReadBufferFromString.h>
#include <Parsers/ASTShowTablesQuery.h> #include <Parsers/ASTShowTablesQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/executeQuery.h> #include <Interpreters/executeQuery.h>
#include <Interpreters/InterpreterShowTablesQuery.h> #include <Interpreters/InterpreterShowTablesQuery.h>

View File

@ -44,11 +44,8 @@ bool PredicateExpressionsOptimizer::optimizeImpl(
/// split predicate with `and` /// split predicate with `and`
PredicateExpressions outer_predicate_expressions = splitConjunctionPredicate(outer_expression); PredicateExpressions outer_predicate_expressions = splitConjunctionPredicate(outer_expression);
std::vector<ASTTableExpression *> tables_expression = getSelectTablesExpression(ast_select); std::vector<DatabaseAndTableWithAlias> database_and_table_with_aliases =
std::vector<DatabaseAndTableWithAlias> database_and_table_with_aliases; getDatabaseAndTables(*ast_select, context.getCurrentDatabase());
for (const auto & table_expression : tables_expression)
database_and_table_with_aliases.emplace_back(
getTableNameWithAliasFromTableExpression(*table_expression, context.getCurrentDatabase()));
bool is_rewrite_subquery = false; bool is_rewrite_subquery = false;
for (const auto & outer_predicate : outer_predicate_expressions) for (const auto & outer_predicate : outer_predicate_expressions)
@ -261,15 +258,14 @@ bool PredicateExpressionsOptimizer::optimizeExpression(const ASTPtr & outer_expr
void PredicateExpressionsOptimizer::getAllSubqueryProjectionColumns(SubqueriesProjectionColumns & all_subquery_projection_columns) void PredicateExpressionsOptimizer::getAllSubqueryProjectionColumns(SubqueriesProjectionColumns & all_subquery_projection_columns)
{ {
const auto tables_expression = getSelectTablesExpression(ast_select); const auto tables_expression = getSelectTablesExpression(*ast_select);
for (const auto & table_expression : tables_expression) for (const auto & table_expression : tables_expression)
{ {
if (table_expression->subquery) if (table_expression->subquery)
{ {
/// Use qualifiers to translate the columns of subqueries /// Use qualifiers to translate the columns of subqueries
const auto database_and_table_with_alias = DatabaseAndTableWithAlias database_and_table_with_alias(*table_expression, context.getCurrentDatabase());
getTableNameWithAliasFromTableExpression(*table_expression, context.getCurrentDatabase());
String qualified_name_prefix = database_and_table_with_alias.getQualifiedNamePrefix(); String qualified_name_prefix = database_and_table_with_alias.getQualifiedNamePrefix();
getSubqueryProjectionColumns(all_subquery_projection_columns, qualified_name_prefix, getSubqueryProjectionColumns(all_subquery_projection_columns, qualified_name_prefix,
static_cast<const ASTSubquery *>(table_expression->subquery.get())->children[0]); static_cast<const ASTSubquery *>(table_expression->subquery.get())->children[0]);
@ -336,7 +332,7 @@ ASTs PredicateExpressionsOptimizer::evaluateAsterisk(ASTSelectQuery * select_que
if (!select_query->tables || select_query->tables->children.empty()) if (!select_query->tables || select_query->tables->children.empty())
return {}; return {};
std::vector<ASTTableExpression *> tables_expression = getSelectTablesExpression(select_query); std::vector<const ASTTableExpression *> tables_expression = getSelectTablesExpression(*select_query);
if (const auto qualified_asterisk = typeid_cast<ASTQualifiedAsterisk *>(asterisk.get())) if (const auto qualified_asterisk = typeid_cast<ASTQualifiedAsterisk *>(asterisk.get()))
{ {
@ -354,8 +350,7 @@ ASTs PredicateExpressionsOptimizer::evaluateAsterisk(ASTSelectQuery * select_que
for (auto it = tables_expression.begin(); it != tables_expression.end(); ++it) for (auto it = tables_expression.begin(); it != tables_expression.end(); ++it)
{ {
const ASTTableExpression * table_expression = *it; const ASTTableExpression * table_expression = *it;
const auto database_and_table_with_alias = DatabaseAndTableWithAlias database_and_table_with_alias(*table_expression, context.getCurrentDatabase());
getTableNameWithAliasFromTableExpression(*table_expression, context.getCurrentDatabase());
/// database.table.* /// database.table.*
if (num_components == 2 && !database_and_table_with_alias.database.empty() if (num_components == 2 && !database_and_table_with_alias.database.empty()
&& static_cast<const ASTIdentifier &>(*ident->children[0]).name == database_and_table_with_alias.database && static_cast<const ASTIdentifier &>(*ident->children[0]).name == database_and_table_with_alias.database
@ -394,8 +389,8 @@ ASTs PredicateExpressionsOptimizer::evaluateAsterisk(ASTSelectQuery * select_que
else if (table_expression->database_and_table_name) else if (table_expression->database_and_table_name)
{ {
const auto database_and_table_ast = static_cast<ASTIdentifier*>(table_expression->database_and_table_name.get()); const auto database_and_table_ast = static_cast<ASTIdentifier*>(table_expression->database_and_table_name.get());
const auto database_and_table_name = getDatabaseAndTableNameFromIdentifier(*database_and_table_ast); DatabaseAndTableWithAlias database_and_table_name(*database_and_table_ast);
storage = context.getTable(database_and_table_name.first, database_and_table_name.second); storage = context.getTable(database_and_table_name.database, database_and_table_name.table);
} }
const auto block = storage->getSampleBlock(); const auto block = storage->getSampleBlock();
@ -406,25 +401,6 @@ ASTs PredicateExpressionsOptimizer::evaluateAsterisk(ASTSelectQuery * select_que
return projection_columns; return projection_columns;
} }
std::vector<ASTTableExpression *> PredicateExpressionsOptimizer::getSelectTablesExpression(ASTSelectQuery * select_query)
{
if (!select_query->tables)
return {};
std::vector<ASTTableExpression *> tables_expression;
const ASTTablesInSelectQuery & tables_in_select_query = static_cast<const ASTTablesInSelectQuery &>(*select_query->tables);
for (const auto & child : tables_in_select_query.children)
{
ASTTablesInSelectQueryElement * tables_element = static_cast<ASTTablesInSelectQueryElement *>(child.get());
if (tables_element->table_expression)
tables_expression.emplace_back(static_cast<ASTTableExpression *>(tables_element->table_expression.get()));
}
return tables_expression;
}
void PredicateExpressionsOptimizer::cleanExpressionAlias(ASTPtr & expression) void PredicateExpressionsOptimizer::cleanExpressionAlias(ASTPtr & expression)
{ {
const auto my_alias = expression->tryGetAlias(); const auto my_alias = expression->tryGetAlias();

View File

@ -9,7 +9,7 @@
#include <Interpreters/ExpressionActions.h> #include <Interpreters/ExpressionActions.h>
#include <Parsers/ASTSubquery.h> #include <Parsers/ASTSubquery.h>
#include <Parsers/ASTTablesInSelectQuery.h> #include <Parsers/ASTTablesInSelectQuery.h>
#include <Interpreters/evaluateQualified.h> #include <Interpreters/DatabaseAndTableWithAlias.h>
namespace DB namespace DB
{ {
@ -105,8 +105,6 @@ private:
ASTs getSelectQueryProjectionColumns(ASTPtr & ast); ASTs getSelectQueryProjectionColumns(ASTPtr & ast);
std::vector<ASTTableExpression *> getSelectTablesExpression(ASTSelectQuery * select_query);
ASTs evaluateAsterisk(ASTSelectQuery * select_query, const ASTPtr & asterisk); ASTs evaluateAsterisk(ASTSelectQuery * select_query, const ASTPtr & asterisk);
void cleanExpressionAlias(ASTPtr & expression); void cleanExpressionAlias(ASTPtr & expression);

View File

@ -1,10 +1,10 @@
#include <Interpreters/ProcessList.h> #include <Interpreters/ProcessList.h>
#include <Interpreters/Settings.h> #include <Interpreters/Settings.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTKillQueryQuery.h> #include <Parsers/ASTKillQueryQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
#include <Common/Exception.h> #include <Common/Exception.h>
#include <Common/CurrentThread.h> #include <Common/CurrentThread.h>
@ -51,28 +51,14 @@ static bool isUnlimitedQuery(const IAST * ast)
if (!ast_selects->list_of_selects || ast_selects->list_of_selects->children.empty()) if (!ast_selects->list_of_selects || ast_selects->list_of_selects->children.empty())
return false; return false;
auto ast_select = typeid_cast<ASTSelectQuery *>(ast_selects->list_of_selects->children[0].get()); auto ast_select = typeid_cast<const ASTSelectQuery *>(ast_selects->list_of_selects->children[0].get());
if (!ast_select) if (!ast_select)
return false; return false;
auto ast_database = ast_select->database(); if (auto database_and_table = getDatabaseAndTable(*ast_select, 0))
if (!ast_database) return database_and_table->database == "system" && database_and_table->table == "processes";
return false;
auto ast_table = ast_select->table(); return false;
if (!ast_table)
return false;
auto ast_database_id = typeid_cast<const ASTIdentifier *>(ast_database.get());
if (!ast_database_id)
return false;
auto ast_table_id = typeid_cast<const ASTIdentifier *>(ast_table.get());
if (!ast_table_id)
return false;
return ast_database_id->name == "system" && ast_table_id->name == "processes";
} }
return false; return false;

View File

@ -9,7 +9,6 @@
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
#include <Poco/String.h> #include <Poco/String.h>
#include <Parsers/ASTQualifiedAsterisk.h> #include <Parsers/ASTQualifiedAsterisk.h>
//#include <iostream>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
namespace DB namespace DB

View File

@ -2,7 +2,7 @@
#include <Core/Names.h> #include <Core/Names.h>
#include <Parsers/IAST.h> #include <Parsers/IAST.h>
#include <Interpreters/evaluateQualified.h> #include <Interpreters/DatabaseAndTableWithAlias.h>
namespace DB namespace DB
{ {

View File

@ -49,6 +49,7 @@ struct Settings
M(SettingMilliseconds, connect_timeout_with_failover_ms, DBMS_DEFAULT_CONNECT_TIMEOUT_WITH_FAILOVER_MS, "Connection timeout for selecting first healthy replica.") \ M(SettingMilliseconds, connect_timeout_with_failover_ms, DBMS_DEFAULT_CONNECT_TIMEOUT_WITH_FAILOVER_MS, "Connection timeout for selecting first healthy replica.") \
M(SettingSeconds, receive_timeout, DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC, "") \ M(SettingSeconds, receive_timeout, DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC, "") \
M(SettingSeconds, send_timeout, DBMS_DEFAULT_SEND_TIMEOUT_SEC, "") \ M(SettingSeconds, send_timeout, DBMS_DEFAULT_SEND_TIMEOUT_SEC, "") \
M(SettingSeconds, tcp_keep_alive_timeout, 0, "") \
M(SettingMilliseconds, queue_max_wait_ms, 5000, "The wait time in the request queue, if the number of concurrent requests exceeds the maximum.") \ M(SettingMilliseconds, queue_max_wait_ms, 5000, "The wait time in the request queue, if the number of concurrent requests exceeds the maximum.") \
M(SettingUInt64, poll_interval, DBMS_DEFAULT_POLL_INTERVAL, "Block at the query wait loop on the server for the specified number of seconds.") \ M(SettingUInt64, poll_interval, DBMS_DEFAULT_POLL_INTERVAL, "Block at the query wait loop on the server for the specified number of seconds.") \
M(SettingUInt64, distributed_connections_pool_size, DBMS_DEFAULT_DISTRIBUTED_CONNECTIONS_POOL_SIZE, "Maximum number of connections with one remote server in the pool.") \ M(SettingUInt64, distributed_connections_pool_size, DBMS_DEFAULT_DISTRIBUTED_CONNECTIONS_POOL_SIZE, "Maximum number of connections with one remote server in the pool.") \

View File

@ -65,18 +65,23 @@ void TranslateQualifiedNamesVisitor::visit(ASTQualifiedAsterisk *, ASTPtr & ast,
if (num_components > 2) if (num_components > 2)
throw Exception("Qualified asterisk cannot have more than two qualifiers", ErrorCodes::UNKNOWN_ELEMENT_IN_AST); throw Exception("Qualified asterisk cannot have more than two qualifiers", ErrorCodes::UNKNOWN_ELEMENT_IN_AST);
DatabaseAndTableWithAlias db_and_table(*ident);
for (const auto & table_names : tables) for (const auto & table_names : tables)
{ {
/// database.table.*, table.* or alias.* /// database.table.*, table.* or alias.*
if ((num_components == 2 if (num_components == 2)
&& !table_names.database.empty()
&& static_cast<const ASTIdentifier &>(*ident->children[0]).name == table_names.database
&& static_cast<const ASTIdentifier &>(*ident->children[1]).name == table_names.table)
|| (num_components == 0
&& ((!table_names.table.empty() && ident->name == table_names.table)
|| (!table_names.alias.empty() && ident->name == table_names.alias))))
{ {
return; if (!table_names.database.empty() &&
db_and_table.database == table_names.database &&
db_and_table.table == table_names.table)
return;
}
else if (num_components == 0)
{
if ((!table_names.table.empty() && db_and_table.table == table_names.table) ||
(!table_names.alias.empty() && db_and_table.table == table_names.alias))
return;
} }
} }

View File

@ -5,7 +5,7 @@
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
#include <Parsers/DumpASTNode.h> #include <Parsers/DumpASTNode.h>
#include <Interpreters/evaluateQualified.h> #include <Interpreters/DatabaseAndTableWithAlias.h>
namespace DB namespace DB
{ {
@ -18,7 +18,7 @@ struct ASTTableJoin;
class NamesAndTypesList; class NamesAndTypesList;
/// It visits nodes, find identifiers and translate their names to needed form. /// It visits nodes, find columns (general identifiers and asterisks) and translate their names according to tables' names.
class TranslateQualifiedNamesVisitor class TranslateQualifiedNamesVisitor
{ {
public: public:

View File

@ -1,167 +0,0 @@
#include <Interpreters/evaluateQualified.h>
#include <Interpreters/Context.h>
#include <Common/typeid_cast.h>
#include <Parsers/IAST.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTTablesInSelectQuery.h>
namespace DB
{
/// Checks that ast is ASTIdentifier and remove num_qualifiers_to_strip components from left.
/// Example: 'database.table.name' -> (num_qualifiers_to_strip = 2) -> 'name'.
void stripIdentifier(DB::ASTPtr & ast, size_t num_qualifiers_to_strip)
{
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(ast.get());
if (!identifier)
throw DB::Exception("ASTIdentifier expected for stripIdentifier", DB::ErrorCodes::LOGICAL_ERROR);
if (num_qualifiers_to_strip)
{
size_t num_components = identifier->children.size();
/// plain column
if (num_components - num_qualifiers_to_strip == 1)
{
DB::String node_alias = identifier->tryGetAlias();
ast = identifier->children.back();
if (!node_alias.empty())
ast->setAlias(node_alias);
}
else
/// nested column
{
identifier->children.erase(identifier->children.begin(), identifier->children.begin() + num_qualifiers_to_strip);
DB::String new_name;
for (const auto & child : identifier->children)
{
if (!new_name.empty())
new_name += '.';
new_name += static_cast<const ASTIdentifier &>(*child.get()).name;
}
identifier->name = new_name;
}
}
}
DatabaseAndTableWithAlias getTableNameWithAliasFromTableExpression(const ASTTableExpression & table_expression,
const String & current_database)
{
DatabaseAndTableWithAlias database_and_table_with_alias;
if (table_expression.database_and_table_name)
{
const auto & identifier = static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name);
database_and_table_with_alias.alias = identifier.tryGetAlias();
if (table_expression.database_and_table_name->children.empty())
{
database_and_table_with_alias.database = current_database;
database_and_table_with_alias.table = identifier.name;
}
else
{
if (table_expression.database_and_table_name->children.size() != 2)
throw Exception("Logical error: number of components in table expression not equal to two", ErrorCodes::LOGICAL_ERROR);
database_and_table_with_alias.database = static_cast<const ASTIdentifier &>(*identifier.children[0]).name;
database_and_table_with_alias.table = static_cast<const ASTIdentifier &>(*identifier.children[1]).name;
}
}
else if (table_expression.table_function)
{
database_and_table_with_alias.alias = table_expression.table_function->tryGetAlias();
}
else if (table_expression.subquery)
{
database_and_table_with_alias.alias = table_expression.subquery->tryGetAlias();
}
else
throw Exception("Logical error: no known elements in ASTTableExpression", ErrorCodes::LOGICAL_ERROR);
return database_and_table_with_alias;
}
/// Get the number of components of identifier which are correspond to 'alias.', 'table.' or 'databas.table.' from names.
size_t getNumComponentsToStripInOrderToTranslateQualifiedName(const ASTIdentifier & identifier,
const DatabaseAndTableWithAlias & names)
{
size_t num_qualifiers_to_strip = 0;
auto get_identifier_name = [](const ASTPtr & ast) { return static_cast<const ASTIdentifier &>(*ast).name; };
/// It is compound identifier
if (!identifier.children.empty())
{
size_t num_components = identifier.children.size();
/// database.table.column
if (num_components >= 3
&& !names.database.empty()
&& get_identifier_name(identifier.children[0]) == names.database
&& get_identifier_name(identifier.children[1]) == names.table)
{
num_qualifiers_to_strip = 2;
}
/// table.column or alias.column. If num_components > 2, it is like table.nested.column.
if (num_components >= 2
&& ((!names.table.empty() && get_identifier_name(identifier.children[0]) == names.table)
|| (!names.alias.empty() && get_identifier_name(identifier.children[0]) == names.alias)))
{
num_qualifiers_to_strip = 1;
}
}
return num_qualifiers_to_strip;
}
std::pair<String, String> getDatabaseAndTableNameFromIdentifier(const ASTIdentifier & identifier)
{
std::pair<String, String> res;
res.second = identifier.name;
if (!identifier.children.empty())
{
if (identifier.children.size() != 2)
throw Exception("Qualified table name could have only two components", ErrorCodes::LOGICAL_ERROR);
res.first = typeid_cast<const ASTIdentifier &>(*identifier.children[0]).name;
res.second = typeid_cast<const ASTIdentifier &>(*identifier.children[1]).name;
}
return res;
}
String DatabaseAndTableWithAlias::getQualifiedNamePrefix() const
{
if (alias.empty() && table.empty())
return "";
return (!alias.empty() ? alias : (database + '.' + table)) + '.';
}
void DatabaseAndTableWithAlias::makeQualifiedName(const ASTPtr & ast) const
{
if (auto identifier = typeid_cast<ASTIdentifier *>(ast.get()))
{
String prefix = getQualifiedNamePrefix();
identifier->name.insert(identifier->name.begin(), prefix.begin(), prefix.end());
Names qualifiers;
if (!alias.empty())
qualifiers.push_back(alias);
else
{
qualifiers.push_back(database);
qualifiers.push_back(table);
}
for (const auto & qualifier : qualifiers)
identifier->children.emplace_back(std::make_shared<ASTIdentifier>(qualifier));
}
}
}

View File

@ -10,7 +10,7 @@
#include <Parsers/ASTSubquery.h> #include <Parsers/ASTSubquery.h>
#include <Interpreters/interpretSubquery.h> #include <Interpreters/interpretSubquery.h>
#include <Interpreters/evaluateQualified.h> #include <Interpreters/DatabaseAndTableWithAlias.h>
namespace DB namespace DB
{ {
@ -69,10 +69,10 @@ std::shared_ptr<InterpreterSelectWithUnionQuery> interpretSubquery(
} }
else else
{ {
auto database_table = getDatabaseAndTableNameFromIdentifier(*table); DatabaseAndTableWithAlias database_table(*table);
const auto & storage = context.getTable(database_table.first, database_table.second); const auto & storage = context.getTable(database_table.database, database_table.table);
columns = storage->getColumns().ordinary; columns = storage->getColumns().ordinary;
select_query->replaceDatabaseAndTable(database_table.first, database_table.second); select_query->replaceDatabaseAndTable(database_table.database, database_table.table);
} }
select_expression_list->children.reserve(columns.size()); select_expression_list->children.reserve(columns.size());

View File

@ -187,18 +187,6 @@ ASTPtr ASTAlterQuery::clone() const
return res; return res;
} }
ASTPtr ASTAlterQuery::getRewrittenASTWithoutOnCluster(const std::string & new_database) const
{
auto query_ptr = clone();
auto & query = static_cast<ASTAlterQuery &>(*query_ptr);
query.cluster.clear();
if (query.database.empty())
query.database = new_database;
return query_ptr;
}
void ASTAlterQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTAlterQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
frame.need_parens = false; frame.need_parens = false;

View File

@ -122,7 +122,10 @@ public:
ASTPtr clone() const override; ASTPtr clone() const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override; ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override
{
return removeOnCluster<ASTAlterQuery>(clone(), new_database);
}
protected: protected:
void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;

View File

@ -112,14 +112,7 @@ public:
ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override
{ {
auto query_ptr = clone(); return removeOnCluster<ASTCreateQuery>(clone(), new_database);
ASTCreateQuery & query = static_cast<ASTCreateQuery &>(*query_ptr);
query.cluster.clear();
if (query.database.empty())
query.database = new_database;
return query_ptr;
} }
protected: protected:

View File

@ -29,18 +29,6 @@ ASTPtr ASTDropQuery::clone() const
return res; return res;
} }
ASTPtr ASTDropQuery::getRewrittenASTWithoutOnCluster(const std::string & new_database) const
{
auto query_ptr = clone();
auto & query = static_cast<ASTDropQuery &>(*query_ptr);
query.cluster.clear();
if (query.database.empty())
query.database = new_database;
return query_ptr;
}
void ASTDropQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const void ASTDropQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{ {
settings.ostr << (settings.hilite ? hilite_keyword : ""); settings.ostr << (settings.hilite ? hilite_keyword : "");

View File

@ -26,7 +26,10 @@ public:
String getID() const override; String getID() const override;
ASTPtr clone() const override; ASTPtr clone() const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override; ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override
{
return removeOnCluster<ASTDropQuery>(clone(), new_database);
}
protected: protected:
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <Parsers/IAST.h> #include <Parsers/IAST.h>
#include <Parsers/ASTLiteral.h>
namespace DB namespace DB

View File

@ -8,16 +8,6 @@ String ASTKillQueryQuery::getID() const
return "KillQueryQuery_" + (where_expression ? where_expression->getID() : "") + "_" + String(sync ? "SYNC" : "ASYNC"); return "KillQueryQuery_" + (where_expression ? where_expression->getID() : "") + "_" + String(sync ? "SYNC" : "ASYNC");
} }
ASTPtr ASTKillQueryQuery::getRewrittenASTWithoutOnCluster(const std::string & /*new_database*/) const
{
auto query_ptr = clone();
ASTKillQueryQuery & query = static_cast<ASTKillQueryQuery &>(*query_ptr);
query.cluster.clear();
return query_ptr;
}
void ASTKillQueryQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTKillQueryQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
settings.ostr << (settings.hilite ? hilite_keyword : "") << "KILL QUERY "; settings.ostr << (settings.hilite ? hilite_keyword : "") << "KILL QUERY ";

View File

@ -24,7 +24,10 @@ public:
void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &new_database) const override; ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override
{
return removeOnCluster<ASTKillQueryQuery>(clone());
}
}; };
} }

View File

@ -3,19 +3,6 @@
namespace DB namespace DB
{ {
ASTPtr ASTOptimizeQuery::getRewrittenASTWithoutOnCluster(const std::string & new_database) const
{
auto query_ptr = clone();
ASTOptimizeQuery & query = static_cast<ASTOptimizeQuery &>(*query_ptr);
query.cluster.clear();
if (query.database.empty())
query.database = new_database;
return query_ptr;
}
void ASTOptimizeQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTOptimizeQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
settings.ostr << (settings.hilite ? hilite_keyword : "") << "OPTIMIZE TABLE " << (settings.hilite ? hilite_none : "") settings.ostr << (settings.hilite ? hilite_keyword : "") << "OPTIMIZE TABLE " << (settings.hilite ? hilite_none : "")

View File

@ -40,7 +40,10 @@ public:
void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &new_database) const override; ASTPtr getRewrittenASTWithoutOnCluster(const std::string &new_database) const override
{
return removeOnCluster<ASTOptimizeQuery>(clone(), new_database);
}
}; };
} }

View File

@ -2,8 +2,6 @@
#include <Parsers/queryToString.h> #include <Parsers/queryToString.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
#include <Interpreters/evaluateConstantExpression.h> #include <Interpreters/evaluateConstantExpression.h>

View File

@ -28,6 +28,27 @@ public:
static bool parse(Pos & pos, std::string & cluster_str, Expected & expected); static bool parse(Pos & pos, std::string & cluster_str, Expected & expected);
virtual ~ASTQueryWithOnCluster() = default; virtual ~ASTQueryWithOnCluster() = default;
protected:
template <typename T>
static ASTPtr removeOnCluster(ASTPtr query_ptr, const std::string & new_database)
{
T & query = static_cast<T &>(*query_ptr);
query.cluster.clear();
if (query.database.empty())
query.database = new_database;
return query_ptr;
}
template <typename T>
static ASTPtr removeOnCluster(ASTPtr query_ptr)
{
T & query = static_cast<T &>(*query_ptr);
query.cluster.clear();
return query_ptr;
}
}; };
} }

View File

@ -19,6 +19,19 @@ namespace ErrorCodes
extern const int NOT_IMPLEMENTED; extern const int NOT_IMPLEMENTED;
} }
ASTPtr createDatabaseAndTableNode(const String & database_name, const String & table_name)
{
if (database_name.empty())
return ASTIdentifier::createSpecial(table_name);
ASTPtr database = ASTIdentifier::createSpecial(database_name);
ASTPtr table = ASTIdentifier::createSpecial(table_name);
ASTPtr database_and_table = ASTIdentifier::createSpecial(database_name + "." + table_name);
database_and_table->children = {database, table};
return database_and_table;
}
ASTPtr ASTSelectQuery::clone() const ASTPtr ASTSelectQuery::clone() const
{ {
@ -242,46 +255,6 @@ static const ASTTablesInSelectQueryElement * getFirstTableJoin(const ASTSelectQu
} }
ASTPtr ASTSelectQuery::database() const
{
const ASTTableExpression * table_expression = getFirstTableExpression(*this);
if (!table_expression || !table_expression->database_and_table_name || table_expression->database_and_table_name->children.empty())
return {};
if (table_expression->database_and_table_name->children.size() != 2)
throw Exception("Logical error: more than two components in table expression", ErrorCodes::LOGICAL_ERROR);
return table_expression->database_and_table_name->children[0];
}
ASTPtr ASTSelectQuery::table() const
{
const ASTTableExpression * table_expression = getFirstTableExpression(*this);
if (!table_expression)
return {};
if (table_expression->database_and_table_name)
{
if (table_expression->database_and_table_name->children.empty())
return table_expression->database_and_table_name;
if (table_expression->database_and_table_name->children.size() != 2)
throw Exception("Logical error: more than two components in table expression", ErrorCodes::LOGICAL_ERROR);
return table_expression->database_and_table_name->children[1];
}
if (table_expression->table_function)
return table_expression->table_function;
if (table_expression->subquery)
return static_cast<const ASTSubquery *>(table_expression->subquery.get())->children.at(0);
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
}
ASTPtr ASTSelectQuery::sample_size() const ASTPtr ASTSelectQuery::sample_size() const
{ {
const ASTTableExpression * table_expression = getFirstTableExpression(*this); const ASTTableExpression * table_expression = getFirstTableExpression(*this);
@ -363,12 +336,9 @@ void ASTSelectQuery::setDatabaseIfNeeded(const String & database_name)
} }
else if (table_expression->database_and_table_name->children.empty()) else if (table_expression->database_and_table_name->children.empty())
{ {
ASTPtr database = ASTIdentifier::createSpecial(database_name); const ASTIdentifier & identifier = static_cast<const ASTIdentifier &>(*table_expression->database_and_table_name);
ASTPtr table = table_expression->database_and_table_name;
const String & old_name = static_cast<ASTIdentifier &>(*table_expression->database_and_table_name).name; table_expression->database_and_table_name = createDatabaseAndTableNode(database_name, identifier.name);
table_expression->database_and_table_name = ASTIdentifier::createSpecial(database_name + "." + old_name);
table_expression->database_and_table_name->children = {database, table};
} }
else if (table_expression->database_and_table_name->children.size() != 2) else if (table_expression->database_and_table_name->children.size() != 2)
{ {
@ -396,19 +366,7 @@ void ASTSelectQuery::replaceDatabaseAndTable(const String & database_name, const
table_expression = table_expr.get(); table_expression = table_expr.get();
} }
ASTPtr table = ASTIdentifier::createSpecial(table_name); table_expression->database_and_table_name = createDatabaseAndTableNode(database_name, table_name);
if (!database_name.empty())
{
ASTPtr database = ASTIdentifier::createSpecial(database_name);
table_expression->database_and_table_name = ASTIdentifier::createSpecial(database_name + "." + table_name);
table_expression->database_and_table_name->children = {database, table};
}
else
{
table_expression->database_and_table_name = ASTIdentifier::createSpecial(table_name);
}
} }

View File

@ -39,8 +39,6 @@ public:
ASTPtr settings; ASTPtr settings;
/// Compatibility with old parser of tables list. TODO remove /// Compatibility with old parser of tables list. TODO remove
ASTPtr database() const;
ASTPtr table() const;
ASTPtr sample_size() const; ASTPtr sample_size() const;
ASTPtr sample_offset() const; ASTPtr sample_offset() const;
ASTPtr array_join_expression_list() const; ASTPtr array_join_expression_list() const;
@ -55,4 +53,7 @@ protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
}; };
ASTPtr createDatabaseAndTableNode(const String & database_name, const String & table_name);
} }

View File

@ -1,4 +1,3 @@
#include <Parsers/ASTIdentifier.h>
#include <Parsers/TablePropertiesQueriesASTs.h> #include <Parsers/TablePropertiesQueriesASTs.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>

View File

@ -1,5 +1,4 @@
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTInsertQuery.h> #include <Parsers/ASTInsertQuery.h>

View File

@ -4,7 +4,6 @@
#include <Parsers/ASTOptimizeQuery.h> #include <Parsers/ASTOptimizeQuery.h>
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>

View File

@ -1,6 +1,5 @@
#include <memory> #include <memory>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/IParserBase.h> #include <Parsers/IParserBase.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>

View File

@ -1,8 +1,6 @@
#include <Parsers/ParserSystemQuery.h> #include <Parsers/ParserSystemQuery.h>
#include <Parsers/ASTSystemQuery.h> #include <Parsers/ASTSystemQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/parseDatabaseAndTableName.h> #include <Parsers/parseDatabaseAndTableName.h>

View File

@ -2,7 +2,6 @@
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTTablesInSelectQuery.h> #include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/ParserSelectQuery.h> #include <Parsers/ParserSelectQuery.h>
#include <Parsers/ParserSampleRatio.h> #include <Parsers/ParserSampleRatio.h>

View File

@ -19,7 +19,6 @@
#include <Interpreters/InterpreterInsertQuery.h> #include <Interpreters/InterpreterInsertQuery.h>
#include <Interpreters/evaluateConstantExpression.h> #include <Interpreters/evaluateConstantExpression.h>
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTInsertQuery.h> #include <Parsers/ASTInsertQuery.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTCreateQuery.h> #include <Parsers/ASTCreateQuery.h>

View File

@ -10,6 +10,7 @@
#include <Interpreters/convertFieldToType.h> #include <Interpreters/convertFieldToType.h>
#include <Interpreters/Set.h> #include <Interpreters/Set.h>
#include <Parsers/queryToString.h> #include <Parsers/queryToString.h>
#include <Parsers/ASTLiteral.h>
namespace DB namespace DB

View File

@ -10,7 +10,6 @@
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <Parsers/ASTLiteral.h>
#include <Storages/SelectQueryInfo.h> #include <Storages/SelectQueryInfo.h>

View File

@ -6,7 +6,6 @@
#include <Storages/StorageMergeTree.h> #include <Storages/StorageMergeTree.h>
#include <Storages/StorageReplicatedMergeTree.h> #include <Storages/StorageReplicatedMergeTree.h>
#include <Storages/AlterCommands.h> #include <Storages/AlterCommands.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTNameTypePair.h> #include <Parsers/ASTNameTypePair.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>

View File

@ -8,6 +8,7 @@
#include <Storages/MergeTree/MergeTreeThreadBlockInputStream.h> #include <Storages/MergeTree/MergeTreeThreadBlockInputStream.h>
#include <Storages/MergeTree/KeyCondition.h> #include <Storages/MergeTree/KeyCondition.h>
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <Parsers/ASTSampleRatio.h> #include <Parsers/ASTSampleRatio.h>

View File

@ -1,4 +1,3 @@
#include <Storages/MergeTree/RangesInDataPart.h>
#include <Storages/MergeTree/MergeTreeReadPool.h> #include <Storages/MergeTree/MergeTreeReadPool.h>
#include <ext/range.h> #include <ext/range.h>
#include <Storages/MergeTree/MergeTreeBaseBlockInputStream.h> #include <Storages/MergeTree/MergeTreeBaseBlockInputStream.h>
@ -10,6 +9,11 @@ namespace ProfileEvents
extern const Event ReadBackoff; extern const Event ReadBackoff;
} }
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
namespace DB namespace DB
{ {
@ -22,8 +26,13 @@ MergeTreeReadPool::MergeTreeReadPool(
const bool do_not_steal_tasks) const bool do_not_steal_tasks)
: backoff_settings{backoff_settings}, backoff_state{threads}, data{data}, : backoff_settings{backoff_settings}, backoff_state{threads}, data{data},
column_names{column_names}, do_not_steal_tasks{do_not_steal_tasks}, column_names{column_names}, do_not_steal_tasks{do_not_steal_tasks},
predict_block_size_bytes{preferred_block_size_bytes > 0}, prewhere_info{prewhere_info} predict_block_size_bytes{preferred_block_size_bytes > 0}, prewhere_info{prewhere_info}, parts_ranges{parts}
{ {
/// reverse from right-to-left to left-to-right
/// because 'reverse' was done in MergeTreeDataSelectExecutor
for (auto & part_ranges : parts_ranges)
std::reverse(std::begin(part_ranges.ranges), std::end(part_ranges.ranges));
/// parts don't contain duplicate MergeTreeDataPart's. /// parts don't contain duplicate MergeTreeDataPart's.
const auto per_part_sum_marks = fillPerPartInfo(parts, prewhere_info, check_columns); const auto per_part_sum_marks = fillPerPartInfo(parts, prewhere_info, check_columns);
fillPerThreadInfo(threads, sum_marks, per_part_sum_marks, parts, min_marks_for_concurrent_read); fillPerThreadInfo(threads, sum_marks, per_part_sum_marks, parts, min_marks_for_concurrent_read);
@ -120,6 +129,27 @@ MergeTreeReadTaskPtr MergeTreeReadPool::getTask(const size_t min_marks_to_read,
prewhere_info && prewhere_info->remove_prewhere_column, per_part_should_reorder[part_idx], std::move(curr_task_size_predictor)); prewhere_info && prewhere_info->remove_prewhere_column, per_part_should_reorder[part_idx], std::move(curr_task_size_predictor));
} }
MarkRanges MergeTreeReadPool::getRestMarks(const std::string & part_path, const MarkRange & from) const
{
MarkRanges all_part_ranges;
for (const auto & part_ranges : parts_ranges)
{
if (part_ranges.data_part->getFullPath() == part_path)
{
all_part_ranges = part_ranges.ranges;
break;
}
}
if (all_part_ranges.empty())
throw Exception("Trying to read marks range [" + std::to_string(from.begin) + ", " + std::to_string(from.end) + "] from part '"
+ part_path + "' which has no ranges in this query", ErrorCodes::LOGICAL_ERROR);
auto begin = std::lower_bound(all_part_ranges.begin(), all_part_ranges.end(), from, [] (const auto & f, const auto & s) { return f.begin < s.begin; });
if (begin == all_part_ranges.end())
begin = std::prev(all_part_ranges.end());
begin->begin = from.begin;
return MarkRanges(begin, all_part_ranges.end());
}
Block MergeTreeReadPool::getHeader() const Block MergeTreeReadPool::getHeader() const
{ {

View File

@ -80,6 +80,9 @@ public:
*/ */
void profileFeedback(const ReadBufferFromFileBase::ProfileInfo info); void profileFeedback(const ReadBufferFromFileBase::ProfileInfo info);
/// This method tells which mark ranges we have to read if we start from @from mark range
MarkRanges getRestMarks(const std::string & part_path, const MarkRange & from) const;
Block getHeader() const; Block getHeader() const;
private: private:
@ -127,6 +130,8 @@ private:
std::set<size_t> remaining_thread_tasks; std::set<size_t> remaining_thread_tasks;
RangesInDataParts parts_ranges;
mutable std::mutex mutex; mutable std::mutex mutex;
Logger * log = &Logger::get("MergeTreeReadPool"); Logger * log = &Logger::get("MergeTreeReadPool");

View File

@ -149,7 +149,7 @@ struct MergeTreeSettings
M(SettingUInt64, finished_mutations_to_keep, 100) \ M(SettingUInt64, finished_mutations_to_keep, 100) \
\ \
/** Minimal amount of bytes to enable O_DIRECT in merge (0 - disabled) */ \ /** Minimal amount of bytes to enable O_DIRECT in merge (0 - disabled) */ \
M(SettingUInt64, min_merge_bytes_to_use_direct_io, 0) M(SettingUInt64, min_merge_bytes_to_use_direct_io, 10ULL * 1024 * 1024 * 1024)
/// Settings that should not change after the creation of a table. /// Settings that should not change after the creation of a table.
#define APPLY_FOR_IMMUTABLE_MERGE_TREE_SETTINGS(M) \ #define APPLY_FOR_IMMUTABLE_MERGE_TREE_SETTINGS(M) \

View File

@ -65,50 +65,49 @@ bool MergeTreeThreadBlockInputStream::getNewTask()
} }
const std::string path = task->data_part->getFullPath(); const std::string path = task->data_part->getFullPath();
size_t current_task_first_mark = task->mark_ranges[0].begin;
size_t current_task_end_mark = task->mark_ranges.back().end;
/// Allows pool to reduce number of threads in case of too slow reads. /// Allows pool to reduce number of threads in case of too slow reads.
auto profile_callback = [this](ReadBufferFromFileBase::ProfileInfo info) { pool->profileFeedback(info); }; auto profile_callback = [this](ReadBufferFromFileBase::ProfileInfo info) { pool->profileFeedback(info); };
if (!reader) if (!reader)
{ {
auto rest_mark_ranges = pool->getRestMarks(path, task->mark_ranges[0]);
if (use_uncompressed_cache) if (use_uncompressed_cache)
owned_uncompressed_cache = storage.context.getUncompressedCache(); owned_uncompressed_cache = storage.context.getUncompressedCache();
owned_mark_cache = storage.context.getMarkCache(); owned_mark_cache = storage.context.getMarkCache();
reader = std::make_unique<MergeTreeReader>( reader = std::make_unique<MergeTreeReader>(
path, task->data_part, task->columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache, path, task->data_part, task->columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache,
storage, task->mark_ranges, min_bytes_to_use_direct_io, max_read_buffer_size, MergeTreeReader::ValueSizeMap{}, profile_callback); storage, rest_mark_ranges, min_bytes_to_use_direct_io, max_read_buffer_size, MergeTreeReader::ValueSizeMap{}, profile_callback);
if (prewhere_info) if (prewhere_info)
pre_reader = std::make_unique<MergeTreeReader>( pre_reader = std::make_unique<MergeTreeReader>(
path, task->data_part, task->pre_columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache, path, task->data_part, task->pre_columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache,
storage, task->mark_ranges, min_bytes_to_use_direct_io, storage, rest_mark_ranges, min_bytes_to_use_direct_io,
max_read_buffer_size, MergeTreeReader::ValueSizeMap{}, profile_callback); max_read_buffer_size, MergeTreeReader::ValueSizeMap{}, profile_callback);
} }
else else
{ {
/// in other case we can reuse readers, they stopped exactly at required position /// in other case we can reuse readers, anyway they will be "seeked" to required mark
if (last_task_end_mark != current_task_first_mark || path != last_readed_part_path) if (path != last_readed_part_path)
{ {
auto rest_mark_ranges = pool->getRestMarks(path, task->mark_ranges[0]);
/// retain avg_value_size_hints /// retain avg_value_size_hints
reader = std::make_unique<MergeTreeReader>( reader = std::make_unique<MergeTreeReader>(
path, task->data_part, task->columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache, path, task->data_part, task->columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache,
storage, task->mark_ranges, min_bytes_to_use_direct_io, max_read_buffer_size, storage, rest_mark_ranges, min_bytes_to_use_direct_io, max_read_buffer_size,
reader->getAvgValueSizeHints(), profile_callback); reader->getAvgValueSizeHints(), profile_callback);
if (prewhere_info) if (prewhere_info)
pre_reader = std::make_unique<MergeTreeReader>( pre_reader = std::make_unique<MergeTreeReader>(
path, task->data_part, task->pre_columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache, path, task->data_part, task->pre_columns, owned_uncompressed_cache.get(), owned_mark_cache.get(), save_marks_in_cache,
storage, task->mark_ranges, min_bytes_to_use_direct_io, storage, rest_mark_ranges, min_bytes_to_use_direct_io,
max_read_buffer_size, pre_reader->getAvgValueSizeHints(), profile_callback); max_read_buffer_size, pre_reader->getAvgValueSizeHints(), profile_callback);
} }
} }
last_readed_part_path = path; last_readed_part_path = path;
last_task_end_mark = current_task_end_mark;
return true; return true;
} }

View File

@ -44,8 +44,6 @@ private:
std::shared_ptr<MergeTreeReadPool> pool; std::shared_ptr<MergeTreeReadPool> pool;
size_t min_marks_to_read; size_t min_marks_to_read;
/// Last readed mark in task for this thread
size_t last_task_end_mark;
/// Last part readed in this thread /// Last part readed in this thread
std::string last_readed_part_path; std::string last_readed_part_path;
/// Names from header. Used in order to order columns in read blocks. /// Names from header. Used in order to order columns in read blocks.

View File

@ -4,7 +4,6 @@
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/ParserAlterQuery.h> #include <Parsers/ParserAlterQuery.h>
#include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTAssignment.h> #include <Parsers/ASTAssignment.h>
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>

View File

@ -16,7 +16,6 @@
#include <Parsers/ASTInsertQuery.h> #include <Parsers/ASTInsertQuery.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/TablePropertiesQueriesASTs.h> #include <Parsers/TablePropertiesQueriesASTs.h>
#include <Parsers/ParserAlterQuery.h> #include <Parsers/ParserAlterQuery.h>
#include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>

View File

@ -1,7 +1,6 @@
#include <Storages/StorageFactory.h> #include <Storages/StorageFactory.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTCreateQuery.h> #include <Parsers/ASTCreateQuery.h>
#include <Common/Exception.h> #include <Common/Exception.h>
#include <Common/StringUtils/StringUtils.h> #include <Common/StringUtils/StringUtils.h>

View File

@ -2,11 +2,11 @@
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTCreateQuery.h> #include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTDropQuery.h> #include <Parsers/ASTDropQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/InterpreterCreateQuery.h> #include <Interpreters/InterpreterCreateQuery.h>
#include <Interpreters/InterpreterDropQuery.h> #include <Interpreters/InterpreterDropQuery.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Storages/StorageMaterializedView.h> #include <Storages/StorageMaterializedView.h>
#include <Storages/StorageFactory.h> #include <Storages/StorageFactory.h>
@ -27,23 +27,25 @@ namespace ErrorCodes
static void extractDependentTable(ASTSelectQuery & query, String & select_database_name, String & select_table_name) static void extractDependentTable(ASTSelectQuery & query, String & select_database_name, String & select_table_name)
{ {
auto query_table = query.table(); auto db_and_table = getDatabaseAndTable(query, 0);
ASTPtr subquery = getTableFunctionOrSubquery(query, 0);
if (!query_table) if (!db_and_table && !subquery)
return; return;
if (auto ast_id = typeid_cast<const ASTIdentifier *>(query_table.get())) if (db_and_table)
{ {
auto query_database = query.database(); select_table_name = db_and_table->table;
if (!query_database) if (db_and_table->database.empty())
{
db_and_table->database = select_database_name;
query.setDatabaseIfNeeded(select_database_name); query.setDatabaseIfNeeded(select_database_name);
}
select_table_name = ast_id->name; else
select_database_name = query_database ? typeid_cast<const ASTIdentifier &>(*query_database).name : select_database_name; select_database_name = db_and_table->database;
} }
else if (auto ast_select = typeid_cast<ASTSelectWithUnionQuery *>(query_table.get())) else if (auto ast_select = typeid_cast<ASTSelectWithUnionQuery *>(subquery.get()))
{ {
if (ast_select->list_of_selects->children.size() != 1) if (ast_select->list_of_selects->children.size() != 1)
throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW);
@ -64,12 +66,11 @@ static void checkAllowedQueries(const ASTSelectQuery & query)
if (query.prewhere_expression || query.final() || query.sample_size()) if (query.prewhere_expression || query.final() || query.sample_size())
throw Exception("MATERIALIZED VIEW cannot have PREWHERE, SAMPLE or FINAL.", DB::ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); throw Exception("MATERIALIZED VIEW cannot have PREWHERE, SAMPLE or FINAL.", DB::ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW);
auto query_table = query.table(); ASTPtr subquery = getTableFunctionOrSubquery(query, 0);
if (!subquery)
if (!query_table)
return; return;
if (auto ast_select = typeid_cast<const ASTSelectWithUnionQuery *>(query_table.get())) if (auto ast_select = typeid_cast<const ASTSelectWithUnionQuery *>(subquery.get()))
{ {
if (ast_select->list_of_selects->children.size() != 1) if (ast_select->list_of_selects->children.size() != 1)
throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW); throw Exception("UNION is not supported for MATERIALIZED VIEW", ErrorCodes::QUERY_IS_NOT_SUPPORTED_IN_MATERIALIZED_VIEW);

View File

@ -15,7 +15,6 @@
#include <Interpreters/InterpreterSelectQuery.h> #include <Interpreters/InterpreterSelectQuery.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <DataTypes/DataTypeString.h> #include <DataTypes/DataTypeString.h>
#include <Columns/ColumnString.h> #include <Columns/ColumnString.h>

View File

@ -3,7 +3,6 @@
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/evaluateConstantExpression.h> #include <Interpreters/evaluateConstantExpression.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <IO/ReadWriteBufferFromHTTP.h> #include <IO/ReadWriteBufferFromHTTP.h>

View File

@ -1,5 +1,16 @@
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/StorageSystemContributors.generated.cpp)
execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/StorageSystemContributors.sh)
endif()
set (CONFIG_BUILD ${CMAKE_CURRENT_BINARY_DIR}/StorageSystemBuildOptions.generated.cpp)
get_property (BUILD_COMPILE_DEFINITIONS DIRECTORY ${ClickHouse_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
get_property (BUILD_INCLUDE_DIRECTORIES DIRECTORY ${ClickHouse_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
string (TIMESTAMP BUILD_DATE "%Y-%m-%d" UTC)
configure_file (StorageSystemBuildOptions.generated.cpp.in ${CONFIG_BUILD})
include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake) include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake)
add_headers_and_sources(storages_system .) add_headers_and_sources(storages_system .)
list (APPEND storages_system_sources ${CONFIG_BUILD})
add_library(clickhouse_storages_system ${LINK_MODE} ${storages_system_headers} ${storages_system_sources}) add_library(clickhouse_storages_system ${LINK_MODE} ${storages_system_headers} ${storages_system_sources})
target_link_libraries(clickhouse_storages_system dbms) target_link_libraries(clickhouse_storages_system dbms)
target_include_directories(clickhouse_storages_system PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -1,7 +1,9 @@
#include <Common/config_build.h> #include "StorageSystemBuildOptions.h"
#include <DataTypes/DataTypeString.h> #include <DataTypes/DataTypeString.h>
#include <Interpreters/Settings.h> #include <Interpreters/Settings.h>
#include <Storages/System/StorageSystemBuildOptions.h>
extern const char * auto_config_build[];
namespace DB namespace DB
{ {

View File

@ -1,7 +1,5 @@
// .cpp autogenerated by cmake // .cpp autogenerated by cmake
#include <Common/config_build.h>
const char * auto_config_build[] const char * auto_config_build[]
{ {
"VERSION_FULL", "@VERSION_FULL@", "VERSION_FULL", "@VERSION_FULL@",

View File

@ -11,7 +11,6 @@
#include <Storages/VirtualColumnUtils.h> #include <Storages/VirtualColumnUtils.h>
#include <Parsers/queryToString.h> #include <Parsers/queryToString.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Databases/IDatabase.h> #include <Databases/IDatabase.h>

View File

@ -0,0 +1,36 @@
#if __has_include("StorageSystemContributors.generated.cpp")
#include "StorageSystemContributors.h"
#include <algorithm>
#include <pcg_random.hpp>
#include <DataTypes/DataTypeString.h>
#include <Common/randomSeed.h>
extern const char * auto_contributors[];
namespace DB
{
NamesAndTypesList StorageSystemContributors::getNamesAndTypes()
{
return {
{"name", std::make_shared<DataTypeString>()},
};
}
void StorageSystemContributors::fillData(MutableColumns & res_columns, const Context &, const SelectQueryInfo &) const
{
std::vector<const char *> contributors;
for (auto it = auto_contributors; *it; ++it)
contributors.emplace_back(*it);
pcg64 rng(randomSeed());
std::shuffle(contributors.begin(), contributors.end(), rng);
for (auto & it : contributors)
res_columns[0]->insert(String(it));
}
}
#endif

View File

@ -0,0 +1,34 @@
#pragma once
#if __has_include("StorageSystemContributors.generated.cpp")
#include <Storages/System/IStorageSystemOneBlock.h>
#include <ext/shared_ptr_helper.h>
namespace DB
{
class Context;
/** System table "contributors" with list of clickhouse contributors
*/
class StorageSystemContributors : public ext::shared_ptr_helper<StorageSystemContributors>,
public IStorageSystemOneBlock<StorageSystemContributors>
{
protected:
void fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo & query_info) const override;
using IStorageSystemOneBlock::IStorageSystemOneBlock;
public:
std::string getName() const override
{
return "SystemContributors";
}
static NamesAndTypesList getNamesAndTypes();
};
}
#endif

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
CONTRIBUTORS_FILE=${CONTRIBUTORS_FILE=$CUR_DIR/StorageSystemContributors.generated.cpp}
git shortlog --summary | perl -lnE 's/^\s+\d+\s+(.+)/"$1",/; next unless $1; say $_' > $CONTRIBUTORS_FILE.tmp
# If git history not available - dont make target file
if [ ! -s $CONTRIBUTORS_FILE.tmp ]; then
exit
fi
echo "// autogenerated by $0" > $CONTRIBUTORS_FILE
echo "const char * auto_contributors[] {" >> $CONTRIBUTORS_FILE
cat $CONTRIBUTORS_FILE.tmp >> $CONTRIBUTORS_FILE
echo "nullptr };" >> $CONTRIBUTORS_FILE
rm $CONTRIBUTORS_FILE.tmp

View File

@ -32,6 +32,9 @@
#include <Storages/System/StorageSystemTableFunctions.h> #include <Storages/System/StorageSystemTableFunctions.h>
#include <Storages/System/StorageSystemTables.h> #include <Storages/System/StorageSystemTables.h>
#include <Storages/System/StorageSystemZooKeeper.h> #include <Storages/System/StorageSystemZooKeeper.h>
#if __has_include("StorageSystemContributors.generated.cpp")
# include <Storages/System/StorageSystemContributors.h>
#endif
namespace DB namespace DB
@ -56,6 +59,9 @@ void attachSystemTablesLocal(IDatabase & system_database)
system_database.attachTable("data_type_families", StorageSystemDataTypeFamilies::create("data_type_families")); system_database.attachTable("data_type_families", StorageSystemDataTypeFamilies::create("data_type_families"));
system_database.attachTable("collations", StorageSystemCollations::create("collations")); system_database.attachTable("collations", StorageSystemCollations::create("collations"));
system_database.attachTable("table_engines", StorageSystemTableEngines::create("table_engines")); system_database.attachTable("table_engines", StorageSystemTableEngines::create("table_engines"));
#if __has_include("StorageSystemContributors.generated.cpp")
system_database.attachTable("contributors", StorageSystemContributors::create("contributors"));
#endif
} }
void attachSystemTablesServer(IDatabase & system_database, bool has_zookeeper) void attachSystemTablesServer(IDatabase & system_database, bool has_zookeeper)

View File

@ -119,16 +119,23 @@ String transformQueryForExternalDatabase(
{ {
if (function->name == "and") if (function->name == "and")
{ {
bool compatible_found = false;
auto new_function_and = std::make_shared<ASTFunction>(); auto new_function_and = std::make_shared<ASTFunction>();
auto new_function_and_arguments = std::make_shared<ASTExpressionList>(); auto new_function_and_arguments = std::make_shared<ASTExpressionList>();
new_function_and->arguments = new_function_and_arguments; new_function_and->arguments = new_function_and_arguments;
new_function_and->children.push_back(new_function_and_arguments); new_function_and->children.push_back(new_function_and_arguments);
for (const auto & elem : function->arguments->children) for (const auto & elem : function->arguments->children)
{
if (isCompatible(*elem)) if (isCompatible(*elem))
{
new_function_and_arguments->children.push_back(elem); new_function_and_arguments->children.push_back(elem);
compatible_found = true;
}
}
select->where_expression = std::move(new_function_and); if (compatible_found)
select->where_expression = std::move(new_function_and);
} }
} }
} }

View File

@ -3,7 +3,6 @@
#include <Storages/StorageMerge.h> #include <Storages/StorageMerge.h>
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <TableFunctions/ITableFunction.h> #include <TableFunctions/ITableFunction.h>

View File

@ -27,7 +27,7 @@ if (ENABLE_TESTS)
# maybe add --no-long ? # maybe add --no-long ?
# if you want disable some tests: env TEST_OPT0='--skip compile' # if you want disable some tests: env TEST_OPT0='--skip compile'
add_test(NAME with_server COMMAND bash -c "env BUILD_DIR=${ClickHouse_BINARY_DIR} INTERNAL_COMPILER_BIN_ROOT=${INTERNAL_COMPILER_BIN_ROOT} ${CMAKE_CURRENT_SOURCE_DIR}/clickhouse-test-server") add_test(NAME with_server COMMAND bash -c "env BUILD_DIR=${ClickHouse_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/clickhouse-test-server")
endif () endif ()
if (ENABLE_TEST_INTEGRATION) if (ENABLE_TEST_INTEGRATION)

View File

@ -242,7 +242,7 @@ def main(args):
stderr_element = et.Element("system-err") stderr_element = et.Element("system-err")
stderr_element.text = et.CDATA(stderr) stderr_element.text = et.CDATA(stderr)
report_testcase.append(stderr_element) report_testcase.append(stderr_element)
print(stderr) print(stderr.encode('utf-8'))
if args.stop and ('Connection refused' in stderr or 'Attempt to read after eof' in stderr) and not 'Received exception from server' in stderr: if args.stop and ('Connection refused' in stderr or 'Attempt to read after eof' in stderr) and not 'Received exception from server' in stderr:
SERVER_DIED = True SERVER_DIED = True

View File

@ -141,10 +141,17 @@ def generate_structure(args):
base_name = 'range_hashed_' + range_hashed_range_type base_name = 'range_hashed_' + range_hashed_range_type
dictionaries.extend([ dictionaries.extend([
[ 'file_' + base_name, 3, False ], [ 'file_' + base_name, 3, False ],
# [ 'clickhouse_' + base_name, 3, True ], [ 'clickhouse_' + base_name, 3, False ],
# [ 'executable_flat' + base_name, 3, True ] # [ 'executable_flat' + base_name, 3, True ]
]) ])
if not args.no_mysql:
for range_hashed_range_type in range_hashed_range_types:
base_name = 'range_hashed_' + range_hashed_range_type
dictionaries.extend([
['mysql_' + base_name, 3, False],
])
files = [ 'key_simple.tsv', 'key_complex_integers.tsv', 'key_complex_mixed.tsv', 'key_range_hashed_{range_hashed_range_type}.tsv' ] files = [ 'key_simple.tsv', 'key_complex_integers.tsv', 'key_complex_mixed.tsv', 'key_range_hashed_{range_hashed_range_type}.tsv' ]
@ -206,6 +213,36 @@ range_hashed_dictGet_values = {
("toDateTime('2015-11-19 23:59:59')", "toDateTime('2015-10-26 00:00:01')", "toDateTime('2018-09-14 00:00:00')")], ("toDateTime('2015-11-19 23:59:59')", "toDateTime('2015-10-26 00:00:01')", "toDateTime('2018-09-14 00:00:00')")],
} }
range_hashed_mysql_column_types = {
'UInt8': 'tinyint unsigned',
'UInt16': 'smallint unsigned',
'UInt32': 'int unsigned',
'UInt64': 'bigint unsigned',
'Int8': 'tinyint',
'Int16': 'smallint',
'Int32': 'int',
'Int64': 'bigint',
# default type (Date) for compatibility with older versions:
'': 'date',
'Date': 'date',
'DateTime': 'datetime',
}
range_hashed_clickhouse_column_types = {
'UInt8': 'UInt8',
'UInt16': 'UInt16',
'UInt32': 'UInt32',
'UInt64': 'UInt64',
'Int8': 'Int8',
'Int16': 'Int16',
'Int32': 'Int32',
'Int64': 'Int64',
# default type (Date) for compatibility with older versions:
'': 'Date',
'Date': 'Date',
'DateTime': 'DateTime',
}
def dump_report(destination, suite, test_case, report): def dump_report(destination, suite, test_case, report):
if destination is not None: if destination is not None:
@ -268,6 +305,41 @@ def generate_data(args):
query = file_source_query % comma_separated(chain(keys, columns(), ['Parent'] if 1 == len(keys) else [])) query = file_source_query % comma_separated(chain(keys, columns(), ['Parent'] if 1 == len(keys) else []))
call([args.client, '--port', args.port, '--query', query], 'generated/' + file) call([args.client, '--port', args.port, '--query', query], 'generated/' + file)
table_name = "test.dictionary_source_" + range_hashed_range_type
col_type = range_hashed_clickhouse_column_types[range_hashed_range_type]
source_tsv_full_path = "{0}/generated/{1}".format(prefix, file)
print 'Creating Clickhouse table for "{0}" range_hashed dictionary...'.format(range_hashed_range_type)
system('cat {source} | {ch} --port={port} -m -n --query "'
'create database if not exists test;'
'drop table if exists {table_name};'
'create table {table_name} ('
'id UInt64, StartDate {col_type}, EndDate {col_type},'
'UInt8_ UInt8, UInt16_ UInt16, UInt32_ UInt32, UInt64_ UInt64,'
'Int8_ Int8, Int16_ Int16, Int32_ Int32, Int64_ Int64,'
'Float32_ Float32, Float64_ Float64,'
'String_ String,'
'Date_ Date, DateTime_ DateTime, UUID_ UUID'
') engine=Log; insert into {table_name} format TabSeparated'
'"'.format(table_name=table_name, col_type=col_type, source=source_tsv_full_path, ch=args.client, port=args.port))
if not args.no_mysql:
print 'Creating MySQL table for "{0}" range_hashed dictionary...'.format(range_hashed_range_type)
col_type = range_hashed_mysql_column_types[range_hashed_range_type]
subprocess.check_call('echo "'
'create database if not exists test;'
'drop table if exists {table_name};'
'create table {table_name} ('
'id tinyint unsigned, StartDate {col_type}, EndDate {col_type}, '
'UInt8_ tinyint unsigned, UInt16_ smallint unsigned, UInt32_ int unsigned, UInt64_ bigint unsigned, '
'Int8_ tinyint, Int16_ smallint, Int32_ int, Int64_ bigint, '
'Float32_ float, Float64_ double, '
'String_ text, Date_ date, DateTime_ datetime, UUID_ varchar(36)'
');'
'load data local infile \'{source}\' into table {table_name};" | mysql $MYSQL_OPTIONS --local-infile=1'
.format(prefix, table_name=table_name, col_type=col_type, source=source_tsv_full_path), shell=True)
# create MySQL table from complete_query # create MySQL table from complete_query
if not args.no_mysql: if not args.no_mysql:
print 'Creating MySQL table' print 'Creating MySQL table'
@ -365,7 +437,7 @@ def generate_dictionaries(args):
<user>default</user> <user>default</user>
<password></password> <password></password>
<db>test</db> <db>test</db>
<table>dictionary_source</table> <table>dictionary_source{key_type}</table>
</clickhouse> </clickhouse>
''' % args.port ''' % args.port
@ -384,7 +456,7 @@ def generate_dictionaries(args):
<user>root</user> <user>root</user>
<password></password> <password></password>
<db>test</db> <db>test</db>
<table>dictionary_source</table> <table>dictionary_source{key_type}</table>
</mysql> </mysql>
''' '''
@ -518,33 +590,34 @@ def generate_dictionaries(args):
</attribute> </attribute>
''' '''
source_clickhouse_deafult = source_clickhouse.format(key_type="")
sources_and_layouts = [ sources_and_layouts = [
# Simple key dictionaries # Simple key dictionaries
[ source_file % (generated_prefix + files[0]), layout_flat], [ source_file % (generated_prefix + files[0]), layout_flat],
[ source_clickhouse, layout_flat ], [ source_clickhouse_deafult, layout_flat ],
[ source_executable % (generated_prefix + files[0]), layout_flat ], [ source_executable % (generated_prefix + files[0]), layout_flat ],
[ source_file % (generated_prefix + files[0]), layout_hashed], [ source_file % (generated_prefix + files[0]), layout_hashed],
[ source_clickhouse, layout_hashed ], [ source_clickhouse_deafult, layout_hashed ],
[ source_executable % (generated_prefix + files[0]), layout_hashed ], [ source_executable % (generated_prefix + files[0]), layout_hashed ],
[ source_clickhouse, layout_cache ], [ source_clickhouse_deafult, layout_cache ],
[ source_executable_cache % (generated_prefix + files[0]), layout_cache ], [ source_executable_cache % (generated_prefix + files[0]), layout_cache ],
# Complex key dictionaries with (UInt8, UInt8) key # Complex key dictionaries with (UInt8, UInt8) key
[ source_file % (generated_prefix + files[1]), layout_complex_key_hashed], [ source_file % (generated_prefix + files[1]), layout_complex_key_hashed],
[ source_clickhouse, layout_complex_key_hashed ], [ source_clickhouse_deafult, layout_complex_key_hashed ],
[ source_executable % (generated_prefix + files[1]), layout_complex_key_hashed ], [ source_executable % (generated_prefix + files[1]), layout_complex_key_hashed ],
[ source_clickhouse, layout_complex_key_cache ], [ source_clickhouse_deafult, layout_complex_key_cache ],
[ source_executable_cache % (generated_prefix + files[1]), layout_complex_key_cache ], [ source_executable_cache % (generated_prefix + files[1]), layout_complex_key_cache ],
# Complex key dictionaries with (String, UInt8) key # Complex key dictionaries with (String, UInt8) key
[ source_file % (generated_prefix + files[2]), layout_complex_key_hashed], [ source_file % (generated_prefix + files[2]), layout_complex_key_hashed],
[ source_clickhouse, layout_complex_key_hashed ], [ source_clickhouse_deafult, layout_complex_key_hashed ],
[ source_executable % (generated_prefix + files[2]), layout_complex_key_hashed ], [ source_executable % (generated_prefix + files[2]), layout_complex_key_hashed ],
[ source_clickhouse, layout_complex_key_cache ], [ source_clickhouse_deafult, layout_complex_key_cache ],
[ source_executable_cache % (generated_prefix + files[2]), layout_complex_key_cache ], [ source_executable_cache % (generated_prefix + files[2]), layout_complex_key_cache ],
] ]
@ -568,14 +641,15 @@ def generate_dictionaries(args):
]) ])
if not args.no_mysql: if not args.no_mysql:
source_mysql_default = source_mysql.format(key_type="")
sources_and_layouts.extend([ sources_and_layouts.extend([
[ source_mysql, layout_flat ], [ source_mysql_default, layout_flat ],
[ source_mysql, layout_hashed ], [ source_mysql_default, layout_hashed ],
[ source_mysql, layout_cache ], [ source_mysql_default, layout_cache ],
[ source_mysql, layout_complex_key_hashed ], [ source_mysql_default, layout_complex_key_hashed ],
[ source_mysql, layout_complex_key_cache ], [ source_mysql_default, layout_complex_key_cache ],
[ source_mysql, layout_complex_key_hashed ], [ source_mysql_default, layout_complex_key_hashed ],
[ source_mysql, layout_complex_key_cache ], [ source_mysql_default, layout_complex_key_cache ],
]) ])
if not args.no_mongo: if not args.no_mongo:
@ -613,16 +687,29 @@ def generate_dictionaries(args):
]) ])
for range_hashed_range_type in range_hashed_range_types: for range_hashed_range_type in range_hashed_range_types:
key_type = "_" + range_hashed_range_type
sources_and_layouts.extend([ sources_and_layouts.extend([
[ source_file % (generated_prefix + (files[3].format(range_hashed_range_type=range_hashed_range_type))), (layout_range_hashed, range_hashed_range_type) ], [ source_file % (generated_prefix + (files[3].format(range_hashed_range_type=range_hashed_range_type))), (layout_range_hashed, range_hashed_range_type) ],
# [ source_clickhouse, layout_range_hashed ], [ source_clickhouse.format(key_type=key_type), (layout_range_hashed, range_hashed_range_type) ],
# [ source_executable, layout_range_hashed ] # [ source_executable, layout_range_hashed ]
]) ])
if not args.no_mysql:
for range_hashed_range_type in range_hashed_range_types:
key_type = "_" + range_hashed_range_type
source_mysql_typed = source_mysql.format(key_type=key_type)
sources_and_layouts.extend([
[source_mysql_typed,
(layout_range_hashed, range_hashed_range_type)],
])
dict_name_filter = args.filter.split('/')[0] if args.filter else None
for (name, key_idx, has_parent), (source, layout) in zip(dictionaries, sources_and_layouts): for (name, key_idx, has_parent), (source, layout) in zip(dictionaries, sources_and_layouts):
if args.filter and not fnmatch.fnmatch(name, dict_name_filter):
continue
filename = os.path.join(args.generated, 'dictionary_%s.xml' % name) filename = os.path.join(args.generated, 'dictionary_%s.xml' % name)
key = keys[key_idx] key = keys[key_idx]
if key_idx == 3: if key_idx == 3:
layout, range_hashed_range_type = layout layout, range_hashed_range_type = layout
# Wrap non-empty type (default) with <type> tag. # Wrap non-empty type (default) with <type> tag.
@ -670,7 +757,7 @@ def run_tests(args):
global SERVER_DIED global SERVER_DIED
print "{0:100}".format('Dictionary: ' + dict + ' Name: ' + name + ": "), print "{0:100}".format('Dictionary: ' + dict + ' Name: ' + name + ": "),
if args.filter and not fnmatch.fnmatch(dict, args.filter) and not fnmatch.fnmatch(name, args.filter): if args.filter and not fnmatch.fnmatch(dict + "/" + name, args.filter):
print " ... skipped due to filter." print " ... skipped due to filter."
return return

View File

@ -0,0 +1,15 @@
<yandex>
<include_from from_env="INCLUDE_FROM_ENV"></include_from>
<profiles>
<default>
<max_query_size incl="mqs" />
</default>
</profiles>
<users>
<default>
<password></password>
<profile>default</profile>
<quota>default</quota>
</default>
</users>
</yandex>

View File

@ -9,6 +9,7 @@ node2 = cluster.add_instance('node2', user_configs=['configs/config_env.xml'], e
node3 = cluster.add_instance('node3', user_configs=['configs/config_zk.xml'], with_zookeeper=True) node3 = cluster.add_instance('node3', user_configs=['configs/config_zk.xml'], with_zookeeper=True)
node4 = cluster.add_instance('node4', user_configs=['configs/config_incl.xml'], main_configs=['configs/max_query_size.xml']) # include value 77777 node4 = cluster.add_instance('node4', user_configs=['configs/config_incl.xml'], main_configs=['configs/max_query_size.xml']) # include value 77777
node5 = cluster.add_instance('node5', user_configs=['configs/config_allow_databases.xml']) node5 = cluster.add_instance('node5', user_configs=['configs/config_allow_databases.xml'])
node6 = cluster.add_instance('node6', user_configs=['configs/config_include_from_env.xml'], env_variables={"INCLUDE_FROM_ENV": "/etc/clickhouse-server/config.d/max_query_size.xml"}, main_configs=['configs/max_query_size.xml'])
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def start_cluster(): def start_cluster():
@ -27,6 +28,7 @@ def test_config(start_cluster):
assert node2.query("select value from system.settings where name = 'max_query_size'") == "55555\n" assert node2.query("select value from system.settings where name = 'max_query_size'") == "55555\n"
assert node3.query("select value from system.settings where name = 'max_query_size'") == "77777\n" assert node3.query("select value from system.settings where name = 'max_query_size'") == "77777\n"
assert node4.query("select value from system.settings where name = 'max_query_size'") == "99999\n" assert node4.query("select value from system.settings where name = 'max_query_size'") == "99999\n"
assert node6.query("select value from system.settings where name = 'max_query_size'") == "99999\n"
def test_allow_databases(start_cluster): def test_allow_databases(start_cluster):
node5.query("CREATE DATABASE db1") node5.query("CREATE DATABASE db1")

Some files were not shown because too many files have changed in this diff Show More