2015-09-04 21:39:10 +00:00
|
|
|
|
#include <Poco/Util/Application.h>
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
#include <DB/DataTypes/FieldToDataType.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Parsers/ASTFunction.h>
|
|
|
|
|
#include <DB/Parsers/ASTIdentifier.h>
|
|
|
|
|
#include <DB/Parsers/ASTLiteral.h>
|
|
|
|
|
#include <DB/Parsers/ASTAsterisk.h>
|
|
|
|
|
#include <DB/Parsers/ASTExpressionList.h>
|
|
|
|
|
#include <DB/Parsers/ASTSelectQuery.h>
|
|
|
|
|
#include <DB/Parsers/ASTSubquery.h>
|
|
|
|
|
#include <DB/Parsers/ASTSet.h>
|
2013-05-27 14:02:55 +00:00
|
|
|
|
#include <DB/Parsers/ASTOrderByElement.h>
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/DataTypes/DataTypeSet.h>
|
|
|
|
|
#include <DB/DataTypes/DataTypeTuple.h>
|
|
|
|
|
#include <DB/DataTypes/DataTypeExpression.h>
|
2013-07-26 13:46:52 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeNested.h>
|
2015-01-14 02:44:25 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
#include <DB/Columns/ColumnSet.h>
|
|
|
|
|
#include <DB/Columns/ColumnExpression.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Interpreters/InterpreterSelectQuery.h>
|
|
|
|
|
#include <DB/Interpreters/ExpressionAnalyzer.h>
|
2016-01-13 00:32:59 +00:00
|
|
|
|
#include <DB/Interpreters/ExpressionActions.h>
|
2015-09-18 13:36:10 +00:00
|
|
|
|
#include <DB/Interpreters/InJoinSubqueriesPreprocessor.h>
|
2015-02-18 09:43:36 +00:00
|
|
|
|
#include <DB/Interpreters/LogicalExpressionsOptimizer.h>
|
2015-05-13 16:11:07 +00:00
|
|
|
|
#include <DB/Interpreters/ExternalDictionaries.h>
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
2015-04-16 06:12:35 +00:00
|
|
|
|
#include <DB/AggregateFunctions/AggregateFunctionFactory.h>
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
#include <DB/Storages/StorageDistributed.h>
|
2014-03-14 14:52:48 +00:00
|
|
|
|
#include <DB/Storages/StorageMemory.h>
|
2015-01-27 00:52:03 +00:00
|
|
|
|
#include <DB/Storages/StorageSet.h>
|
2015-01-28 02:37:05 +00:00
|
|
|
|
#include <DB/Storages/StorageJoin.h>
|
2014-03-14 14:52:48 +00:00
|
|
|
|
|
2015-01-14 02:44:25 +00:00
|
|
|
|
#include <DB/DataStreams/LazyBlockInputStream.h>
|
2014-03-14 14:52:48 +00:00
|
|
|
|
#include <DB/DataStreams/copyData.h>
|
|
|
|
|
|
2015-05-13 16:11:07 +00:00
|
|
|
|
#include <DB/Dictionaries/IDictionary.h>
|
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
#include <DB/Common/typeid_cast.h>
|
|
|
|
|
|
2014-03-14 14:52:48 +00:00
|
|
|
|
#include <DB/Parsers/formatAST.h>
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
2014-12-17 15:26:24 +00:00
|
|
|
|
#include <DB/Functions/FunctionFactory.h>
|
2016-05-03 23:19:14 +00:00
|
|
|
|
#include <DB/Functions/FunctionsTransform.h>
|
|
|
|
|
#include <DB/Functions/FunctionsConditional.h>
|
|
|
|
|
#include <DB/Functions/FunctionsArray.h>
|
2014-12-17 15:26:24 +00:00
|
|
|
|
|
2015-10-05 00:33:43 +00:00
|
|
|
|
#include <ext/range.hpp>
|
2015-12-23 08:11:11 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeFactory.h>
|
2014-12-17 11:53:17 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS;
|
|
|
|
|
extern const int UNKNOWN_IDENTIFIER;
|
|
|
|
|
extern const int CYCLIC_ALIASES;
|
|
|
|
|
extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY;
|
|
|
|
|
extern const int TOO_MUCH_ROWS;
|
|
|
|
|
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
|
|
|
|
extern const int INCORRECT_ELEMENT_OF_SET;
|
|
|
|
|
extern const int ALIAS_REQUIRED;
|
|
|
|
|
extern const int EMPTY_NESTED_TABLE;
|
|
|
|
|
extern const int NOT_AN_AGGREGATE;
|
|
|
|
|
extern const int UNEXPECTED_EXPRESSION;
|
|
|
|
|
extern const int PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS;
|
|
|
|
|
extern const int DUPLICATE_COLUMN;
|
2016-01-13 01:02:10 +00:00
|
|
|
|
extern const int FUNCTION_CANNOT_HAVE_PARAMETERS;
|
2016-03-05 02:30:20 +00:00
|
|
|
|
extern const int ILLEGAL_AGGREGATION;
|
2016-07-26 19:43:58 +00:00
|
|
|
|
extern const int SUPPORT_IS_DISABLED;
|
2016-01-11 21:46:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
2014-07-31 08:14:19 +00:00
|
|
|
|
/** Calls to these functions in the GROUP BY statement would be
|
|
|
|
|
* replaced by their immediate argument.
|
2014-07-31 07:24:07 +00:00
|
|
|
|
*/
|
2014-08-19 23:12:31 +00:00
|
|
|
|
const std::unordered_set<String> injective_function_names
|
|
|
|
|
{
|
2014-07-31 07:24:07 +00:00
|
|
|
|
"negate",
|
|
|
|
|
"bitNot",
|
|
|
|
|
"reverse",
|
|
|
|
|
"reverseUTF8",
|
|
|
|
|
"toString",
|
|
|
|
|
"toFixedString",
|
|
|
|
|
"toStringCutToZero",
|
|
|
|
|
"IPv4NumToString",
|
|
|
|
|
"IPv4StringToNum",
|
|
|
|
|
"hex",
|
|
|
|
|
"unhex",
|
|
|
|
|
"bitmaskToList",
|
|
|
|
|
"bitmaskToArray",
|
|
|
|
|
"tuple",
|
|
|
|
|
"regionToName",
|
2015-10-14 12:46:42 +00:00
|
|
|
|
"concatAssumeInjective",
|
2014-07-31 07:24:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-05-13 16:11:07 +00:00
|
|
|
|
const std::unordered_set<String> possibly_injective_function_names
|
|
|
|
|
{
|
|
|
|
|
"dictGetString",
|
|
|
|
|
"dictGetUInt8",
|
|
|
|
|
"dictGetUInt16",
|
|
|
|
|
"dictGetUInt32",
|
|
|
|
|
"dictGetUInt64",
|
|
|
|
|
"dictGetInt8",
|
|
|
|
|
"dictGetInt16",
|
|
|
|
|
"dictGetInt32",
|
|
|
|
|
"dictGetInt64",
|
|
|
|
|
"dictGetFloat32",
|
|
|
|
|
"dictGetFloat64",
|
|
|
|
|
"dictGetDate",
|
|
|
|
|
"dictGetDateTime"
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-18 13:36:10 +00:00
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
bool functionIsInOperator(const String & name)
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
|
|
|
|
return name == "in" || name == "notIn";
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 13:36:10 +00:00
|
|
|
|
bool functionIsInOrGlobalInOperator(const String & name)
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
|
|
|
|
return name == "in" || name == "notIn" || name == "globalIn" || name == "globalNotIn";
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 23:19:14 +00:00
|
|
|
|
/// Create a function uniquely identified by the first two parameters. If this
|
|
|
|
|
/// function actually is a CASE expression, record this information.
|
|
|
|
|
FunctionPtr getFunctionFromFactory(const String & name, const ASTFunction::Genus genus, const Context & context)
|
|
|
|
|
{
|
|
|
|
|
FunctionPtr function = FunctionFactory::instance().get(name, context);
|
|
|
|
|
|
|
|
|
|
if (genus == ASTFunction::Genus::CASE_WITH_EXPR)
|
|
|
|
|
{
|
|
|
|
|
FunctionTransform * fun_transform = typeid_cast<FunctionTransform *>(&*function);
|
|
|
|
|
if (fun_transform == nullptr)
|
|
|
|
|
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
fun_transform->setCaseMode();
|
|
|
|
|
}
|
|
|
|
|
else if (genus == ASTFunction::Genus::CASE_WITHOUT_EXPR)
|
|
|
|
|
{
|
|
|
|
|
FunctionMultiIf * fun_multi_if = typeid_cast<FunctionMultiIf *>(&*function);
|
|
|
|
|
if (fun_multi_if == nullptr)
|
|
|
|
|
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
fun_multi_if->setCaseMode();
|
|
|
|
|
}
|
|
|
|
|
else if (genus == ASTFunction::Genus::CASE_ARRAY)
|
|
|
|
|
{
|
|
|
|
|
FunctionArray * fun_array = typeid_cast<FunctionArray *>(&*function);
|
|
|
|
|
if (fun_array == nullptr)
|
|
|
|
|
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
fun_array->setCaseMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return function;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 13:36:10 +00:00
|
|
|
|
}
|
2015-07-26 07:08:46 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
void ExpressionAnalyzer::init()
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
select_query = typeid_cast<ASTSelectQuery *>(ast.get());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-09-18 13:36:10 +00:00
|
|
|
|
/// В зависимости от профиля пользователя проверить наличие прав на выполнение
|
|
|
|
|
/// распределённых подзапросов внутри секций IN или JOIN и обработать эти подзапросы.
|
|
|
|
|
InJoinSubqueriesPreprocessor<>(select_query, context, storage).perform();
|
|
|
|
|
|
2015-02-18 16:54:42 +00:00
|
|
|
|
/// Оптимизирует логические выражения.
|
2015-09-29 14:40:23 +00:00
|
|
|
|
LogicalExpressionsOptimizer(select_query, settings).perform();
|
2015-02-16 17:25:44 +00:00
|
|
|
|
|
2014-07-04 19:13:38 +00:00
|
|
|
|
/// Создаёт словарь aliases: alias -> ASTPtr
|
2014-10-03 15:30:10 +00:00
|
|
|
|
addASTAliases(ast);
|
2014-07-04 19:13:38 +00:00
|
|
|
|
|
2014-07-04 20:30:06 +00:00
|
|
|
|
/// Common subexpression elimination. Rewrite rules.
|
2013-05-24 10:49:19 +00:00
|
|
|
|
normalizeTree();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-10-29 15:14:19 +00:00
|
|
|
|
/// ALIAS столбцы не должны подставляться вместо ASTAsterisk, добавим их теперь, после normalizeTree.
|
|
|
|
|
addAliasColumns();
|
|
|
|
|
|
2015-07-25 11:47:50 +00:00
|
|
|
|
/// Выполнение скалярных подзапросов - замена их на значения-константы.
|
|
|
|
|
executeScalarSubqueries();
|
|
|
|
|
|
2014-08-19 23:12:31 +00:00
|
|
|
|
/// GROUP BY injective function elimination.
|
2014-08-04 15:25:38 +00:00
|
|
|
|
optimizeGroupBy();
|
2014-07-31 07:24:07 +00:00
|
|
|
|
|
2015-03-12 03:31:15 +00:00
|
|
|
|
/// Удалить из ORDER BY повторяющиеся элементы.
|
|
|
|
|
optimizeOrderBy();
|
|
|
|
|
|
2014-07-04 19:13:38 +00:00
|
|
|
|
/// array_join_alias_to_name, array_join_result_to_source.
|
2013-08-01 13:29:32 +00:00
|
|
|
|
getArrayJoinedColumns();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 19:13:38 +00:00
|
|
|
|
/// Удалить ненужное из списка columns. Создать unknown_required_columns. Сформировать columns_added_by_join.
|
|
|
|
|
collectUsedColumns();
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// external_tables, subqueries_for_sets для глобальных подзапросов.
|
2014-07-04 20:30:06 +00:00
|
|
|
|
/// Заменяет глобальные подзапросы на сгенерированные имена временных таблиц, которые будут отправлены на удалённые серверы.
|
|
|
|
|
initGlobalSubqueriesAndExternalTables();
|
2015-10-15 11:07:39 +00:00
|
|
|
|
|
|
|
|
|
/// has_aggregation, aggregation_keys, aggregate_descriptions, aggregated_columns.
|
|
|
|
|
/// Этот анализ надо провести после обработки глобальных подзапросов, потому что в противном случае,
|
|
|
|
|
/// если агрегатная функция содержит глобальный подзапрос, то метод analyzeAggregation сохранит
|
|
|
|
|
/// в aggregate_descriptions информацию о параметрах этой агрегатной функции, среди которых окажется
|
|
|
|
|
/// глобальный подзапрос. Затем при вызове метода initGlobalSubqueriesAndExternalTables, этот
|
|
|
|
|
/// глобальный подзапрос будет заменён на временную таблицу, в результате чего aggregate_descriptions
|
2015-10-15 13:07:35 +00:00
|
|
|
|
/// будет содержать устаревшую информацию, что приведёт к ошибке при выполнении запроса.
|
2015-10-15 11:07:39 +00:00
|
|
|
|
analyzeAggregation();
|
2014-07-04 19:13:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::analyzeAggregation()
|
|
|
|
|
{
|
|
|
|
|
/** Найдем ключи агрегации (aggregation_keys), информацию об агрегатных функциях (aggregate_descriptions),
|
|
|
|
|
* а также набор столбцов, получаемых после агрегации, если она есть,
|
|
|
|
|
* или после всех действий, которые обычно выполняются до агрегации (aggregated_columns).
|
|
|
|
|
*
|
|
|
|
|
* Всё, что ниже (составление временных ExpressionActions) - только в целях анализа запроса (вывода типов).
|
|
|
|
|
*/
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (select_query && (select_query->group_expression_list || select_query->having_expression))
|
|
|
|
|
has_aggregation = true;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-01-13 00:32:59 +00:00
|
|
|
|
ExpressionActionsPtr temp_actions = std::make_shared<ExpressionActions>(columns, settings);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (select_query && select_query->array_join_expression_list())
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
getRootActions(select_query->array_join_expression_list(), true, false, temp_actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
addMultipleArrayJoinAction(temp_actions);
|
2013-10-21 11:33:25 +00:00
|
|
|
|
}
|
2014-03-28 12:13:58 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (select_query)
|
2014-06-13 02:05:05 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const ASTTablesInSelectQueryElement * join = select_query->join();
|
|
|
|
|
if (join)
|
|
|
|
|
{
|
|
|
|
|
if (static_cast<const ASTTableJoin &>(*join->table_join).using_expression_list)
|
|
|
|
|
getRootActions(static_cast<const ASTTableJoin &>(*join->table_join).using_expression_list, true, false, temp_actions);
|
2015-07-23 20:23:24 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
addJoinAction(temp_actions, true);
|
|
|
|
|
}
|
2014-06-13 02:05:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getAggregates(ast, temp_actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (has_aggregation)
|
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
/// Найдем ключи агрегации.
|
|
|
|
|
if (select_query->group_expression_list)
|
|
|
|
|
{
|
2013-06-20 15:38:03 +00:00
|
|
|
|
NameSet unique_keys;
|
2014-08-04 15:25:38 +00:00
|
|
|
|
auto & group_asts = select_query->group_expression_list->children;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
for (size_t i = 0; i < group_asts.size(); ++i)
|
|
|
|
|
{
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(group_asts[i], true, false, temp_actions);
|
2014-06-27 18:22:33 +00:00
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
const auto & column_name = group_asts[i]->getColumnName();
|
|
|
|
|
const auto & block = temp_actions->getSampleBlock();
|
2014-06-27 18:22:33 +00:00
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
if (!block.has(column_name))
|
|
|
|
|
throw Exception("Unknown identifier (in GROUP BY): " + column_name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
|
|
|
|
|
|
|
|
|
const auto & col = block.getByName(column_name);
|
|
|
|
|
|
2014-08-04 15:25:38 +00:00
|
|
|
|
/// constant expressions have non-null column pointer at this stage
|
|
|
|
|
if (const auto is_constexpr = col.column)
|
|
|
|
|
{
|
2015-10-21 21:43:42 +00:00
|
|
|
|
/// but don't remove last key column if no aggregate functions, otherwise aggregation will not work
|
|
|
|
|
if (!aggregate_descriptions.empty() || group_asts.size() > 1)
|
|
|
|
|
{
|
|
|
|
|
if (i < group_asts.size() - 1)
|
|
|
|
|
group_asts[i] = std::move(group_asts.back());
|
2014-08-04 15:25:38 +00:00
|
|
|
|
|
2015-10-21 21:43:42 +00:00
|
|
|
|
group_asts.pop_back();
|
|
|
|
|
i -= 1;
|
2015-01-30 21:19:35 +00:00
|
|
|
|
|
2015-10-21 21:43:42 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-08-04 15:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
NameAndTypePair key{column_name, col.type};
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-03-12 02:22:55 +00:00
|
|
|
|
/// Ключи агрегации уникализируются.
|
2014-07-09 11:45:51 +00:00
|
|
|
|
if (!unique_keys.count(key.name))
|
2013-06-20 15:38:03 +00:00
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
unique_keys.insert(key.name);
|
2015-03-12 02:22:55 +00:00
|
|
|
|
aggregation_keys.push_back(key);
|
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
/// key is no longer needed, therefore we can save a little by moving it
|
|
|
|
|
aggregated_columns.push_back(std::move(key));
|
2013-06-20 15:38:03 +00:00
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2014-08-04 15:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (group_asts.empty())
|
|
|
|
|
{
|
|
|
|
|
select_query->group_expression_list = nullptr;
|
|
|
|
|
has_aggregation = select_query->having_expression || aggregate_descriptions.size();
|
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
for (size_t i = 0; i < aggregate_descriptions.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
AggregateDescription & desc = aggregate_descriptions[i];
|
2014-07-06 00:19:49 +00:00
|
|
|
|
aggregated_columns.emplace_back(desc.column_name, desc.function->getReturnType());
|
2013-05-28 11:54:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-06-24 19:53:48 +00:00
|
|
|
|
aggregated_columns = temp_actions->getSampleBlock().getColumnsList();
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-07-04 20:30:06 +00:00
|
|
|
|
void ExpressionAnalyzer::initGlobalSubqueriesAndExternalTables()
|
|
|
|
|
{
|
2015-08-14 21:07:17 +00:00
|
|
|
|
/// Добавляет уже существующие внешние таблицы (не подзапросы) в словарь external_tables.
|
2014-07-04 20:30:06 +00:00
|
|
|
|
findExternalTables(ast);
|
2015-11-04 22:02:52 +00:00
|
|
|
|
|
|
|
|
|
/// Преобразует GLOBAL-подзапросы во внешние таблицы; кладёт их в словарь external_tables: name -> StoragePtr.
|
|
|
|
|
initGlobalSubqueries(ast);
|
2014-07-04 20:30:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::initGlobalSubqueries(ASTPtr & ast)
|
|
|
|
|
{
|
|
|
|
|
/// Рекурсивные вызовы. Не опускаемся в подзапросы.
|
|
|
|
|
|
|
|
|
|
for (auto & child : ast->children)
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (!typeid_cast<ASTSelectQuery *>(child.get()))
|
2014-07-04 20:30:06 +00:00
|
|
|
|
initGlobalSubqueries(child);
|
|
|
|
|
|
|
|
|
|
/// Действия, выполняемые снизу вверх.
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTFunction * node = typeid_cast<ASTFunction *>(ast.get()))
|
2014-07-04 20:30:06 +00:00
|
|
|
|
{
|
|
|
|
|
/// Для GLOBAL IN.
|
|
|
|
|
if (do_global && (node->name == "globalIn" || node->name == "globalNotIn"))
|
|
|
|
|
addExternalStorage(node->arguments->children.at(1));
|
|
|
|
|
}
|
2016-07-22 20:39:28 +00:00
|
|
|
|
else if (ASTTablesInSelectQueryElement * node = typeid_cast<ASTTablesInSelectQueryElement *>(ast.get()))
|
2014-07-04 20:30:06 +00:00
|
|
|
|
{
|
|
|
|
|
/// Для GLOBAL JOIN.
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (do_global && node->table_join
|
|
|
|
|
&& static_cast<const ASTTableJoin &>(*node->table_join).locality == ASTTableJoin::Locality::Global)
|
2016-07-26 19:43:58 +00:00
|
|
|
|
addExternalStorage(node->table_expression);
|
2014-07-04 20:30:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::findExternalTables(ASTPtr & ast)
|
|
|
|
|
{
|
|
|
|
|
/// Обход снизу. Намеренно опускаемся в подзапросы.
|
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
findExternalTables(child);
|
|
|
|
|
|
|
|
|
|
/// Если идентификатор типа таблица
|
|
|
|
|
StoragePtr external_storage;
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTIdentifier * node = typeid_cast<ASTIdentifier *>(ast.get()))
|
2015-11-04 22:02:52 +00:00
|
|
|
|
if (node->kind == ASTIdentifier::Table)
|
2014-07-04 20:30:06 +00:00
|
|
|
|
if ((external_storage = context.tryGetExternalTable(node->name)))
|
|
|
|
|
external_tables[node->name] = external_storage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
static std::shared_ptr<InterpreterSelectQuery> interpretSubquery(
|
2015-11-04 22:02:52 +00:00
|
|
|
|
ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, const Names & required_columns);
|
|
|
|
|
|
|
|
|
|
|
2016-07-26 19:43:58 +00:00
|
|
|
|
void ExpressionAnalyzer::addExternalStorage(ASTPtr & subquery_or_table_name_or_table_expression)
|
2015-11-04 22:02:52 +00:00
|
|
|
|
{
|
|
|
|
|
/// При нераспределённых запросах, создание временных таблиц не имеет смысла.
|
|
|
|
|
if (!(storage && storage->isRemote()))
|
|
|
|
|
return;
|
|
|
|
|
|
2016-07-26 19:43:58 +00:00
|
|
|
|
ASTPtr subquery;
|
|
|
|
|
ASTPtr table_name;
|
|
|
|
|
ASTPtr subquery_or_table_name;
|
|
|
|
|
|
|
|
|
|
if (typeid_cast<const ASTIdentifier *>(subquery_or_table_name_or_table_expression.get()))
|
|
|
|
|
{
|
|
|
|
|
table_name = subquery_or_table_name_or_table_expression;
|
|
|
|
|
subquery_or_table_name = table_name;
|
|
|
|
|
}
|
|
|
|
|
else if (auto ast_table_expr = typeid_cast<const ASTTableExpression *>(subquery_or_table_name_or_table_expression.get()))
|
|
|
|
|
{
|
|
|
|
|
if (ast_table_expr->database_and_table_name)
|
|
|
|
|
{
|
|
|
|
|
table_name = ast_table_expr->database_and_table_name;
|
|
|
|
|
subquery_or_table_name = table_name;
|
|
|
|
|
}
|
|
|
|
|
else if (ast_table_expr->subquery)
|
|
|
|
|
{
|
|
|
|
|
subquery = ast_table_expr->subquery;
|
|
|
|
|
subquery_or_table_name = subquery;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (typeid_cast<const ASTSubquery *>(subquery_or_table_name_or_table_expression.get()))
|
|
|
|
|
{
|
|
|
|
|
subquery = subquery_or_table_name_or_table_expression;
|
|
|
|
|
subquery_or_table_name = subquery;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subquery_or_table_name)
|
|
|
|
|
throw Exception("Logical error: unknown AST element passed to ExpressionAnalyzer::addExternalStorage method", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
|
|
if (table_name)
|
2015-11-04 22:02:52 +00:00
|
|
|
|
{
|
|
|
|
|
/// Если это уже внешняя таблица, ничего заполять не нужно. Просто запоминаем ее наличие.
|
2016-07-26 19:43:58 +00:00
|
|
|
|
if (external_tables.end() != external_tables.find(static_cast<const ASTIdentifier &>(*table_name).name))
|
2015-11-04 22:02:52 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Сгенерируем имя для внешней таблицы.
|
|
|
|
|
String external_table_name = "_data" + toString(external_table_id);
|
|
|
|
|
while (external_tables.count(external_table_name))
|
|
|
|
|
{
|
|
|
|
|
++external_table_id;
|
|
|
|
|
external_table_name = "_data" + toString(external_table_id);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
auto interpreter = interpretSubquery(subquery_or_table_name, context, subquery_depth, {});
|
2015-11-04 22:02:52 +00:00
|
|
|
|
|
|
|
|
|
Block sample = interpreter->getSampleBlock();
|
2016-05-28 08:15:50 +00:00
|
|
|
|
NamesAndTypesListPtr columns = std::make_shared<NamesAndTypesList>(sample.getColumnsList());
|
2015-11-04 22:02:52 +00:00
|
|
|
|
|
|
|
|
|
StoragePtr external_storage = StorageMemory::create(external_table_name, columns);
|
|
|
|
|
|
|
|
|
|
/** Есть два способа выполнения распределённых GLOBAL-подзапросов.
|
|
|
|
|
*
|
|
|
|
|
* Способ push:
|
|
|
|
|
* Данные подзапроса отправляются на все удалённые серверы, где они затем используются.
|
|
|
|
|
* Для этого способа, данные отправляются в виде "внешних таблиц" и будут доступны на каждом удалённом сервере по имени типа _data1.
|
|
|
|
|
* Заменяем в запросе подзапрос на это имя.
|
|
|
|
|
*
|
|
|
|
|
* Способ pull:
|
|
|
|
|
* Удалённые серверы скачивают данные подзапроса с сервера-инициатора запроса.
|
|
|
|
|
* Для этого способа, заменяем подзапрос на другой подзапрос вида (SELECT * FROM remote('host:port', _query_QUERY_ID, _data1))
|
|
|
|
|
* Этот подзапрос, по факту, говорит - "надо скачать данные оттуда".
|
|
|
|
|
*
|
|
|
|
|
* Способ pull имеет преимущество, потому что в нём удалённый сервер может решить, что ему не нужны данные и не скачивать их в таких случаях.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (settings.global_subqueries_method == GlobalSubqueriesMethod::PUSH)
|
|
|
|
|
{
|
|
|
|
|
/** Заменяем подзапрос на имя временной таблицы.
|
|
|
|
|
* Именно в таком виде, запрос отправится на удалённый сервер.
|
|
|
|
|
* На удалённый сервер отправится эта временная таблица, и на его стороне,
|
|
|
|
|
* вместо выполнения подзапроса, надо будет просто из неё прочитать.
|
|
|
|
|
*/
|
|
|
|
|
|
2016-07-26 19:43:58 +00:00
|
|
|
|
auto database_and_table_name = std::make_shared<ASTIdentifier>(StringRange(), external_table_name, ASTIdentifier::Table);
|
|
|
|
|
|
|
|
|
|
if (auto ast_table_expr = typeid_cast<ASTTableExpression *>(subquery_or_table_name_or_table_expression.get()))
|
|
|
|
|
{
|
|
|
|
|
ast_table_expr->subquery.reset();
|
|
|
|
|
ast_table_expr->database_and_table_name = database_and_table_name;
|
|
|
|
|
|
|
|
|
|
ast_table_expr->children.clear();
|
|
|
|
|
ast_table_expr->children.emplace_back(database_and_table_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
subquery_or_table_name_or_table_expression = database_and_table_name;
|
2015-11-04 22:02:52 +00:00
|
|
|
|
}
|
|
|
|
|
else if (settings.global_subqueries_method == GlobalSubqueriesMethod::PULL)
|
|
|
|
|
{
|
2016-07-26 19:43:58 +00:00
|
|
|
|
throw Exception("Support for 'pull' method of execution of global subqueries is disabled.", ErrorCodes::SUPPORT_IS_DISABLED);
|
|
|
|
|
|
|
|
|
|
/// TODO
|
2016-07-22 20:39:28 +00:00
|
|
|
|
/* String host_port = getFQDNOrHostName() + ":" + toString(context.getTCPPort());
|
2015-11-04 22:02:52 +00:00
|
|
|
|
String database = "_query_" + context.getCurrentQueryId();
|
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto subquery = std::make_shared<ASTSubquery>();
|
2015-11-04 22:02:52 +00:00
|
|
|
|
subquery_or_table_name = subquery;
|
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto select = std::make_shared<ASTSelectQuery>();
|
2015-11-04 22:02:52 +00:00
|
|
|
|
subquery->children.push_back(select);
|
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto exp_list = std::make_shared<ASTExpressionList>();
|
2015-11-04 22:02:52 +00:00
|
|
|
|
select->select_expression_list = exp_list;
|
|
|
|
|
select->children.push_back(select->select_expression_list);
|
|
|
|
|
|
|
|
|
|
Names column_names = external_storage->getColumnNamesList();
|
|
|
|
|
for (const auto & name : column_names)
|
2016-05-28 15:56:51 +00:00
|
|
|
|
exp_list->children.push_back(std::make_shared<ASTIdentifier>(StringRange(), name));
|
2015-11-04 22:02:52 +00:00
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto table_func = std::make_shared<ASTFunction>();
|
2015-11-04 22:02:52 +00:00
|
|
|
|
select->table = table_func;
|
|
|
|
|
select->children.push_back(select->table);
|
|
|
|
|
|
|
|
|
|
table_func->name = "remote";
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto args = std::make_shared<ASTExpressionList>();
|
2015-11-04 22:02:52 +00:00
|
|
|
|
table_func->arguments = args;
|
|
|
|
|
table_func->children.push_back(table_func->arguments);
|
|
|
|
|
|
2016-05-28 15:56:51 +00:00
|
|
|
|
auto address_lit = std::make_shared<ASTLiteral>(StringRange(), host_port);
|
2015-11-04 22:02:52 +00:00
|
|
|
|
args->children.push_back(address_lit);
|
|
|
|
|
|
2016-05-28 15:56:51 +00:00
|
|
|
|
auto database_lit = std::make_shared<ASTLiteral>(StringRange(), database);
|
2015-11-04 22:02:52 +00:00
|
|
|
|
args->children.push_back(database_lit);
|
|
|
|
|
|
2016-05-28 15:56:51 +00:00
|
|
|
|
auto table_lit = std::make_shared<ASTLiteral>(StringRange(), external_table_name);
|
2016-07-22 20:39:28 +00:00
|
|
|
|
args->children.push_back(table_lit);*/
|
2015-11-04 22:02:52 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Unknown global subqueries execution method", ErrorCodes::UNKNOWN_GLOBAL_SUBQUERIES_METHOD);
|
|
|
|
|
|
|
|
|
|
external_tables[external_table_name] = external_storage;
|
|
|
|
|
subqueries_for_sets[external_table_name].source = interpreter->execute().in;
|
|
|
|
|
subqueries_for_sets[external_table_name].source_sample = interpreter->getSampleBlock();
|
|
|
|
|
subqueries_for_sets[external_table_name].table = external_storage;
|
|
|
|
|
|
|
|
|
|
/** NOTE Если было написано IN tmp_table - существующая временная (но не внешняя) таблица,
|
|
|
|
|
* то здесь будет создана новая временная таблица (например, _data1),
|
|
|
|
|
* и данные будут затем в неё скопированы.
|
|
|
|
|
* Может быть, этого можно избежать.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-06-12 21:17:03 +00:00
|
|
|
|
NamesAndTypesList::iterator ExpressionAnalyzer::findColumn(const String & name, NamesAndTypesList & cols)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2014-06-12 21:12:47 +00:00
|
|
|
|
return std::find_if(cols.begin(), cols.end(),
|
2014-07-09 11:45:51 +00:00
|
|
|
|
[&](const NamesAndTypesList::value_type & val) { return val.name == name; });
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-10-21 11:33:25 +00:00
|
|
|
|
/// ignore_levels - алиасы в скольки верхних уровнях поддерева нужно игнорировать.
|
|
|
|
|
/// Например, при ignore_levels=1 ast не может быть занесен в словарь, но его дети могут.
|
2014-10-03 15:30:10 +00:00
|
|
|
|
void ExpressionAnalyzer::addASTAliases(ASTPtr & ast, int ignore_levels)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
/// Обход снизу-вверх. Не опускаемся в подзапросы.
|
2014-07-04 20:30:06 +00:00
|
|
|
|
for (auto & child : ast->children)
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
|
|
|
|
int new_ignore_levels = std::max(0, ignore_levels - 1);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
|
2013-10-21 11:33:25 +00:00
|
|
|
|
/// Алиасы верхнего уровня в секции ARRAY JOIN имеют особый смысл, их добавлять не будем
|
|
|
|
|
/// (пропустим сам expression list и его детей).
|
2016-07-23 02:25:09 +00:00
|
|
|
|
if (typeid_cast<ASTArrayJoin *>(ast.get()))
|
|
|
|
|
new_ignore_levels = 3;
|
2014-06-12 19:53:36 +00:00
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
/// Don't descent into UNION ALL, table functions and subqueries.
|
|
|
|
|
if (!typeid_cast<ASTTableExpression *>(child.get())
|
|
|
|
|
&& !typeid_cast<ASTSelectQuery *>(child.get()))
|
2014-10-03 15:30:10 +00:00
|
|
|
|
addASTAliases(child, new_ignore_levels);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ignore_levels > 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2014-07-03 22:39:13 +00:00
|
|
|
|
String alias = ast->tryGetAlias();
|
|
|
|
|
if (!alias.empty())
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2014-07-03 22:39:13 +00:00
|
|
|
|
if (aliases.count(alias) && ast->getTreeID() != aliases[alias]->getTreeID())
|
|
|
|
|
throw Exception("Different expressions with the same alias " + alias, ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
|
2014-07-03 22:39:13 +00:00
|
|
|
|
aliases[alias] = ast;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StoragePtr ExpressionAnalyzer::getTable()
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (const ASTSelectQuery * select = typeid_cast<const ASTSelectQuery *>(ast.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
auto select_database = select->database();
|
|
|
|
|
auto select_table = select->table();
|
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
if (select_table
|
|
|
|
|
&& !typeid_cast<const ASTSelectQuery *>(select_table.get())
|
|
|
|
|
&& !typeid_cast<const ASTFunction *>(select_table.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
String database = select_database
|
|
|
|
|
? typeid_cast<const ASTIdentifier &>(*select_database).name
|
2014-06-12 19:53:36 +00:00
|
|
|
|
: "";
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const String & table = typeid_cast<const ASTIdentifier &>(*select_table).name;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return context.tryGetTable(database, table);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-12 21:12:47 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return StoragePtr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::normalizeTree()
|
|
|
|
|
{
|
|
|
|
|
SetOfASTs tmp_set;
|
|
|
|
|
MapOfASTs tmp_map;
|
2014-06-12 19:23:06 +00:00
|
|
|
|
normalizeTreeImpl(ast, tmp_map, tmp_set, "");
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// finished_asts - уже обработанные вершины (и на что они заменены)
|
|
|
|
|
/// current_asts - вершины в текущем стеке вызовов этого метода
|
2013-10-18 08:07:51 +00:00
|
|
|
|
/// current_alias - алиас, повешенный на предка ast (самого глубокого из предков с алиасами)
|
2015-05-12 20:09:18 +00:00
|
|
|
|
void ExpressionAnalyzer::normalizeTreeImpl(
|
|
|
|
|
ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
if (finished_asts.count(ast))
|
|
|
|
|
{
|
|
|
|
|
ast = finished_asts[ast];
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
ASTPtr initial_ast = ast;
|
2016-05-28 16:19:27 +00:00
|
|
|
|
current_asts.insert(initial_ast.get());
|
2013-06-15 07:10:06 +00:00
|
|
|
|
|
2014-07-03 22:39:13 +00:00
|
|
|
|
String my_alias = ast->tryGetAlias();
|
|
|
|
|
if (!my_alias.empty())
|
|
|
|
|
current_alias = my_alias;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-03 11:52:23 +00:00
|
|
|
|
/// rewrite правила, которые действуют при обходе сверху-вниз.
|
2013-10-18 08:07:51 +00:00
|
|
|
|
bool replaced = false;
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * func_node = typeid_cast<ASTFunction *>(ast.get());
|
2015-05-12 20:09:18 +00:00
|
|
|
|
if (func_node)
|
2013-06-03 11:52:23 +00:00
|
|
|
|
{
|
|
|
|
|
/** Нет ли в таблице столбца, название которого полностью совпадает с записью функции?
|
2014-06-12 21:12:47 +00:00
|
|
|
|
* Например, в таблице есть столбец "domain(URL)", и мы запросили domain(URL).
|
|
|
|
|
*/
|
2015-05-12 20:09:18 +00:00
|
|
|
|
String function_string = func_node->getColumnName();
|
2013-06-03 11:52:23 +00:00
|
|
|
|
NamesAndTypesList::const_iterator it = findColumn(function_string);
|
|
|
|
|
if (columns.end() != it)
|
|
|
|
|
{
|
2016-05-28 15:42:22 +00:00
|
|
|
|
ast = std::make_shared<ASTIdentifier>(func_node->range, function_string);
|
2016-05-28 16:19:27 +00:00
|
|
|
|
current_asts.insert(ast.get());
|
2013-10-18 08:07:51 +00:00
|
|
|
|
replaced = true;
|
2013-06-03 11:52:23 +00:00
|
|
|
|
}
|
2014-07-03 20:32:42 +00:00
|
|
|
|
|
2015-05-13 01:19:19 +00:00
|
|
|
|
/// Может быть указано IN t, где t - таблица, что равносильно IN (SELECT * FROM t).
|
2015-07-26 07:08:46 +00:00
|
|
|
|
if (functionIsInOrGlobalInOperator(func_node->name))
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTIdentifier * right = typeid_cast<ASTIdentifier *>(func_node->arguments->children.at(1).get()))
|
2014-03-12 14:15:35 +00:00
|
|
|
|
right->kind = ASTIdentifier::Table;
|
2015-05-13 01:19:19 +00:00
|
|
|
|
|
2016-07-14 05:22:09 +00:00
|
|
|
|
/// Special cases for count function.
|
|
|
|
|
String func_name_lowercase = Poco::toLower(func_node->name);
|
|
|
|
|
if (startsWith(func_name_lowercase, "count"))
|
2015-05-13 01:19:19 +00:00
|
|
|
|
{
|
2016-07-14 05:22:09 +00:00
|
|
|
|
/// Select implementation of countDistinct based on settings.
|
|
|
|
|
/// Important that it is done as query rewrite. It means rewritten query
|
|
|
|
|
/// will be sent to remote servers during distributed query execution,
|
|
|
|
|
/// and on all remote servers, function implementation will be same.
|
|
|
|
|
if (endsWith(func_node->name, "Distinct") && func_name_lowercase == "countdistinct")
|
|
|
|
|
func_node->name = settings.count_distinct_implementation;
|
|
|
|
|
|
|
|
|
|
/// As special case, treat count(*) as count(), not as count(list of all columns).
|
|
|
|
|
if (func_name_lowercase == "count" && func_node->arguments->children.size() == 1
|
|
|
|
|
&& typeid_cast<const ASTAsterisk *>(func_node->arguments->children[0].get()))
|
|
|
|
|
{
|
|
|
|
|
func_node->arguments->children.clear();
|
|
|
|
|
}
|
2015-05-13 01:19:19 +00:00
|
|
|
|
}
|
2013-06-03 11:52:23 +00:00
|
|
|
|
}
|
2016-03-05 02:30:20 +00:00
|
|
|
|
else if (ASTIdentifier * node = typeid_cast<ASTIdentifier *>(ast.get()))
|
2013-06-03 11:19:31 +00:00
|
|
|
|
{
|
2013-10-17 13:32:32 +00:00
|
|
|
|
if (node->kind == ASTIdentifier::Column)
|
2013-06-03 11:19:31 +00:00
|
|
|
|
{
|
2013-06-18 09:43:35 +00:00
|
|
|
|
/// Если это алиас, но не родительский алиас (чтобы работали конструкции вроде "SELECT column+1 AS column").
|
2013-06-03 11:19:31 +00:00
|
|
|
|
Aliases::const_iterator jt = aliases.find(node->name);
|
2013-06-18 09:43:35 +00:00
|
|
|
|
if (jt != aliases.end() && current_alias != node->name)
|
2013-06-03 11:19:31 +00:00
|
|
|
|
{
|
2013-10-18 08:07:51 +00:00
|
|
|
|
/// Заменим его на соответствующий узел дерева.
|
2016-05-28 16:19:27 +00:00
|
|
|
|
if (current_asts.count(jt->second.get()))
|
2013-06-15 07:10:06 +00:00
|
|
|
|
throw Exception("Cyclic aliases", ErrorCodes::CYCLIC_ALIASES);
|
2014-07-03 22:39:13 +00:00
|
|
|
|
if (!my_alias.empty() && my_alias != jt->second->getAliasOrColumnName())
|
2013-10-18 08:07:51 +00:00
|
|
|
|
{
|
|
|
|
|
/// В конструкции вроде "a AS b", где a - алиас, нужно перевесить алиас b на результат подстановки алиаса a.
|
|
|
|
|
ast = jt->second->clone();
|
2014-07-03 22:39:13 +00:00
|
|
|
|
ast->setAlias(my_alias);
|
2013-10-18 08:07:51 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ast = jt->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
replaced = true;
|
2013-06-03 11:19:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-05 02:30:20 +00:00
|
|
|
|
else if (ASTExpressionList * node = typeid_cast<ASTExpressionList *>(ast.get()))
|
2013-06-03 11:19:31 +00:00
|
|
|
|
{
|
|
|
|
|
/// Заменим * на список столбцов.
|
|
|
|
|
ASTs & asts = node->children;
|
|
|
|
|
for (int i = static_cast<int>(asts.size()) - 1; i >= 0; --i)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTAsterisk * asterisk = typeid_cast<ASTAsterisk *>(asts[i].get()))
|
2013-06-03 11:19:31 +00:00
|
|
|
|
{
|
|
|
|
|
ASTs all_columns;
|
2014-06-12 21:12:47 +00:00
|
|
|
|
for (const auto & column_name_type : columns)
|
2016-05-28 15:42:22 +00:00
|
|
|
|
all_columns.emplace_back(std::make_shared<ASTIdentifier>(asterisk->range, column_name_type.name));
|
2014-06-12 21:12:47 +00:00
|
|
|
|
|
2013-06-03 11:19:31 +00:00
|
|
|
|
asts.erase(asts.begin() + i);
|
|
|
|
|
asts.insert(asts.begin() + i, all_columns.begin(), all_columns.end());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-22 20:39:28 +00:00
|
|
|
|
else if (ASTTablesInSelectQueryElement * node = typeid_cast<ASTTablesInSelectQueryElement *>(ast.get()))
|
2014-07-06 04:22:12 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (node->table_expression)
|
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
auto & database_and_table_name = static_cast<ASTTableExpression &>(*node->table_expression).database_and_table_name;
|
|
|
|
|
if (database_and_table_name)
|
2016-07-22 20:39:28 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
if (ASTIdentifier * right = typeid_cast<ASTIdentifier *>(database_and_table_name.get()))
|
|
|
|
|
{
|
|
|
|
|
right->kind = ASTIdentifier::Table;
|
|
|
|
|
}
|
2016-07-22 20:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-06 04:22:12 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-10-18 08:07:51 +00:00
|
|
|
|
/// Если заменили корень поддерева вызовемся для нового корня снова - на случай, если алиас заменился на алиас.
|
|
|
|
|
if (replaced)
|
|
|
|
|
{
|
2014-06-12 19:23:06 +00:00
|
|
|
|
normalizeTreeImpl(ast, finished_asts, current_asts, current_alias);
|
2016-05-28 16:19:27 +00:00
|
|
|
|
current_asts.erase(initial_ast.get());
|
|
|
|
|
current_asts.erase(ast.get());
|
2016-05-28 16:25:09 +00:00
|
|
|
|
finished_asts[initial_ast] = ast;
|
2013-10-18 08:07:51 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-03 11:19:31 +00:00
|
|
|
|
/// Рекурсивные вызовы. Не опускаемся в подзапросы.
|
2015-05-12 20:09:18 +00:00
|
|
|
|
/// Также не опускаемся в левый аргумент лямбда-выражений, чтобы не заменять формальные параметры
|
|
|
|
|
/// по алиасам в выражениях вида 123 AS x, arrayMap(x -> 1, [2]).
|
|
|
|
|
|
|
|
|
|
if (func_node && func_node->name == "lambda")
|
|
|
|
|
{
|
|
|
|
|
/// Пропускаем первый аргумент. Также предполагаем, что у функции lambda не может быть parameters.
|
|
|
|
|
for (size_t i = 1, size = func_node->arguments->children.size(); i < size; ++i)
|
|
|
|
|
{
|
|
|
|
|
auto & child = func_node->arguments->children[i];
|
|
|
|
|
|
2016-07-23 02:42:42 +00:00
|
|
|
|
if (typeid_cast<const ASTSelectQuery *>(child.get())
|
|
|
|
|
|| typeid_cast<const ASTTableExpression *>(child.get()))
|
2015-05-12 20:09:18 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
normalizeTreeImpl(child, finished_asts, current_asts, current_alias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
{
|
2016-07-23 02:42:42 +00:00
|
|
|
|
if (typeid_cast<const ASTSelectQuery *>(child.get())
|
|
|
|
|
|| typeid_cast<const ASTTableExpression *>(child.get()))
|
2015-05-12 20:09:18 +00:00
|
|
|
|
continue;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 20:30:06 +00:00
|
|
|
|
normalizeTreeImpl(child, finished_asts, current_asts, current_alias);
|
2015-05-12 20:09:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
/// Если секция WHERE или HAVING состоит из одного алиаса, ссылку нужно заменить не только в children, но и в where_expression и having_expression.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTSelectQuery * select = typeid_cast<ASTSelectQuery *>(ast.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-12-05 13:07:55 +00:00
|
|
|
|
if (select->prewhere_expression)
|
2014-06-12 19:23:06 +00:00
|
|
|
|
normalizeTreeImpl(select->prewhere_expression, finished_asts, current_asts, current_alias);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (select->where_expression)
|
2014-06-12 19:23:06 +00:00
|
|
|
|
normalizeTreeImpl(select->where_expression, finished_asts, current_asts, current_alias);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (select->having_expression)
|
2014-06-12 19:23:06 +00:00
|
|
|
|
normalizeTreeImpl(select->having_expression, finished_asts, current_asts, current_alias);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-18 09:43:35 +00:00
|
|
|
|
/// Действия, выполняемые снизу вверх.
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTFunction * node = typeid_cast<ASTFunction *>(ast.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2014-02-28 13:09:43 +00:00
|
|
|
|
if (node->kind == ASTFunction::TABLE_FUNCTION)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else if (node->name == "lambda")
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
node->kind = ASTFunction::LAMBDA_EXPRESSION;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
else if (context.getAggregateFunctionFactory().isAggregateFunctionName(node->name))
|
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
node->kind = ASTFunction::AGGREGATE_FUNCTION;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-05-29 11:46:51 +00:00
|
|
|
|
else if (node->name == "arrayJoin")
|
|
|
|
|
{
|
|
|
|
|
node->kind = ASTFunction::ARRAY_JOIN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
node->kind = ASTFunction::FUNCTION;
|
|
|
|
|
}
|
2016-01-13 01:02:10 +00:00
|
|
|
|
|
|
|
|
|
if (node->parameters && node->kind != ASTFunction::AGGREGATE_FUNCTION)
|
|
|
|
|
throw Exception("The only parametric functions (functions with two separate parenthesis pairs) are aggregate functions"
|
|
|
|
|
", and '" + node->name + "' is not an aggregate function.", ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2014-07-03 20:32:42 +00:00
|
|
|
|
|
2016-05-28 16:19:27 +00:00
|
|
|
|
current_asts.erase(initial_ast.get());
|
|
|
|
|
current_asts.erase(ast.get());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
finished_asts[initial_ast] = ast;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-25 11:47:50 +00:00
|
|
|
|
|
2015-10-29 15:14:19 +00:00
|
|
|
|
void ExpressionAnalyzer::addAliasColumns()
|
|
|
|
|
{
|
2015-12-15 14:13:30 +00:00
|
|
|
|
if (!select_query)
|
2015-10-29 15:14:19 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!storage)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
columns.insert(std::end(columns), std::begin(storage->alias_columns), std::end(storage->alias_columns));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-25 11:47:50 +00:00
|
|
|
|
void ExpressionAnalyzer::executeScalarSubqueries()
|
|
|
|
|
{
|
2015-07-26 08:28:12 +00:00
|
|
|
|
if (!select_query)
|
|
|
|
|
executeScalarSubqueriesImpl(ast);
|
|
|
|
|
else
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
2015-07-26 08:28:12 +00:00
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
{
|
2015-11-13 20:50:51 +00:00
|
|
|
|
/// Не опускаемся в FROM, JOIN, UNION.
|
2016-07-23 02:42:42 +00:00
|
|
|
|
if (!typeid_cast<const ASTTableExpression *>(child.get())
|
2015-11-13 20:50:51 +00:00
|
|
|
|
&& child.get() != select_query->next_union_all.get())
|
|
|
|
|
{
|
2015-07-26 08:28:12 +00:00
|
|
|
|
executeScalarSubqueriesImpl(child);
|
2015-11-13 20:50:51 +00:00
|
|
|
|
}
|
2015-07-26 08:28:12 +00:00
|
|
|
|
}
|
2015-07-26 07:08:46 +00:00
|
|
|
|
}
|
2015-07-25 11:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-26 07:55:48 +00:00
|
|
|
|
|
2016-05-30 20:31:03 +00:00
|
|
|
|
static ASTPtr addTypeConversion(std::unique_ptr<ASTLiteral> && ast, const String & type_name)
|
2015-07-26 07:55:48 +00:00
|
|
|
|
{
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto func = std::make_shared<ASTFunction>(ast->range);
|
2015-07-26 07:55:48 +00:00
|
|
|
|
ASTPtr res = func;
|
|
|
|
|
func->alias = ast->alias;
|
|
|
|
|
ast->alias.clear();
|
|
|
|
|
func->kind = ASTFunction::FUNCTION;
|
2015-12-23 11:16:28 +00:00
|
|
|
|
func->name = "CAST";
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto exp_list = std::make_shared<ASTExpressionList>(ast->range);
|
2015-07-26 07:55:48 +00:00
|
|
|
|
func->arguments = exp_list;
|
|
|
|
|
func->children.push_back(func->arguments);
|
2015-12-23 11:16:28 +00:00
|
|
|
|
exp_list->children.emplace_back(ast.release());
|
2016-05-28 15:56:51 +00:00
|
|
|
|
exp_list->children.emplace_back(std::make_shared<ASTLiteral>(StringRange(), type_name));
|
2015-07-26 07:55:48 +00:00
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-25 11:47:50 +00:00
|
|
|
|
void ExpressionAnalyzer::executeScalarSubqueriesImpl(ASTPtr & ast)
|
|
|
|
|
{
|
|
|
|
|
/** Заменяем подзапросы, возвращающие ровно одну строку
|
|
|
|
|
* ("скалярные" подзапросы) на соответствующие константы.
|
|
|
|
|
*
|
|
|
|
|
* Если подзапрос возвращает более одного столбца, то он заменяется на кортеж констант.
|
|
|
|
|
*
|
|
|
|
|
* Особенности:
|
|
|
|
|
*
|
|
|
|
|
* Замена происходит во время анализа запроса, а не во время основной стадии выполнения.
|
|
|
|
|
* Это значит, что не будет работать индикатор прогресса во время выполнения этих запросов,
|
|
|
|
|
* а также такие запросы нельзя будет прервать.
|
|
|
|
|
*
|
|
|
|
|
* Зато результат запросов может быть использован для индекса в таблице.
|
|
|
|
|
*
|
|
|
|
|
* Скалярные подзапросы выполняются на сервере-инициаторе запроса.
|
|
|
|
|
* На удалённые серверы запрос отправляется с уже подставленными константами.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (ASTSubquery * subquery = typeid_cast<ASTSubquery *>(ast.get()))
|
|
|
|
|
{
|
|
|
|
|
Context subquery_context = context;
|
|
|
|
|
Settings subquery_settings = context.getSettings();
|
|
|
|
|
subquery_settings.limits.max_result_rows = 1;
|
|
|
|
|
subquery_settings.extremes = 0;
|
|
|
|
|
subquery_context.setSettings(subquery_settings);
|
|
|
|
|
|
|
|
|
|
ASTPtr query = subquery->children.at(0);
|
|
|
|
|
BlockIO res = InterpreterSelectQuery(query, subquery_context, QueryProcessingStage::Complete, subquery_depth + 1).execute();
|
|
|
|
|
|
|
|
|
|
Block block;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
block = res.in->read();
|
|
|
|
|
|
|
|
|
|
if (!block)
|
|
|
|
|
throw Exception("Scalar subquery returned empty result", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
|
|
|
|
|
|
|
|
|
if (block.rows() != 1 || res.in->read())
|
|
|
|
|
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
|
|
|
|
}
|
|
|
|
|
catch (const Exception & e)
|
|
|
|
|
{
|
|
|
|
|
if (e.code() == ErrorCodes::TOO_MUCH_ROWS)
|
|
|
|
|
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
|
|
|
|
else
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t columns = block.columns();
|
|
|
|
|
if (columns == 1)
|
|
|
|
|
{
|
2016-05-30 20:31:03 +00:00
|
|
|
|
auto lit = std::make_unique<ASTLiteral>(ast->range, (*block.getByPosition(0).column)[0]);
|
2015-07-26 07:55:48 +00:00
|
|
|
|
lit->alias = subquery->alias;
|
2016-05-30 20:31:03 +00:00
|
|
|
|
ast = addTypeConversion(std::move(lit), block.getByPosition(0).type->getName());
|
2015-07-25 11:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto tuple = std::make_shared<ASTFunction>(ast->range);
|
2015-07-26 07:55:48 +00:00
|
|
|
|
tuple->alias = subquery->alias;
|
2015-07-25 11:47:50 +00:00
|
|
|
|
ast = tuple;
|
|
|
|
|
tuple->kind = ASTFunction::FUNCTION;
|
|
|
|
|
tuple->name = "tuple";
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto exp_list = std::make_shared<ASTExpressionList>(ast->range);
|
2015-07-25 11:47:50 +00:00
|
|
|
|
tuple->arguments = exp_list;
|
2015-07-25 11:59:21 +00:00
|
|
|
|
tuple->children.push_back(tuple->arguments);
|
2015-07-25 11:47:50 +00:00
|
|
|
|
|
|
|
|
|
exp_list->children.resize(columns);
|
|
|
|
|
for (size_t i = 0; i < columns; ++i)
|
2015-07-26 07:55:48 +00:00
|
|
|
|
{
|
|
|
|
|
exp_list->children[i] = addTypeConversion(
|
2016-05-30 20:31:03 +00:00
|
|
|
|
std::make_unique<ASTLiteral>(ast->range, (*block.getByPosition(i).column)[0]),
|
2015-07-26 07:55:48 +00:00
|
|
|
|
block.getByPosition(i).type->getName());
|
|
|
|
|
}
|
2015-07-25 11:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
/** Don't descend into subqueries in FROM section.
|
2015-07-26 07:08:46 +00:00
|
|
|
|
*/
|
2016-07-23 02:42:42 +00:00
|
|
|
|
if (!typeid_cast<ASTTableExpression *>(ast.get()))
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
/** Don't descend into subqueries in arguments of IN operator.
|
|
|
|
|
* But if an argument is not subquery, than deeper may be scalar subqueries and we need to descend in them.
|
|
|
|
|
*/
|
|
|
|
|
ASTFunction * func = typeid_cast<ASTFunction *>(ast.get());
|
|
|
|
|
|
|
|
|
|
if (func && func->kind == ASTFunction::FUNCTION
|
|
|
|
|
&& functionIsInOrGlobalInOperator(func->name))
|
2015-07-26 07:08:46 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
{
|
|
|
|
|
if (child != func->arguments)
|
|
|
|
|
executeScalarSubqueriesImpl(child);
|
|
|
|
|
else
|
|
|
|
|
for (size_t i = 0, size = func->arguments->children.size(); i < size; ++i)
|
|
|
|
|
if (i != 1 || !typeid_cast<ASTSubquery *>(func->arguments->children[i].get()))
|
|
|
|
|
executeScalarSubqueriesImpl(func->arguments->children[i]);
|
|
|
|
|
}
|
2015-07-26 07:08:46 +00:00
|
|
|
|
}
|
2016-07-23 02:25:09 +00:00
|
|
|
|
else
|
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
executeScalarSubqueriesImpl(child);
|
2015-07-26 07:08:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-07-25 11:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-08-04 15:25:38 +00:00
|
|
|
|
void ExpressionAnalyzer::optimizeGroupBy()
|
2014-07-31 07:24:07 +00:00
|
|
|
|
{
|
|
|
|
|
if (!(select_query && select_query->group_expression_list))
|
|
|
|
|
return;
|
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
const auto is_literal = [] (const ASTPtr& ast) {
|
|
|
|
|
return typeid_cast<const ASTLiteral*>(ast.get());
|
|
|
|
|
};
|
2014-07-31 07:24:07 +00:00
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
auto & group_exprs = select_query->group_expression_list->children;
|
2014-07-31 07:24:07 +00:00
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
/// removes expression at index idx by making it last one and calling .pop_back()
|
2014-08-19 23:12:31 +00:00
|
|
|
|
const auto remove_expr_at_index = [&group_exprs] (const size_t idx)
|
|
|
|
|
{
|
2014-07-31 11:26:05 +00:00
|
|
|
|
if (idx < group_exprs.size() - 1)
|
2014-10-02 18:34:49 +00:00
|
|
|
|
std::swap(group_exprs[idx], group_exprs.back());
|
2014-07-31 07:24:07 +00:00
|
|
|
|
|
2014-07-31 11:26:05 +00:00
|
|
|
|
group_exprs.pop_back();
|
|
|
|
|
};
|
2014-07-31 07:24:07 +00:00
|
|
|
|
|
2014-07-31 11:27:34 +00:00
|
|
|
|
/// iterate over each GROUP BY expression, eliminate injective function calls and literals
|
2014-08-08 06:08:17 +00:00
|
|
|
|
for (size_t i = 0; i < group_exprs.size();)
|
2014-07-31 11:26:05 +00:00
|
|
|
|
{
|
2015-05-13 16:11:07 +00:00
|
|
|
|
if (const auto function = typeid_cast<ASTFunction *>(group_exprs[i].get()))
|
2014-07-31 11:26:05 +00:00
|
|
|
|
{
|
|
|
|
|
/// assert function is injective
|
2015-05-13 16:11:07 +00:00
|
|
|
|
if (possibly_injective_function_names.count(function->name))
|
|
|
|
|
{
|
|
|
|
|
/// do not handle semantic errors here
|
|
|
|
|
if (function->arguments->children.size() < 2)
|
|
|
|
|
{
|
|
|
|
|
++i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto & dict_name = typeid_cast<const ASTLiteral &>(*function->arguments->children[0])
|
|
|
|
|
.value.safeGet<String>();
|
|
|
|
|
|
|
|
|
|
const auto & dict_ptr = context.getExternalDictionaries().getDictionary(dict_name);
|
|
|
|
|
|
|
|
|
|
const auto & attr_name = typeid_cast<const ASTLiteral &>(*function->arguments->children[1])
|
|
|
|
|
.value.safeGet<String>();
|
|
|
|
|
|
|
|
|
|
if (!dict_ptr->isInjective(attr_name))
|
|
|
|
|
{
|
|
|
|
|
++i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!injective_function_names.count(function->name))
|
2014-08-08 06:08:17 +00:00
|
|
|
|
{
|
|
|
|
|
++i;
|
2014-07-31 11:26:05 +00:00
|
|
|
|
continue;
|
2014-08-08 06:08:17 +00:00
|
|
|
|
}
|
2014-07-31 11:26:05 +00:00
|
|
|
|
|
|
|
|
|
/// copy shared pointer to args in order to ensure lifetime
|
|
|
|
|
auto args_ast = function->arguments;
|
|
|
|
|
|
|
|
|
|
/** remove function call and take a step back to ensure
|
|
|
|
|
* next iteration does not skip not yet processed data
|
|
|
|
|
*/
|
|
|
|
|
remove_expr_at_index(i);
|
|
|
|
|
|
|
|
|
|
/// copy non-literal arguments
|
|
|
|
|
std::remove_copy_if(
|
|
|
|
|
std::begin(args_ast->children), std::end(args_ast->children),
|
|
|
|
|
std::back_inserter(group_exprs), is_literal
|
|
|
|
|
);
|
|
|
|
|
}
|
2014-08-04 15:25:38 +00:00
|
|
|
|
else if (is_literal(group_exprs[i]))
|
|
|
|
|
{
|
|
|
|
|
remove_expr_at_index(i);
|
2014-08-08 06:08:17 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/// if neither a function nor literal - advance to next expression
|
|
|
|
|
++i;
|
2014-08-04 15:25:38 +00:00
|
|
|
|
}
|
2014-07-31 07:24:07 +00:00
|
|
|
|
}
|
2014-08-04 15:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (group_exprs.empty())
|
2015-10-21 21:43:42 +00:00
|
|
|
|
{
|
|
|
|
|
/** Нельзя полностью убирать GROUP BY. Потому что если при этом даже агрегатных функций не было, то получится, что не будет агрегации.
|
|
|
|
|
* Вместо этого оставим GROUP BY const.
|
|
|
|
|
* Далее см. удаление констант в методе analyzeAggregation.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/// Нужно вставить константу, которая не является именем столбца таблицы. Такой случай редкий, но бывает.
|
|
|
|
|
UInt64 unused_column = 0;
|
|
|
|
|
String unused_column_name = toString(unused_column);
|
|
|
|
|
|
|
|
|
|
while (columns.end() != std::find_if(columns.begin(), columns.end(),
|
|
|
|
|
[&unused_column_name](const NameAndTypePair & name_type) { return name_type.name == unused_column_name; }))
|
|
|
|
|
{
|
|
|
|
|
++unused_column;
|
|
|
|
|
unused_column_name = toString(unused_column);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
select_query->group_expression_list = std::make_shared<ASTExpressionList>();
|
|
|
|
|
select_query->group_expression_list->children.emplace_back(std::make_shared<ASTLiteral>(StringRange(), UInt64(unused_column)));
|
2015-10-21 21:43:42 +00:00
|
|
|
|
}
|
2014-07-31 07:24:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-03-12 03:31:15 +00:00
|
|
|
|
void ExpressionAnalyzer::optimizeOrderBy()
|
|
|
|
|
{
|
|
|
|
|
if (!(select_query && select_query->order_expression_list))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/// Уникализируем условия сортировки.
|
|
|
|
|
using NameAndLocale = std::pair<std::string, std::string>;
|
|
|
|
|
std::set<NameAndLocale> elems_set;
|
|
|
|
|
|
|
|
|
|
ASTs & elems = select_query->order_expression_list->children;
|
|
|
|
|
ASTs unique_elems;
|
|
|
|
|
unique_elems.reserve(elems.size());
|
|
|
|
|
|
|
|
|
|
for (const auto & elem : elems)
|
|
|
|
|
{
|
|
|
|
|
String name = elem->children.front()->getColumnName();
|
|
|
|
|
const ASTOrderByElement & order_by_elem = typeid_cast<const ASTOrderByElement &>(*elem);
|
|
|
|
|
|
|
|
|
|
if (elems_set.emplace(
|
|
|
|
|
std::piecewise_construct,
|
|
|
|
|
std::forward_as_tuple(name),
|
|
|
|
|
std::forward_as_tuple(order_by_elem.collator ? order_by_elem.collator->getLocale() : std::string())).second)
|
|
|
|
|
{
|
|
|
|
|
unique_elems.emplace_back(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unique_elems.size() < elems.size())
|
|
|
|
|
elems = unique_elems;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-04-10 08:57:01 +00:00
|
|
|
|
void ExpressionAnalyzer::makeSetsForIndex()
|
2014-03-31 14:49:43 +00:00
|
|
|
|
{
|
2014-04-12 15:49:36 +00:00
|
|
|
|
if (storage && ast && storage->supportsIndexForIn())
|
2014-06-12 21:12:47 +00:00
|
|
|
|
makeSetsForIndexImpl(ast, storage->getSampleBlock());
|
2014-03-31 14:49:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 21:12:47 +00:00
|
|
|
|
void ExpressionAnalyzer::makeSetsForIndexImpl(ASTPtr & node, const Block & sample_block)
|
2014-03-31 14:49:43 +00:00
|
|
|
|
{
|
|
|
|
|
for (auto & child : node->children)
|
2014-06-12 21:12:47 +00:00
|
|
|
|
makeSetsForIndexImpl(child, sample_block);
|
2014-03-31 14:49:43 +00:00
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
ASTFunction * func = typeid_cast<ASTFunction *>(node.get());
|
2015-07-26 07:08:46 +00:00
|
|
|
|
if (func && func->kind == ASTFunction::FUNCTION && functionIsInOperator(func->name))
|
2014-03-31 14:49:43 +00:00
|
|
|
|
{
|
|
|
|
|
IAST & args = *func->arguments;
|
2014-07-06 04:22:12 +00:00
|
|
|
|
ASTPtr & arg = args.children.at(1);
|
2014-03-31 14:49:43 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (!typeid_cast<ASTSet *>(arg.get()) && !typeid_cast<ASTSubquery *>(arg.get()) && !typeid_cast<ASTIdentifier *>(arg.get()))
|
2014-04-09 08:44:15 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2014-04-10 08:57:01 +00:00
|
|
|
|
makeExplicitSet(func, sample_block, true);
|
2014-04-09 08:44:15 +00:00
|
|
|
|
}
|
|
|
|
|
catch (const DB::Exception & e)
|
|
|
|
|
{
|
|
|
|
|
/// в sample_block нет колонок, которые добаляет getActions
|
|
|
|
|
if (e.code() != ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK)
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-31 14:49:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
2014-03-14 14:52:48 +00:00
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
static std::shared_ptr<InterpreterSelectQuery> interpretSubquery(
|
2015-11-04 22:02:52 +00:00
|
|
|
|
ASTPtr & subquery_or_table_name, const Context & context, size_t subquery_depth, const Names & required_columns)
|
2014-03-14 14:52:48 +00:00
|
|
|
|
{
|
2014-07-04 01:40:22 +00:00
|
|
|
|
/// Подзапрос или имя таблицы. Имя таблицы аналогично подзапросу SELECT * FROM t.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
const ASTSubquery * subquery = typeid_cast<const ASTSubquery *>(subquery_or_table_name.get());
|
|
|
|
|
const ASTIdentifier * table = typeid_cast<const ASTIdentifier *>(subquery_or_table_name.get());
|
2014-03-14 14:52:48 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
if (!subquery && !table)
|
|
|
|
|
throw Exception("IN/JOIN supports only SELECT subqueries.", ErrorCodes::BAD_ARGUMENTS);
|
2014-04-01 14:06:58 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
/** Для подзапроса в секции IN/JOIN не действуют ограничения на максимальный размер результата.
|
|
|
|
|
* Так как результат этого поздапроса - ещё не результат всего запроса.
|
|
|
|
|
* Вместо этого работают ограничения
|
|
|
|
|
* max_rows_in_set, max_bytes_in_set, set_overflow_mode,
|
2015-07-25 11:47:50 +00:00
|
|
|
|
* max_rows_in_join, max_bytes_in_join, join_overflow_mode,
|
|
|
|
|
* которые проверяются отдельно (в объектах Set, Join).
|
2014-07-04 01:40:22 +00:00
|
|
|
|
*/
|
|
|
|
|
Context subquery_context = context;
|
|
|
|
|
Settings subquery_settings = context.getSettings();
|
|
|
|
|
subquery_settings.limits.max_result_rows = 0;
|
|
|
|
|
subquery_settings.limits.max_result_bytes = 0;
|
|
|
|
|
/// Вычисление extremes не имеет смысла и не нужно (если его делать, то в результате всего запроса могут взяться extremes подзапроса).
|
|
|
|
|
subquery_settings.extremes = 0;
|
|
|
|
|
subquery_context.setSettings(subquery_settings);
|
|
|
|
|
|
|
|
|
|
ASTPtr query;
|
|
|
|
|
if (table)
|
|
|
|
|
{
|
2014-12-23 00:31:11 +00:00
|
|
|
|
/// create ASTSelectQuery for "SELECT * FROM table" as if written by hand
|
2016-05-28 15:42:22 +00:00
|
|
|
|
const auto select_query = std::make_shared<ASTSelectQuery>();
|
2014-12-23 00:31:11 +00:00
|
|
|
|
query = select_query;
|
2015-01-14 02:44:25 +00:00
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
const auto select_expression_list = std::make_shared<ASTExpressionList>();
|
2014-12-23 00:31:11 +00:00
|
|
|
|
select_query->select_expression_list = select_expression_list;
|
|
|
|
|
select_query->children.emplace_back(select_query->select_expression_list);
|
|
|
|
|
|
|
|
|
|
/// get columns list for target table
|
|
|
|
|
const auto & storage = context.getTable("", table->name);
|
|
|
|
|
const auto & columns = storage->getColumnsListNonMaterialized();
|
|
|
|
|
select_expression_list->children.reserve(columns.size());
|
|
|
|
|
|
|
|
|
|
/// manually substitute column names in place of asterisk
|
|
|
|
|
for (const auto & column : columns)
|
2016-05-28 15:42:22 +00:00
|
|
|
|
select_expression_list->children.emplace_back(std::make_shared<ASTIdentifier>(
|
|
|
|
|
StringRange{}, column.name));
|
2014-12-23 00:31:11 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
select_query->replaceDatabaseAndTable("", table->name);
|
2014-03-14 14:52:48 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-09-02 20:35:38 +00:00
|
|
|
|
{
|
2014-07-04 01:40:22 +00:00
|
|
|
|
query = subquery->children.at(0);
|
|
|
|
|
|
2015-09-02 20:35:38 +00:00
|
|
|
|
/** В подзапросе могут быть указаны столбцы с одинаковыми именами. Например, SELECT x, x FROM t
|
|
|
|
|
* Это плохо, потому что результат такого запроса нельзя сохранить в таблицу, потому что в таблице не может быть одноимённых столбцов.
|
|
|
|
|
* Сохранение в таблицу требуется для GLOBAL-подзапросов.
|
|
|
|
|
*
|
|
|
|
|
* Чтобы избежать такой ситуации, будем переименовывать одинаковые столбцы.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
std::set<std::string> all_column_names;
|
|
|
|
|
std::set<std::string> assigned_column_names;
|
|
|
|
|
|
|
|
|
|
if (ASTSelectQuery * select = typeid_cast<ASTSelectQuery *>(query.get()))
|
|
|
|
|
{
|
|
|
|
|
for (auto & expr : select->select_expression_list->children)
|
|
|
|
|
all_column_names.insert(expr->getAliasOrColumnName());
|
|
|
|
|
|
|
|
|
|
for (auto & expr : select->select_expression_list->children)
|
|
|
|
|
{
|
|
|
|
|
auto name = expr->getAliasOrColumnName();
|
|
|
|
|
|
|
|
|
|
if (!assigned_column_names.insert(name).second)
|
|
|
|
|
{
|
|
|
|
|
size_t i = 1;
|
|
|
|
|
while (all_column_names.end() != all_column_names.find(name + "_" + toString(i)))
|
|
|
|
|
++i;
|
|
|
|
|
|
|
|
|
|
name = name + "_" + toString(i);
|
|
|
|
|
expr = expr->clone(); /// Отменяет склейку одинаковых выражений в дереве.
|
|
|
|
|
expr->setAlias(name);
|
|
|
|
|
|
|
|
|
|
all_column_names.insert(name);
|
|
|
|
|
assigned_column_names.insert(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
if (required_columns.empty())
|
2016-05-28 12:22:22 +00:00
|
|
|
|
return std::make_shared<InterpreterSelectQuery>(
|
|
|
|
|
query, subquery_context, QueryProcessingStage::Complete, subquery_depth + 1);
|
2014-07-06 19:48:39 +00:00
|
|
|
|
else
|
2016-05-28 12:22:22 +00:00
|
|
|
|
return std::make_shared<InterpreterSelectQuery>(
|
|
|
|
|
query, subquery_context, required_columns, QueryProcessingStage::Complete, subquery_depth + 1);
|
2014-07-06 19:48:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
|
2013-06-11 16:21:25 +00:00
|
|
|
|
void ExpressionAnalyzer::makeSet(ASTFunction * node, const Block & sample_block)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
/** Нужно преобразовать правый аргумент в множество.
|
2014-03-12 14:15:35 +00:00
|
|
|
|
* Это может быть имя таблицы, значение, перечисление значений или подзапрос.
|
2013-05-29 11:46:51 +00:00
|
|
|
|
* Перечисление значений парсится как функция tuple.
|
|
|
|
|
*/
|
|
|
|
|
IAST & args = *node->arguments;
|
2014-07-06 04:22:12 +00:00
|
|
|
|
ASTPtr & arg = args.children.at(1);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// Уже преобразовали.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (typeid_cast<ASTSet *>(arg.get()))
|
2013-06-26 16:31:49 +00:00
|
|
|
|
return;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 20:30:06 +00:00
|
|
|
|
/// Если подзапрос или имя таблицы для SELECT.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(arg.get());
|
|
|
|
|
if (typeid_cast<ASTSubquery *>(arg.get()) || identifier)
|
2013-05-29 11:46:51 +00:00
|
|
|
|
{
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// Получаем поток блоков для подзапроса. Создаём Set и кладём на место подзапроса.
|
|
|
|
|
String set_id = arg->getColumnName();
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto ast_set = std::make_shared<ASTSet>(set_id);
|
2014-03-04 11:26:55 +00:00
|
|
|
|
ASTPtr ast_set_ptr = ast_set;
|
2014-01-28 19:24:50 +00:00
|
|
|
|
|
2015-01-27 00:52:03 +00:00
|
|
|
|
/// Особый случай - если справа оператора IN указано имя таблицы, при чём, таблица имеет тип Set (заранее подготовленное множество).
|
|
|
|
|
/// TODO В этом синтаксисе не поддерживается указание имени БД.
|
|
|
|
|
if (identifier)
|
|
|
|
|
{
|
|
|
|
|
StoragePtr table = context.tryGetTable("", identifier->name);
|
|
|
|
|
|
|
|
|
|
if (table)
|
|
|
|
|
{
|
|
|
|
|
StorageSet * storage_set = typeid_cast<StorageSet *>(table.get());
|
|
|
|
|
|
|
|
|
|
if (storage_set)
|
|
|
|
|
{
|
|
|
|
|
SetPtr & set = storage_set->getSet();
|
|
|
|
|
ast_set->set = set;
|
|
|
|
|
arg = ast_set_ptr;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
SubqueryForSet & subquery_for_set = subqueries_for_sets[set_id];
|
2014-05-14 13:47:37 +00:00
|
|
|
|
|
2015-01-27 00:52:03 +00:00
|
|
|
|
/// Если уже создали Set с таким же подзапросом/таблицей.
|
2014-07-06 19:48:39 +00:00
|
|
|
|
if (subquery_for_set.set)
|
2014-03-04 11:26:55 +00:00
|
|
|
|
{
|
2014-07-06 19:48:39 +00:00
|
|
|
|
ast_set->set = subquery_for_set.set;
|
|
|
|
|
arg = ast_set_ptr;
|
|
|
|
|
return;
|
2014-03-04 11:26:55 +00:00
|
|
|
|
}
|
2014-03-12 14:15:35 +00:00
|
|
|
|
|
2015-11-02 19:19:29 +00:00
|
|
|
|
ast_set->set = std::make_shared<Set>(settings.limits);
|
2014-06-12 21:12:47 +00:00
|
|
|
|
|
2014-07-06 20:46:17 +00:00
|
|
|
|
/** Для GLOBAL IN-ов происходит следующее:
|
|
|
|
|
* - в функции addExternalStorage подзапрос IN (SELECT ...) заменяется на IN _data1,
|
|
|
|
|
* в объекте subquery_for_set выставляется этот подзапрос в качестве source и временная таблица _data1 в качестве table.
|
|
|
|
|
* - в этой функции видно выражение IN _data1.
|
|
|
|
|
*/
|
|
|
|
|
if (!subquery_for_set.source)
|
2015-01-14 02:44:25 +00:00
|
|
|
|
{
|
2015-11-04 22:02:52 +00:00
|
|
|
|
auto interpreter = interpretSubquery(arg, context, subquery_depth, {});
|
2016-05-28 12:22:22 +00:00
|
|
|
|
subquery_for_set.source = std::make_shared<LazyBlockInputStream>(
|
|
|
|
|
[interpreter]() mutable { return interpreter->execute().in; });
|
2015-05-27 00:55:54 +00:00
|
|
|
|
subquery_for_set.source_sample = interpreter->getSampleBlock();
|
2015-01-14 02:44:25 +00:00
|
|
|
|
|
|
|
|
|
/** Зачем используется LazyBlockInputStream?
|
|
|
|
|
*
|
|
|
|
|
* Дело в том, что при обработке запроса вида
|
|
|
|
|
* SELECT ... FROM remote_test WHERE column GLOBAL IN (subquery),
|
|
|
|
|
* если распределённая таблица remote_test содержит в качестве одного из серверов localhost,
|
|
|
|
|
* то запрос будет ещё раз интерпретирован локально (а не отправлен по TCP, как в случае удалённого сервера).
|
|
|
|
|
*
|
|
|
|
|
* Конвейер выполнения запроса будет такой:
|
|
|
|
|
* CreatingSets
|
|
|
|
|
* выполнение подзапроса subquery, заполнение временной таблицы _data1 (1)
|
|
|
|
|
* CreatingSets
|
|
|
|
|
* чтение из таблицы _data1, создание множества (2)
|
|
|
|
|
* чтение из таблицы, подчинённой remote_test.
|
|
|
|
|
*
|
|
|
|
|
* (Вторая часть конвейера под CreatingSets - это повторная интерпретация запроса внутри StorageDistributed,
|
|
|
|
|
* запрос отличается тем, что имя БД и таблицы заменены на подчинённые, а также подзапрос заменён на _data1.)
|
|
|
|
|
*
|
|
|
|
|
* Но при создании конвейера, при создании источника (2), будет обнаружено, что таблица _data1 пустая
|
|
|
|
|
* (потому что запрос ещё не начал выполняться), и будет возвращён в качестве источника пустой источник.
|
|
|
|
|
* И затем, при выполнении запроса, на шаге (2), будет создано пустое множество.
|
|
|
|
|
*
|
|
|
|
|
* Поэтому, мы делаем инициализацию шага (2) ленивой
|
|
|
|
|
* - чтобы она произошла только после выполнения шага (1), на котором нужная таблица будет заполнена.
|
|
|
|
|
*
|
|
|
|
|
* Замечание: это решение не очень хорошее, надо подумать лучше.
|
|
|
|
|
*/
|
|
|
|
|
}
|
2014-07-06 20:46:17 +00:00
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
subquery_for_set.set = ast_set->set;
|
2014-03-04 11:26:55 +00:00
|
|
|
|
arg = ast_set_ptr;
|
2013-05-29 11:46:51 +00:00
|
|
|
|
}
|
2013-06-26 16:31:49 +00:00
|
|
|
|
else
|
2013-05-29 11:46:51 +00:00
|
|
|
|
{
|
2014-06-12 21:12:47 +00:00
|
|
|
|
/// Явное перечисление значений в скобках.
|
2014-04-01 10:09:22 +00:00
|
|
|
|
makeExplicitSet(node, sample_block, false);
|
2014-03-31 14:49:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Случай явного перечисления значений.
|
2014-04-01 10:09:22 +00:00
|
|
|
|
void ExpressionAnalyzer::makeExplicitSet(ASTFunction * node, const Block & sample_block, bool create_ordered_set)
|
2014-03-31 14:49:43 +00:00
|
|
|
|
{
|
2015-05-03 08:35:50 +00:00
|
|
|
|
IAST & args = *node->arguments;
|
2015-09-11 20:58:44 +00:00
|
|
|
|
|
|
|
|
|
if (args.children.size() != 2)
|
|
|
|
|
throw Exception("Wrong number of arguments passed to function in", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
ASTPtr & arg = args.children.at(1);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
DataTypes set_element_types;
|
|
|
|
|
ASTPtr & left_arg = args.children.at(0);
|
2013-05-29 11:46:51 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * left_arg_tuple = typeid_cast<ASTFunction *>(left_arg.get());
|
2013-05-29 11:46:51 +00:00
|
|
|
|
|
2016-07-10 07:24:24 +00:00
|
|
|
|
/** NOTE If tuple in left hand side specified non-explicitly
|
|
|
|
|
* Example: identity((a, b)) IN ((1, 2), (3, 4))
|
|
|
|
|
* instead of (a, b)) IN ((1, 2), (3, 4))
|
|
|
|
|
* then set creation of set doesn't work correctly.
|
|
|
|
|
*/
|
2015-05-03 08:35:50 +00:00
|
|
|
|
if (left_arg_tuple && left_arg_tuple->name == "tuple")
|
|
|
|
|
{
|
|
|
|
|
for (const auto & arg : left_arg_tuple->arguments->children)
|
2013-05-29 11:46:51 +00:00
|
|
|
|
{
|
2015-05-03 08:35:50 +00:00
|
|
|
|
const auto & data_type = sample_block.getByName(arg->getColumnName()).type;
|
2014-10-21 13:07:38 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
/// @note prevent crash in query: SELECT (1, [1]) in (1, 1)
|
|
|
|
|
if (const auto array = typeid_cast<const DataTypeArray * >(data_type.get()))
|
|
|
|
|
throw Exception("Incorrect element of tuple: " + array->getName(), ErrorCodes::INCORRECT_ELEMENT_OF_SET);
|
2014-10-21 13:07:38 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
set_element_types.push_back(data_type);
|
2013-05-29 11:46:51 +00:00
|
|
|
|
}
|
2015-05-03 08:35:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DataTypePtr left_type = sample_block.getByName(left_arg->getColumnName()).type;
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (DataTypeArray * array_type = typeid_cast<DataTypeArray *>(left_type.get()))
|
2015-05-03 08:35:50 +00:00
|
|
|
|
set_element_types.push_back(array_type->getNestedType());
|
2013-05-29 11:46:51 +00:00
|
|
|
|
else
|
2015-05-03 08:35:50 +00:00
|
|
|
|
set_element_types.push_back(left_type);
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
/// Отличим случай x in (1, 2) от случая x in 1 (он же x in (1)).
|
|
|
|
|
bool single_value = false;
|
|
|
|
|
ASTPtr elements_ast = arg;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTFunction * set_func = typeid_cast<ASTFunction *>(arg.get()))
|
2015-05-03 08:35:50 +00:00
|
|
|
|
{
|
2015-06-12 05:54:49 +00:00
|
|
|
|
if (set_func->name == "tuple")
|
|
|
|
|
{
|
2015-09-11 20:58:44 +00:00
|
|
|
|
if (set_func->arguments->children.empty())
|
|
|
|
|
{
|
|
|
|
|
/// Пустое множество.
|
2015-06-12 05:54:49 +00:00
|
|
|
|
elements_ast = set_func->arguments;
|
2015-09-11 20:58:44 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-03-05 03:17:11 +00:00
|
|
|
|
/// Отличим случай (x, y) in ((1, 2), (3, 4)) от случая (x, y) in (1, 2).
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * any_element = typeid_cast<ASTFunction *>(set_func->arguments->children.at(0).get());
|
2015-09-11 20:58:44 +00:00
|
|
|
|
if (set_element_types.size() >= 2 && (!any_element || any_element->name != "tuple"))
|
|
|
|
|
single_value = true;
|
|
|
|
|
else
|
|
|
|
|
elements_ast = set_func->arguments;
|
|
|
|
|
}
|
2015-06-12 05:54:49 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (set_element_types.size() >= 2)
|
|
|
|
|
throw Exception("Incorrect type of 2nd argument for function " + node->name
|
|
|
|
|
+ ". Must be subquery or set of " + toString(set_element_types.size()) + "-element tuples.",
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
single_value = true;
|
2015-06-12 05:54:49 +00:00
|
|
|
|
}
|
2015-05-03 08:35:50 +00:00
|
|
|
|
}
|
2016-03-05 02:30:20 +00:00
|
|
|
|
else if (typeid_cast<ASTLiteral *>(arg.get()))
|
2015-05-03 08:35:50 +00:00
|
|
|
|
{
|
|
|
|
|
single_value = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw Exception("Incorrect type of 2nd argument for function " + node->name + ". Must be subquery or set of values.",
|
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-05-03 08:35:50 +00:00
|
|
|
|
if (single_value)
|
|
|
|
|
{
|
2016-05-28 15:42:22 +00:00
|
|
|
|
ASTPtr exp_list = std::make_shared<ASTExpressionList>();
|
2015-05-03 08:35:50 +00:00
|
|
|
|
exp_list->children.push_back(elements_ast);
|
|
|
|
|
elements_ast = exp_list;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
|
auto ast_set = std::make_shared<ASTSet>(arg->getColumnName());
|
2015-11-02 19:19:29 +00:00
|
|
|
|
ast_set->set = std::make_shared<Set>(settings.limits);
|
2015-05-03 08:35:50 +00:00
|
|
|
|
ast_set->is_explicit = true;
|
2015-06-12 05:18:47 +00:00
|
|
|
|
ast_set->set->createFromAST(set_element_types, elements_ast, context, create_ordered_set);
|
2016-05-28 15:42:22 +00:00
|
|
|
|
arg = ast_set;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-07-06 00:19:49 +00:00
|
|
|
|
static String getUniqueName(const Block & block, const String & prefix)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
int i = 1;
|
2013-06-21 20:34:19 +00:00
|
|
|
|
while (block.has(prefix + toString(i)))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
++i;
|
2013-06-21 20:34:19 +00:00
|
|
|
|
return prefix + toString(i);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-06-12 19:53:36 +00:00
|
|
|
|
/** Для getActionsImpl.
|
|
|
|
|
* Стек из ExpressionActions, соответствующих вложенным лямбда-выражениям.
|
|
|
|
|
* Новое действие нужно добавлять на самый высокий возможный уровень.
|
|
|
|
|
* Например, в выражении "select arrayMap(x -> x + column1 * column2, array1)"
|
|
|
|
|
* вычисление произведения нужно делать вне лямбда-выражения (оно не зависит от x), а вычисление суммы - внутри (зависит от x).
|
|
|
|
|
*/
|
|
|
|
|
struct ExpressionAnalyzer::ScopeStack
|
|
|
|
|
{
|
|
|
|
|
struct Level
|
|
|
|
|
{
|
|
|
|
|
ExpressionActionsPtr actions;
|
|
|
|
|
NameSet new_columns;
|
|
|
|
|
};
|
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Levels = std::vector<Level>;
|
2014-06-12 19:53:36 +00:00
|
|
|
|
|
|
|
|
|
Levels stack;
|
|
|
|
|
Settings settings;
|
|
|
|
|
|
2014-06-24 19:53:48 +00:00
|
|
|
|
ScopeStack(const ExpressionActionsPtr & actions, const Settings & settings_)
|
2014-06-12 19:53:36 +00:00
|
|
|
|
: settings(settings_)
|
|
|
|
|
{
|
2014-07-06 00:19:49 +00:00
|
|
|
|
stack.emplace_back();
|
2014-06-24 19:53:48 +00:00
|
|
|
|
stack.back().actions = actions;
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
|
|
|
|
const Block & sample_block = actions->getSampleBlock();
|
|
|
|
|
for (size_t i = 0, size = sample_block.columns(); i < size; ++i)
|
|
|
|
|
stack.back().new_columns.insert(sample_block.unsafeGetByPosition(i).name);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pushLevel(const NamesAndTypesList & input_columns)
|
|
|
|
|
{
|
2014-07-06 00:19:49 +00:00
|
|
|
|
stack.emplace_back();
|
2014-06-12 19:53:36 +00:00
|
|
|
|
Level & prev = stack[stack.size() - 2];
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnsWithTypeAndName all_columns;
|
2014-06-12 19:53:36 +00:00
|
|
|
|
NameSet new_names;
|
|
|
|
|
|
|
|
|
|
for (NamesAndTypesList::const_iterator it = input_columns.begin(); it != input_columns.end(); ++it)
|
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
all_columns.emplace_back(nullptr, it->type, it->name);
|
|
|
|
|
new_names.insert(it->name);
|
|
|
|
|
stack.back().new_columns.insert(it->name);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-25 00:17:51 +00:00
|
|
|
|
const Block & prev_sample_block = prev.actions->getSampleBlock();
|
|
|
|
|
for (size_t i = 0, size = prev_sample_block.columns(); i < size; ++i)
|
2014-06-12 19:53:36 +00:00
|
|
|
|
{
|
2015-07-17 01:27:35 +00:00
|
|
|
|
const ColumnWithTypeAndName & col = prev_sample_block.unsafeGetByPosition(i);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
if (!new_names.count(col.name))
|
|
|
|
|
all_columns.push_back(col);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-13 00:32:59 +00:00
|
|
|
|
stack.back().actions = std::make_shared<ExpressionActions>(all_columns, settings);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t getColumnLevel(const std::string & name)
|
|
|
|
|
{
|
|
|
|
|
for (int i = static_cast<int>(stack.size()) - 1; i >= 0; --i)
|
|
|
|
|
if (stack[i].new_columns.count(name))
|
|
|
|
|
return i;
|
|
|
|
|
|
|
|
|
|
throw Exception("Unknown identifier: " + name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addAction(const ExpressionAction & action, const Names & additional_required_columns = Names())
|
|
|
|
|
{
|
|
|
|
|
size_t level = 0;
|
|
|
|
|
for (size_t i = 0; i < additional_required_columns.size(); ++i)
|
|
|
|
|
level = std::max(level, getColumnLevel(additional_required_columns[i]));
|
|
|
|
|
Names required = action.getNeededColumns();
|
|
|
|
|
for (size_t i = 0; i < required.size(); ++i)
|
|
|
|
|
level = std::max(level, getColumnLevel(required[i]));
|
|
|
|
|
|
|
|
|
|
Names added;
|
|
|
|
|
stack[level].actions->add(action, added);
|
|
|
|
|
|
|
|
|
|
stack[level].new_columns.insert(added.begin(), added.end());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < added.size(); ++i)
|
|
|
|
|
{
|
2015-07-17 01:27:35 +00:00
|
|
|
|
const ColumnWithTypeAndName & col = stack[level].actions->getSampleBlock().getByName(added[i]);
|
2014-06-12 19:53:36 +00:00
|
|
|
|
for (size_t j = level + 1; j < stack.size(); ++j)
|
|
|
|
|
stack[j].actions->addInput(col);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExpressionActionsPtr popLevel()
|
|
|
|
|
{
|
|
|
|
|
ExpressionActionsPtr res = stack.back().actions;
|
|
|
|
|
stack.pop_back();
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
const Block & getSampleBlock() const
|
2014-06-12 19:53:36 +00:00
|
|
|
|
{
|
|
|
|
|
return stack.back().actions->getSampleBlock();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
void ExpressionAnalyzer::getRootActions(ASTPtr ast, bool no_subqueries, bool only_consts, ExpressionActionsPtr & actions)
|
2013-06-11 16:21:25 +00:00
|
|
|
|
{
|
|
|
|
|
ScopeStack scopes(actions, settings);
|
2013-07-26 16:11:31 +00:00
|
|
|
|
getActionsImpl(ast, no_subqueries, only_consts, scopes);
|
2014-06-24 19:53:48 +00:00
|
|
|
|
actions = scopes.popLevel();
|
2013-06-11 16:21:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-08-01 13:29:32 +00:00
|
|
|
|
void ExpressionAnalyzer::getArrayJoinedColumns()
|
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (select_query && select_query->array_join_expression_list())
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
ASTs & array_join_asts = select_query->array_join_expression_list()->children;
|
2015-06-08 15:22:04 +00:00
|
|
|
|
for (const auto & ast : array_join_asts)
|
2013-10-21 11:33:25 +00:00
|
|
|
|
{
|
2015-06-08 15:22:04 +00:00
|
|
|
|
const String nested_table_name = ast->getColumnName();
|
|
|
|
|
const String nested_table_alias = ast->getAliasOrColumnName();
|
2015-10-22 20:56:52 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (nested_table_alias == nested_table_name && !typeid_cast<const ASTIdentifier *>(ast.get()))
|
2013-10-21 11:33:25 +00:00
|
|
|
|
throw Exception("No alias for non-trivial value in ARRAY JOIN: " + nested_table_name, ErrorCodes::ALIAS_REQUIRED);
|
|
|
|
|
|
|
|
|
|
if (array_join_alias_to_name.count(nested_table_alias) || aliases.count(nested_table_alias))
|
2016-07-23 02:25:09 +00:00
|
|
|
|
throw Exception("Duplicate alias in ARRAY JOIN: " + nested_table_alias, ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS);
|
2015-10-22 20:56:52 +00:00
|
|
|
|
|
2013-10-21 11:33:25 +00:00
|
|
|
|
array_join_alias_to_name[nested_table_alias] = nested_table_name;
|
2015-10-22 20:56:52 +00:00
|
|
|
|
array_join_name_to_alias[nested_table_name] = nested_table_alias;
|
2013-10-21 11:33:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
getArrayJoinedColumnsImpl(ast);
|
2013-10-18 08:40:14 +00:00
|
|
|
|
|
|
|
|
|
/// Если результат ARRAY JOIN не используется, придется все равно по-ARRAY-JOIN-ить какой-нибудь столбец,
|
|
|
|
|
/// чтобы получить правильное количество строк.
|
2013-10-21 11:33:25 +00:00
|
|
|
|
if (array_join_result_to_source.empty())
|
2013-10-18 08:40:14 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
ASTPtr expr = select_query->array_join_expression_list()->children.at(0);
|
2013-10-18 08:40:14 +00:00
|
|
|
|
String source_name = expr->getColumnName();
|
2014-07-03 22:39:13 +00:00
|
|
|
|
String result_name = expr->getAliasOrColumnName();
|
2014-06-12 21:12:47 +00:00
|
|
|
|
|
2013-10-18 08:40:14 +00:00
|
|
|
|
/// Это массив.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (!typeid_cast<ASTIdentifier *>(expr.get()) || findColumn(source_name, columns) != columns.end())
|
2013-10-18 08:40:14 +00:00
|
|
|
|
{
|
2013-10-21 11:33:25 +00:00
|
|
|
|
array_join_result_to_source[result_name] = source_name;
|
2013-10-18 08:40:14 +00:00
|
|
|
|
}
|
|
|
|
|
else /// Это вложенная таблица.
|
|
|
|
|
{
|
|
|
|
|
bool found = false;
|
2014-06-12 21:12:47 +00:00
|
|
|
|
for (const auto & column_name_type : columns)
|
2013-10-18 08:40:14 +00:00
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
String table_name = DataTypeNested::extractNestedTableName(column_name_type.name);
|
|
|
|
|
String column_name = DataTypeNested::extractNestedColumnName(column_name_type.name);
|
2013-10-18 08:40:14 +00:00
|
|
|
|
if (table_name == source_name)
|
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
array_join_result_to_source[DataTypeNested::concatenateNestedName(result_name, column_name)] = column_name_type.name;
|
2013-10-18 08:40:14 +00:00
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-21 11:33:25 +00:00
|
|
|
|
if (!found)
|
|
|
|
|
throw Exception("No columns in nested table " + source_name, ErrorCodes::EMPTY_NESTED_TABLE);
|
2013-10-18 08:40:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
2013-08-01 13:29:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-22 20:56:52 +00:00
|
|
|
|
/// Заполняет array_join_result_to_source: по каким столбцам-массивам размножить, и как их после этого назвать.
|
2013-08-01 13:29:32 +00:00
|
|
|
|
void ExpressionAnalyzer::getArrayJoinedColumnsImpl(ASTPtr ast)
|
2013-07-26 16:11:31 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
if (typeid_cast<ASTTablesInSelectQuery *>(ast.get()))
|
|
|
|
|
return;
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTIdentifier * node = typeid_cast<ASTIdentifier *>(ast.get()))
|
2013-07-26 16:11:31 +00:00
|
|
|
|
{
|
2013-10-21 11:33:25 +00:00
|
|
|
|
if (node->kind == ASTIdentifier::Column)
|
|
|
|
|
{
|
|
|
|
|
String table_name = DataTypeNested::extractNestedTableName(node->name);
|
2015-10-22 20:56:52 +00:00
|
|
|
|
|
2013-10-21 11:33:25 +00:00
|
|
|
|
if (array_join_alias_to_name.count(node->name))
|
2015-10-22 20:56:52 +00:00
|
|
|
|
{
|
|
|
|
|
/// Был написан ARRAY JOIN со столбцом-массивом. Пример: SELECT K1 FROM ... ARRAY JOIN ParsedParams.Key1 AS K1
|
|
|
|
|
array_join_result_to_source[node->name] = array_join_alias_to_name[node->name]; /// K1 -> ParsedParams.Key1
|
|
|
|
|
}
|
2013-10-21 11:33:25 +00:00
|
|
|
|
else if (array_join_alias_to_name.count(table_name))
|
|
|
|
|
{
|
2015-10-22 20:56:52 +00:00
|
|
|
|
/// Был написан ARRAY JOIN с вложенной таблицей. Пример: SELECT PP.Key1 FROM ... ARRAY JOIN ParsedParams AS PP
|
|
|
|
|
String nested_column = DataTypeNested::extractNestedColumnName(node->name); /// Key1
|
|
|
|
|
array_join_result_to_source[node->name] /// PP.Key1 -> ParsedParams.Key1
|
2013-10-21 11:33:25 +00:00
|
|
|
|
= DataTypeNested::concatenateNestedName(array_join_alias_to_name[table_name], nested_column);
|
|
|
|
|
}
|
2015-10-22 20:56:52 +00:00
|
|
|
|
else if (array_join_name_to_alias.count(table_name))
|
|
|
|
|
{
|
|
|
|
|
/** Пример: SELECT ParsedParams.Key1 FROM ... ARRAY JOIN ParsedParams AS PP.
|
|
|
|
|
* То есть, в запросе используется исходный массив, размноженный по самому себе.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
String nested_column = DataTypeNested::extractNestedColumnName(node->name); /// Key1
|
|
|
|
|
array_join_result_to_source[ /// PP.Key1 -> ParsedParams.Key1
|
|
|
|
|
DataTypeNested::concatenateNestedName(array_join_name_to_alias[table_name], nested_column)] = node->name;
|
|
|
|
|
}
|
2013-10-21 11:33:25 +00:00
|
|
|
|
}
|
2013-07-26 16:11:31 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-07-04 20:30:06 +00:00
|
|
|
|
for (auto & child : ast->children)
|
2016-07-28 20:25:38 +00:00
|
|
|
|
if (!typeid_cast<const ASTSubquery *>(child.get())
|
|
|
|
|
&& !typeid_cast<const ASTSelectQuery *>(child.get()))
|
2014-07-04 20:30:06 +00:00
|
|
|
|
getArrayJoinedColumnsImpl(child);
|
2013-07-26 16:11:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::getActionsImpl(ASTPtr ast, bool no_subqueries, bool only_consts, ScopeStack & actions_stack)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
/// Если результат вычисления уже есть в блоке.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if ((typeid_cast<ASTFunction *>(ast.get()) || typeid_cast<ASTLiteral *>(ast.get()))
|
2013-06-11 16:21:25 +00:00
|
|
|
|
&& actions_stack.getSampleBlock().has(ast->getColumnName()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTIdentifier * node = typeid_cast<ASTIdentifier *>(ast.get()))
|
2014-01-13 11:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
std::string name = node->getColumnName();
|
|
|
|
|
if (!only_consts && !actions_stack.getSampleBlock().has(name))
|
|
|
|
|
{
|
|
|
|
|
/// Запрошенного столбца нет в блоке.
|
2014-03-28 12:13:58 +00:00
|
|
|
|
/// Если такой столбец есть в таблице, значит пользователь наверно забыл окружить его агрегатной функцией или добавить в GROUP BY.
|
2014-01-13 11:29:24 +00:00
|
|
|
|
|
|
|
|
|
bool found = false;
|
2014-06-12 21:12:47 +00:00
|
|
|
|
for (const auto & column_name_type : columns)
|
2014-07-09 11:45:51 +00:00
|
|
|
|
if (column_name_type.name == name)
|
2014-01-13 11:29:24 +00:00
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
|
throw Exception("Column " + name + " is not under aggregate function and not in GROUP BY.",
|
2014-01-29 19:00:19 +00:00
|
|
|
|
ErrorCodes::NOT_AN_AGGREGATE);
|
2014-01-13 11:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-05 02:30:20 +00:00
|
|
|
|
else if (ASTFunction * node = typeid_cast<ASTFunction *>(ast.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
if (node->kind == ASTFunction::LAMBDA_EXPRESSION)
|
2016-03-05 02:30:20 +00:00
|
|
|
|
throw Exception("Unexpected lambda expression", ErrorCodes::UNEXPECTED_EXPRESSION);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-10-22 20:56:52 +00:00
|
|
|
|
/// Функция arrayJoin.
|
2013-05-30 16:52:21 +00:00
|
|
|
|
if (node->kind == ASTFunction::ARRAY_JOIN)
|
|
|
|
|
{
|
|
|
|
|
if (node->arguments->children.size() != 1)
|
|
|
|
|
throw Exception("arrayJoin requires exactly 1 argument", ErrorCodes::TYPE_MISMATCH);
|
2015-10-22 20:56:52 +00:00
|
|
|
|
|
2014-07-06 04:22:12 +00:00
|
|
|
|
ASTPtr arg = node->arguments->children.at(0);
|
2013-07-26 16:11:31 +00:00
|
|
|
|
getActionsImpl(arg, no_subqueries, only_consts, actions_stack);
|
2013-05-30 16:52:21 +00:00
|
|
|
|
if (!only_consts)
|
2013-08-01 16:00:38 +00:00
|
|
|
|
{
|
2013-10-17 13:32:32 +00:00
|
|
|
|
String result_name = node->getColumnName();
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::copyColumn(arg->getColumnName(), result_name));
|
2013-10-17 13:32:32 +00:00
|
|
|
|
NameSet joined_columns;
|
|
|
|
|
joined_columns.insert(result_name);
|
2015-07-26 10:54:45 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::arrayJoin(joined_columns, false));
|
2013-08-01 16:00:38 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-29 11:46:51 +00:00
|
|
|
|
if (node->kind == ASTFunction::FUNCTION)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2015-07-26 07:08:46 +00:00
|
|
|
|
if (functionIsInOrGlobalInOperator(node->name))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
if (!no_subqueries)
|
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
/// Найдем тип первого аргумента (потом getActionsImpl вызовется для него снова и ни на что не повлияет).
|
2014-07-06 04:22:12 +00:00
|
|
|
|
getActionsImpl(node->arguments->children.at(0), no_subqueries, only_consts, actions_stack);
|
2014-07-04 20:30:06 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
/// Превратим tuple или подзапрос в множество.
|
2013-06-11 16:21:25 +00:00
|
|
|
|
makeSet(node, actions_stack.getSampleBlock());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-07 12:10:37 +00:00
|
|
|
|
if (!only_consts)
|
|
|
|
|
{
|
|
|
|
|
/// Мы в той части дерева, которую не собираемся вычислять. Нужно только определить типы.
|
|
|
|
|
/// Не будем выполнять подзапросы и составлять множества. Вставим произвольный столбец правильного типа.
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName fake_column;
|
2014-03-07 12:10:37 +00:00
|
|
|
|
fake_column.name = node->getColumnName();
|
2016-05-28 07:48:40 +00:00
|
|
|
|
fake_column.type = std::make_shared<DataTypeUInt8>();
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::addColumn(fake_column));
|
2014-07-06 04:22:12 +00:00
|
|
|
|
getActionsImpl(node->arguments->children.at(0), no_subqueries, only_consts, actions_stack);
|
2014-03-07 12:10:37 +00:00
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-04-15 23:10:29 +00:00
|
|
|
|
/// Особая функция indexHint. Всё, что внутри неё не вычисляется
|
|
|
|
|
/// (а используется только для анализа индекса, см. PKCondition).
|
|
|
|
|
if (node->name == "indexHint")
|
|
|
|
|
{
|
|
|
|
|
actions_stack.addAction(ExpressionAction::addColumn(ColumnWithTypeAndName(
|
2016-05-28 07:48:40 +00:00
|
|
|
|
std::make_shared<ColumnConstUInt8>(1, 1), std::make_shared<DataTypeUInt8>(), node->getColumnName())));
|
2016-04-15 23:10:29 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 23:19:14 +00:00
|
|
|
|
const FunctionPtr & function = getFunctionFromFactory(node->name, node->genus, context);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
Names argument_names;
|
|
|
|
|
DataTypes argument_types;
|
2013-06-03 14:33:14 +00:00
|
|
|
|
bool arguments_present = true;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
/// Если у функции есть аргумент-лямбда-выражение, нужно определить его тип до рекурсивного вызова.
|
|
|
|
|
bool has_lambda_arguments = false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-06 04:22:12 +00:00
|
|
|
|
for (auto & child : node->arguments->children)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * lambda = typeid_cast<ASTFunction *>(child.get());
|
|
|
|
|
ASTSet * set = typeid_cast<ASTSet *>(child.get());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (lambda && lambda->name == "lambda")
|
|
|
|
|
{
|
2013-06-03 14:33:14 +00:00
|
|
|
|
/// Если аргумент - лямбда-выражение, только запомним его примерный тип.
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (lambda->arguments->children.size() != 2)
|
|
|
|
|
throw Exception("lambda requires two arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * lambda_args_tuple = typeid_cast<ASTFunction *>(lambda->arguments->children.at(0).get());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple")
|
|
|
|
|
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
has_lambda_arguments = true;
|
2016-05-28 07:48:40 +00:00
|
|
|
|
argument_types.emplace_back(std::make_shared<DataTypeExpression>(DataTypes(lambda_args_tuple->arguments->children.size())));
|
2013-06-05 13:15:52 +00:00
|
|
|
|
/// Выберем название в следующем цикле.
|
2014-07-06 00:19:49 +00:00
|
|
|
|
argument_names.emplace_back();
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-06-26 16:31:49 +00:00
|
|
|
|
else if (set)
|
|
|
|
|
{
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName column;
|
2016-05-28 07:48:40 +00:00
|
|
|
|
column.type = std::make_shared<DataTypeSet>();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-03-04 11:26:55 +00:00
|
|
|
|
/// Если аргумент - множество, заданное перечислением значений, дадим ему уникальное имя,
|
|
|
|
|
/// чтобы множества с одинаковой записью не склеивались (у них может быть разный тип).
|
2014-07-06 19:48:39 +00:00
|
|
|
|
if (set->is_explicit)
|
2014-03-04 11:26:55 +00:00
|
|
|
|
column.name = getUniqueName(actions_stack.getSampleBlock(), "__set");
|
|
|
|
|
else
|
|
|
|
|
column.name = set->getColumnName();
|
|
|
|
|
|
|
|
|
|
if (!actions_stack.getSampleBlock().has(column.name))
|
|
|
|
|
{
|
2016-05-28 05:31:36 +00:00
|
|
|
|
column.column = std::make_shared<ColumnSet>(1, set->set);
|
2014-03-04 11:26:55 +00:00
|
|
|
|
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::addColumn(column));
|
2014-03-04 11:26:55 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-26 16:31:49 +00:00
|
|
|
|
argument_types.push_back(column.type);
|
|
|
|
|
argument_names.push_back(column.name);
|
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2013-06-03 14:33:14 +00:00
|
|
|
|
/// Если аргумент не лямбда-выражение, вызовемся рекурсивно и узнаем его тип.
|
2013-07-26 16:11:31 +00:00
|
|
|
|
getActionsImpl(child, no_subqueries, only_consts, actions_stack);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
std::string name = child->getColumnName();
|
2013-06-11 16:21:25 +00:00
|
|
|
|
if (actions_stack.getSampleBlock().has(name))
|
2013-06-03 14:33:14 +00:00
|
|
|
|
{
|
2013-06-11 16:21:25 +00:00
|
|
|
|
argument_types.push_back(actions_stack.getSampleBlock().getByName(name).type);
|
2013-06-03 14:33:14 +00:00
|
|
|
|
argument_names.push_back(name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (only_consts)
|
|
|
|
|
{
|
|
|
|
|
arguments_present = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw Exception("Unknown identifier: " + name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-03 14:33:14 +00:00
|
|
|
|
if (only_consts && !arguments_present)
|
|
|
|
|
return;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-11 16:21:25 +00:00
|
|
|
|
Names additional_requirements;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (has_lambda_arguments && !only_consts)
|
|
|
|
|
{
|
|
|
|
|
function->getLambdaArgumentTypes(argument_types);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
/// Вызовемся рекурсивно для лямбда-выражений.
|
|
|
|
|
for (size_t i = 0; i < node->arguments->children.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
ASTPtr child = node->arguments->children[i];
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * lambda = typeid_cast<ASTFunction *>(child.get());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (lambda && lambda->name == "lambda")
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
DataTypeExpression * lambda_type = typeid_cast<DataTypeExpression *>(argument_types[i].get());
|
|
|
|
|
ASTFunction * lambda_args_tuple = typeid_cast<ASTFunction *>(lambda->arguments->children.at(0).get());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
ASTs lambda_arg_asts = lambda_args_tuple->arguments->children;
|
2013-06-11 16:21:25 +00:00
|
|
|
|
NamesAndTypesList lambda_arguments;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
for (size_t j = 0; j < lambda_arg_asts.size(); ++j)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(lambda_arg_asts[j].get());
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (!identifier)
|
|
|
|
|
throw Exception("lambda argument declarations must be identifiers", ErrorCodes::TYPE_MISMATCH);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
String arg_name = identifier->name;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-31 07:24:07 +00:00
|
|
|
|
lambda_arguments.emplace_back(arg_name, lambda_type->getArgumentTypes()[j]);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-11 16:21:25 +00:00
|
|
|
|
actions_stack.pushLevel(lambda_arguments);
|
2014-07-06 04:22:12 +00:00
|
|
|
|
getActionsImpl(lambda->arguments->children.at(1), no_subqueries, only_consts, actions_stack);
|
2013-06-11 16:21:25 +00:00
|
|
|
|
ExpressionActionsPtr lambda_actions = actions_stack.popLevel();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-06 04:22:12 +00:00
|
|
|
|
String result_name = lambda->arguments->children.at(1)->getColumnName();
|
2013-05-28 11:54:37 +00:00
|
|
|
|
lambda_actions->finalize(Names(1, result_name));
|
2013-05-24 10:49:19 +00:00
|
|
|
|
DataTypePtr result_type = lambda_actions->getSampleBlock().getByName(result_name).type;
|
2016-05-28 07:48:40 +00:00
|
|
|
|
argument_types[i] = std::make_shared<DataTypeExpression>(lambda_type->getArgumentTypes(), result_type);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-11 16:21:25 +00:00
|
|
|
|
Names captured = lambda_actions->getRequiredColumns();
|
|
|
|
|
for (size_t j = 0; j < captured.size(); ++j)
|
|
|
|
|
if (findColumn(captured[j], lambda_arguments) == lambda_arguments.end())
|
|
|
|
|
additional_requirements.push_back(captured[j]);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-05 13:15:52 +00:00
|
|
|
|
/// Не можем дать название getColumnName(),
|
|
|
|
|
/// потому что оно не однозначно определяет выражение (типы аргументов могут быть разными).
|
2013-06-11 16:21:25 +00:00
|
|
|
|
argument_names[i] = getUniqueName(actions_stack.getSampleBlock(), "__lambda");
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName lambda_column;
|
2016-05-28 05:31:36 +00:00
|
|
|
|
lambda_column.column = std::make_shared<ColumnExpression>(1, lambda_actions, lambda_arguments, result_type, result_name);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
lambda_column.type = argument_types[i];
|
|
|
|
|
lambda_column.name = argument_names[i];
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::addColumn(lambda_column));
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (only_consts)
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < argument_names.size(); ++i)
|
|
|
|
|
{
|
2013-06-11 16:21:25 +00:00
|
|
|
|
if (!actions_stack.getSampleBlock().has(argument_names[i]))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-06-03 14:33:14 +00:00
|
|
|
|
arguments_present = false;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-03 14:33:14 +00:00
|
|
|
|
if (arguments_present)
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::applyFunction(function, argument_names, node->getColumnName()),
|
2013-06-11 16:21:25 +00:00
|
|
|
|
additional_requirements);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-05 02:30:20 +00:00
|
|
|
|
else if (ASTLiteral * node = typeid_cast<ASTLiteral *>(ast.get()))
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
DataTypePtr type = apply_visitor(FieldToDataType(), node->value);
|
2015-06-29 04:54:52 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName column;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
column.column = type->createConstColumn(1, node->value);
|
|
|
|
|
column.type = type;
|
|
|
|
|
column.name = node->getColumnName();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions_stack.addAction(ExpressionAction::addColumn(column));
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-07-04 20:30:06 +00:00
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
getActionsImpl(child, no_subqueries, only_consts, actions_stack);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
void ExpressionAnalyzer::getAggregates(const ASTPtr & ast, ExpressionActionsPtr & actions)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
/// Внутри WHERE и PREWHERE не может быть агрегатных функций.
|
|
|
|
|
if (select_query && (ast.get() == select_query->where_expression.get() || ast.get() == select_query->prewhere_expression.get()))
|
|
|
|
|
{
|
|
|
|
|
assertNoAggregates(ast, "in WHERE or PREWHERE");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Если мы анализируем не запрос SELECT, а отдельное выражение, то в нём не может быть агрегатных функций.
|
|
|
|
|
if (!select_query)
|
|
|
|
|
{
|
|
|
|
|
assertNoAggregates(ast, "in wrong place");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ASTFunction * node = typeid_cast<const ASTFunction *>(ast.get());
|
2013-05-29 11:46:51 +00:00
|
|
|
|
if (node && node->kind == ASTFunction::AGGREGATE_FUNCTION)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-05-29 11:46:51 +00:00
|
|
|
|
has_aggregation = true;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
AggregateDescription aggregate;
|
|
|
|
|
aggregate.column_name = node->getColumnName();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2015-03-12 02:22:55 +00:00
|
|
|
|
/// Агрегатные функции уникализируются.
|
2013-05-24 10:49:19 +00:00
|
|
|
|
for (size_t i = 0; i < aggregate_descriptions.size(); ++i)
|
|
|
|
|
if (aggregate_descriptions[i].column_name == aggregate.column_name)
|
|
|
|
|
return;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
const ASTs & arguments = node->arguments->children;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
aggregate.argument_names.resize(arguments.size());
|
|
|
|
|
DataTypes types(arguments.size());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
/// Внутри агрегатных функций не может быть других агрегатных функций.
|
|
|
|
|
assertNoAggregates(arguments[i], "inside another aggregate function");
|
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(arguments[i], true, false, actions);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
const std::string & name = arguments[i]->getColumnName();
|
2014-06-24 19:53:48 +00:00
|
|
|
|
types[i] = actions->getSampleBlock().getByName(name).type;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
aggregate.argument_names[i] = name;
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-27 14:02:55 +00:00
|
|
|
|
aggregate.function = context.getAggregateFunctionFactory().get(node->name, types);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-27 14:02:55 +00:00
|
|
|
|
if (node->parameters)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
const ASTs & parameters = typeid_cast<const ASTExpressionList &>(*node->parameters).children;
|
2014-03-25 18:16:26 +00:00
|
|
|
|
Array params_row(parameters.size());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-27 14:02:55 +00:00
|
|
|
|
for (size_t i = 0; i < parameters.size(); ++i)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
const ASTLiteral * lit = typeid_cast<const ASTLiteral *>(parameters[i].get());
|
2013-05-27 14:02:55 +00:00
|
|
|
|
if (!lit)
|
2016-03-05 02:30:20 +00:00
|
|
|
|
throw Exception("Parameters to aggregate functions must be literals",
|
|
|
|
|
ErrorCodes::PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-27 14:02:55 +00:00
|
|
|
|
params_row[i] = lit->value;
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-03-25 18:16:26 +00:00
|
|
|
|
aggregate.parameters = params_row;
|
2013-05-27 14:02:55 +00:00
|
|
|
|
aggregate.function->setParameters(params_row);
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-27 14:02:55 +00:00
|
|
|
|
aggregate.function->setArguments(types);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
aggregate_descriptions.push_back(aggregate);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
for (const auto & child : ast->children)
|
2016-07-28 20:25:38 +00:00
|
|
|
|
if (!typeid_cast<const ASTSubquery *>(child.get())
|
|
|
|
|
&& !typeid_cast<const ASTSelectQuery *>(child.get()))
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getAggregates(child, actions);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
|
|
|
|
|
void ExpressionAnalyzer::assertNoAggregates(const ASTPtr & ast, const char * description)
|
|
|
|
|
{
|
|
|
|
|
const ASTFunction * node = typeid_cast<const ASTFunction *>(ast.get());
|
|
|
|
|
|
|
|
|
|
if (node && node->kind == ASTFunction::AGGREGATE_FUNCTION)
|
|
|
|
|
throw Exception("Aggregate function " + node->getColumnName()
|
|
|
|
|
+ " is found " + String(description) + " in query", ErrorCodes::ILLEGAL_AGGREGATION);
|
|
|
|
|
|
|
|
|
|
for (const auto & child : ast->children)
|
2016-07-28 20:25:38 +00:00
|
|
|
|
if (!typeid_cast<const ASTSubquery *>(child.get())
|
|
|
|
|
&& !typeid_cast<const ASTSelectQuery *>(child.get()))
|
2016-03-05 02:30:20 +00:00
|
|
|
|
assertNoAggregates(child, description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::assertSelect() const
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
if (!select_query)
|
|
|
|
|
throw Exception("Not a select query", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
}
|
2013-06-14 16:38:54 +00:00
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::assertAggregation() const
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
|
|
|
|
if (!has_aggregation)
|
|
|
|
|
throw Exception("No aggregation", ErrorCodes::LOGICAL_ERROR);
|
2013-05-28 11:54:37 +00:00
|
|
|
|
}
|
2013-06-14 16:38:54 +00:00
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::initChain(ExpressionActionsChain & chain, const NamesAndTypesList & columns) const
|
2013-05-28 14:24:20 +00:00
|
|
|
|
{
|
|
|
|
|
if (chain.steps.empty())
|
|
|
|
|
{
|
|
|
|
|
chain.settings = settings;
|
2016-01-13 00:32:59 +00:00
|
|
|
|
chain.steps.emplace_back(std::make_shared<ExpressionActions>(columns, settings));
|
2013-05-28 14:24:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-05-28 11:54:37 +00:00
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
/// "Big" ARRAY JOIN.
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::addMultipleArrayJoinAction(ExpressionActionsPtr & actions) const
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
2013-10-21 11:33:25 +00:00
|
|
|
|
NameSet result_columns;
|
2015-04-18 22:30:43 +00:00
|
|
|
|
for (const auto & result_source : array_join_result_to_source)
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
2016-07-23 02:25:09 +00:00
|
|
|
|
/// Assign new names to columns, if needed.
|
2015-04-18 22:30:43 +00:00
|
|
|
|
if (result_source.first != result_source.second)
|
|
|
|
|
actions->add(ExpressionAction::copyColumn(result_source.second, result_source.first));
|
2015-10-22 20:56:52 +00:00
|
|
|
|
|
|
|
|
|
/// Сделать ARRAY JOIN (заменить массивы на их внутренности) для столбцов в этими новыми именами.
|
2015-04-18 22:30:43 +00:00
|
|
|
|
result_columns.insert(result_source.first);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
actions->add(ExpressionAction::arrayJoin(result_columns, select_query->array_join_is_left()));
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
bool ExpressionAnalyzer::appendArrayJoin(ExpressionActionsChain & chain, bool only_types)
|
2013-07-26 16:33:05 +00:00
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (!select_query->array_join_expression_list())
|
2013-07-26 16:33:05 +00:00
|
|
|
|
return false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-07-26 16:33:05 +00:00
|
|
|
|
initChain(chain, columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
getRootActions(select_query->array_join_expression_list(), only_types, false, step.actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-24 19:53:48 +00:00
|
|
|
|
addMultipleArrayJoinAction(step.actions);
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2013-07-26 16:33:05 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::addJoinAction(ExpressionActionsPtr & actions, bool only_types) const
|
2014-06-13 02:05:05 +00:00
|
|
|
|
{
|
2014-07-06 22:32:09 +00:00
|
|
|
|
if (only_types)
|
|
|
|
|
actions->add(ExpressionAction::ordinaryJoin(nullptr, columns_added_by_join));
|
|
|
|
|
else
|
|
|
|
|
for (auto & subquery_for_set : subqueries_for_sets)
|
|
|
|
|
if (subquery_for_set.second.join)
|
|
|
|
|
actions->add(ExpressionAction::ordinaryJoin(subquery_for_set.second.join, columns_added_by_join));
|
2014-06-13 02:05:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_types)
|
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (!select_query->join())
|
2014-06-13 02:05:05 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
initChain(chain, columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const ASTTablesInSelectQueryElement & join_element = static_cast<const ASTTablesInSelectQueryElement &>(*select_query->join());
|
|
|
|
|
const ASTTableJoin & join_params = static_cast<const ASTTableJoin &>(*join_element.table_join);
|
|
|
|
|
const ASTTableExpression & table_to_join = static_cast<const ASTTableExpression &>(*join_element.table_expression);
|
|
|
|
|
|
|
|
|
|
if (join_params.using_expression_list)
|
|
|
|
|
getRootActions(join_params.using_expression_list, only_types, false, step.actions);
|
2014-06-13 02:05:05 +00:00
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// Не поддерживается два JOIN-а с одинаковым подзапросом, но разными USING-ами.
|
2016-07-23 02:25:09 +00:00
|
|
|
|
String join_id = join_element.getTreeID();
|
2014-07-06 19:48:39 +00:00
|
|
|
|
|
|
|
|
|
SubqueryForSet & subquery_for_set = subqueries_for_sets[join_id];
|
2015-01-28 02:37:05 +00:00
|
|
|
|
|
|
|
|
|
/// Особый случай - если справа JOIN указано имя таблицы, при чём, таблица имеет тип Join (заранее подготовленное отображение).
|
|
|
|
|
/// TODO В этом синтаксисе не поддерживается указание имени БД.
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (table_to_join.database_and_table_name)
|
2015-01-28 02:37:05 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
StoragePtr table = context.tryGetTable("", static_cast<const ASTIdentifier &>(*table_to_join.database_and_table_name).name);
|
2015-01-28 02:37:05 +00:00
|
|
|
|
|
|
|
|
|
if (table)
|
|
|
|
|
{
|
|
|
|
|
StorageJoin * storage_join = typeid_cast<StorageJoin *>(table.get());
|
|
|
|
|
|
|
|
|
|
if (storage_join)
|
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
storage_join->assertCompatible(join_params.kind, join_params.strictness);
|
2015-01-28 02:37:05 +00:00
|
|
|
|
/// TODO Проверять набор ключей.
|
|
|
|
|
|
|
|
|
|
JoinPtr & join = storage_join->getJoin();
|
|
|
|
|
subquery_for_set.join = join;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
if (!subquery_for_set.join)
|
2014-06-13 06:39:15 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
JoinPtr join = std::make_shared<Join>(
|
|
|
|
|
join_key_names_left, join_key_names_right, settings.limits,
|
|
|
|
|
join_params.kind, join_params.strictness);
|
2014-06-13 06:39:15 +00:00
|
|
|
|
|
2014-07-02 20:23:48 +00:00
|
|
|
|
Names required_joined_columns(join_key_names_right.begin(), join_key_names_right.end());
|
2014-06-13 06:39:15 +00:00
|
|
|
|
for (const auto & name_type : columns_added_by_join)
|
2014-07-09 11:45:51 +00:00
|
|
|
|
required_joined_columns.push_back(name_type.name);
|
2014-06-13 06:39:15 +00:00
|
|
|
|
|
2015-09-05 01:53:16 +00:00
|
|
|
|
/** Для GLOBAL JOIN-ов (в случае, например, push-метода выполнения GLOBAL подзапросов) происходит следующее:
|
2014-07-06 20:46:17 +00:00
|
|
|
|
* - в функции addExternalStorage подзапрос JOIN (SELECT ...) заменяется на JOIN _data1,
|
|
|
|
|
* в объекте subquery_for_set выставляется этот подзапрос в качестве source и временная таблица _data1 в качестве table.
|
|
|
|
|
* - в этой функции видно выражение JOIN _data1.
|
|
|
|
|
*/
|
|
|
|
|
if (!subquery_for_set.source)
|
2015-01-14 02:44:25 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
ASTPtr table;
|
|
|
|
|
if (table_to_join.database_and_table_name)
|
|
|
|
|
table = table_to_join.database_and_table_name;
|
|
|
|
|
else
|
|
|
|
|
table = table_to_join.subquery;
|
|
|
|
|
|
|
|
|
|
auto interpreter = interpretSubquery(table, context, subquery_depth, required_joined_columns);
|
2016-05-28 12:22:22 +00:00
|
|
|
|
subquery_for_set.source = std::make_shared<LazyBlockInputStream>([interpreter]() mutable { return interpreter->execute().in; });
|
2015-05-27 00:55:54 +00:00
|
|
|
|
subquery_for_set.source_sample = interpreter->getSampleBlock();
|
2015-01-14 02:44:25 +00:00
|
|
|
|
}
|
2014-07-06 20:46:17 +00:00
|
|
|
|
|
2015-05-27 00:55:54 +00:00
|
|
|
|
/// TODO Это не нужно выставлять, когда JOIN нужен только на удалённых серверах.
|
2014-07-06 19:48:39 +00:00
|
|
|
|
subquery_for_set.join = join;
|
2015-05-27 00:55:54 +00:00
|
|
|
|
subquery_for_set.join->setSampleBlock(subquery_for_set.source_sample);
|
2014-06-13 06:39:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 19:53:48 +00:00
|
|
|
|
addJoinAction(step.actions, false);
|
2014-06-13 02:05:05 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
bool ExpressionAnalyzer::appendWhere(ExpressionActionsChain & chain, bool only_types)
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (!select_query->where_expression)
|
|
|
|
|
return false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
initChain(chain, columns);
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
step.required_output.push_back(select_query->where_expression->getColumnName());
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(select_query->where_expression, only_types, false, step.actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
bool ExpressionAnalyzer::appendGroupBy(ExpressionActionsChain & chain, bool only_types)
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertAggregation();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (!select_query->group_expression_list)
|
|
|
|
|
return false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
initChain(chain, columns);
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
ASTs asts = select_query->group_expression_list->children;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
|
|
|
|
{
|
2013-05-28 14:24:20 +00:00
|
|
|
|
step.required_output.push_back(asts[i]->getColumnName());
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(asts[i], only_types, false, step.actions);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
void ExpressionAnalyzer::appendAggregateFunctionsArguments(ExpressionActionsChain & chain, bool only_types)
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertAggregation();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
initChain(chain, columns);
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-29 11:46:51 +00:00
|
|
|
|
for (size_t i = 0; i < aggregate_descriptions.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
for (size_t j = 0; j < aggregate_descriptions[i].argument_names.size(); ++j)
|
|
|
|
|
{
|
|
|
|
|
step.required_output.push_back(aggregate_descriptions[i].argument_names[j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getActionsBeforeAggregation(select_query->select_expression_list, step.actions, only_types);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (select_query->having_expression)
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getActionsBeforeAggregation(select_query->having_expression, step.actions, only_types);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (select_query->order_expression_list)
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getActionsBeforeAggregation(select_query->order_expression_list, step.actions, only_types);
|
2013-05-28 11:54:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
bool ExpressionAnalyzer::appendHaving(ExpressionActionsChain & chain, bool only_types)
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertAggregation();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (!select_query->having_expression)
|
|
|
|
|
return false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
initChain(chain, aggregated_columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
step.required_output.push_back(select_query->having_expression->getColumnName());
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(select_query->having_expression, only_types, false, step.actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
return true;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
void ExpressionAnalyzer::appendSelect(ExpressionActionsChain & chain, bool only_types)
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
initChain(chain, aggregated_columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(select_query->select_expression_list, only_types, false, step.actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ASTs asts = select_query->select_expression_list->children;
|
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
step.required_output.push_back(asts[i]->getColumnName());
|
|
|
|
|
}
|
2013-05-28 11:54:37 +00:00
|
|
|
|
}
|
2013-05-24 10:49:19 +00:00
|
|
|
|
|
2014-03-28 12:13:58 +00:00
|
|
|
|
bool ExpressionAnalyzer::appendOrderBy(ExpressionActionsChain & chain, bool only_types)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-05-28 11:54:37 +00:00
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
if (!select_query->order_expression_list)
|
|
|
|
|
return false;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
initChain(chain, aggregated_columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(select_query->order_expression_list, only_types, false, step.actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ASTs asts = select_query->order_expression_list->children;
|
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTOrderByElement * ast = typeid_cast<ASTOrderByElement *>(asts[i].get());
|
2013-05-28 14:24:20 +00:00
|
|
|
|
if (!ast || ast->children.size() != 1)
|
|
|
|
|
throw Exception("Bad order expression AST", ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE);
|
2014-07-06 04:22:12 +00:00
|
|
|
|
ASTPtr order_expression = ast->children.at(0);
|
2013-05-28 14:24:20 +00:00
|
|
|
|
step.required_output.push_back(order_expression->getColumnName());
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::appendProjectResult(DB::ExpressionActionsChain & chain, bool only_types) const
|
2013-05-28 11:54:37 +00:00
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
initChain(chain, aggregated_columns);
|
|
|
|
|
ExpressionActionsChain::Step & step = chain.steps.back();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
NamesWithAliases result_columns;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 14:24:20 +00:00
|
|
|
|
ASTs asts = select_query->select_expression_list->children;
|
2015-05-03 09:13:08 +00:00
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2015-05-03 09:13:08 +00:00
|
|
|
|
result_columns.emplace_back(asts[i]->getColumnName(), asts[i]->getAliasOrColumnName());
|
|
|
|
|
step.required_output.push_back(result_columns.back().second);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-12 18:41:09 +00:00
|
|
|
|
step.actions->add(ExpressionAction::project(result_columns));
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
Block ExpressionAnalyzer::getSelectSampleBlock()
|
|
|
|
|
{
|
|
|
|
|
assertSelect();
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-01-13 00:32:59 +00:00
|
|
|
|
ExpressionActionsPtr temp_actions = std::make_shared<ExpressionActions>(aggregated_columns, settings);
|
2013-05-30 16:52:21 +00:00
|
|
|
|
NamesWithAliases result_columns;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
ASTs asts = select_query->select_expression_list->children;
|
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
|
|
|
|
{
|
2014-07-06 00:19:49 +00:00
|
|
|
|
result_columns.emplace_back(asts[i]->getColumnName(), asts[i]->getAliasOrColumnName());
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(asts[i], true, false, temp_actions);
|
2013-05-30 16:52:21 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-24 19:53:48 +00:00
|
|
|
|
temp_actions->add(ExpressionAction::project(result_columns));
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-24 19:53:48 +00:00
|
|
|
|
return temp_actions->getSampleBlock();
|
2013-05-30 16:52:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
void ExpressionAnalyzer::getActionsBeforeAggregation(ASTPtr ast, ExpressionActionsPtr & actions, bool no_subqueries)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * node = typeid_cast<ASTFunction *>(ast.get());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
if (node && node->kind == ASTFunction::AGGREGATE_FUNCTION)
|
|
|
|
|
for (auto & argument : node->arguments->children)
|
|
|
|
|
getRootActions(argument, no_subqueries, false, actions);
|
2013-05-29 11:46:51 +00:00
|
|
|
|
else
|
2014-07-04 01:40:22 +00:00
|
|
|
|
for (auto & child : ast->children)
|
|
|
|
|
getActionsBeforeAggregation(child, actions, no_subqueries);
|
2013-05-29 11:46:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-03 13:17:17 +00:00
|
|
|
|
ExpressionActionsPtr ExpressionAnalyzer::getActions(bool project_result)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2016-01-13 00:32:59 +00:00
|
|
|
|
ExpressionActionsPtr actions = std::make_shared<ExpressionActions>(columns, settings);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
NamesWithAliases result_columns;
|
2013-05-28 11:54:37 +00:00
|
|
|
|
Names result_names;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-17 13:29:50 +00:00
|
|
|
|
ASTs asts;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (auto node = typeid_cast<const ASTExpressionList *>(ast.get()))
|
2013-06-17 13:29:50 +00:00
|
|
|
|
asts = node->children;
|
2013-05-24 10:49:19 +00:00
|
|
|
|
else
|
2013-06-17 13:29:50 +00:00
|
|
|
|
asts = ASTs(1, ast);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-17 13:29:50 +00:00
|
|
|
|
for (size_t i = 0; i < asts.size(); ++i)
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2013-06-17 13:29:50 +00:00
|
|
|
|
std::string name = asts[i]->getColumnName();
|
|
|
|
|
std::string alias;
|
|
|
|
|
if (project_result)
|
2014-07-03 22:39:13 +00:00
|
|
|
|
alias = asts[i]->getAliasOrColumnName();
|
2013-06-17 13:29:50 +00:00
|
|
|
|
else
|
|
|
|
|
alias = name;
|
2014-07-06 00:19:49 +00:00
|
|
|
|
result_columns.emplace_back(name, alias);
|
2013-06-17 13:29:50 +00:00
|
|
|
|
result_names.push_back(alias);
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(asts[i], false, false, actions);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-03 13:17:17 +00:00
|
|
|
|
if (project_result)
|
|
|
|
|
{
|
2014-06-12 18:41:09 +00:00
|
|
|
|
actions->add(ExpressionAction::project(result_columns));
|
2013-06-03 13:17:17 +00:00
|
|
|
|
}
|
2013-06-18 09:43:35 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/// Не будем удалять исходные столбцы.
|
2014-06-12 21:12:47 +00:00
|
|
|
|
for (const auto & column_name_type : columns)
|
2014-07-09 11:45:51 +00:00
|
|
|
|
result_names.push_back(column_name_type.name);
|
2013-06-18 09:43:35 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-28 11:54:37 +00:00
|
|
|
|
actions->finalize(result_names);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return actions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExpressionActionsPtr ExpressionAnalyzer::getConstActions()
|
|
|
|
|
{
|
2016-01-13 00:32:59 +00:00
|
|
|
|
ExpressionActionsPtr actions = std::make_shared<ExpressionActions>(NamesAndTypesList(), settings);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-04 01:40:22 +00:00
|
|
|
|
getRootActions(ast, true, true, actions);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
return actions;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-18 22:30:43 +00:00
|
|
|
|
void ExpressionAnalyzer::getAggregateInfo(Names & key_names, AggregateDescriptions & aggregates) const
|
2013-05-24 10:49:19 +00:00
|
|
|
|
{
|
2015-04-18 22:30:43 +00:00
|
|
|
|
for (const auto & name_and_type : aggregation_keys)
|
|
|
|
|
key_names.emplace_back(name_and_type.name);
|
2015-03-12 02:22:55 +00:00
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
aggregates = aggregate_descriptions;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-04 19:13:38 +00:00
|
|
|
|
void ExpressionAnalyzer::collectUsedColumns()
|
2013-05-30 16:52:21 +00:00
|
|
|
|
{
|
2014-06-12 21:12:47 +00:00
|
|
|
|
/** Вычислим, какие столбцы требуются для выполнения выражения.
|
|
|
|
|
* Затем, удалим все остальные столбцы из списка доступных столбцов.
|
|
|
|
|
* После выполнения, columns будет содержать только список столбцов, нужных для чтения из таблицы.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
NameSet required;
|
|
|
|
|
NameSet ignored;
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (select_query && select_query->array_join_expression_list())
|
2013-10-17 13:32:32 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
ASTs & expressions = select_query->array_join_expression_list()->children;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
for (size_t i = 0; i < expressions.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
/// Игнорируем идентификаторы верхнего уровня из секции ARRAY JOIN.
|
2013-10-21 11:33:25 +00:00
|
|
|
|
/// Их потом добавим отдельно.
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (typeid_cast<ASTIdentifier *>(expressions[i].get()))
|
2013-12-06 10:41:54 +00:00
|
|
|
|
{
|
2013-10-17 13:32:32 +00:00
|
|
|
|
ignored.insert(expressions[i]->getColumnName());
|
2013-12-06 10:41:54 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/// Для выражений в ARRAY JOIN ничего игнорировать не нужно.
|
2014-06-12 21:12:47 +00:00
|
|
|
|
NameSet empty;
|
2014-06-13 06:39:15 +00:00
|
|
|
|
getRequiredColumnsImpl(expressions[i], required, empty, empty, empty);
|
2013-12-06 10:41:54 +00:00
|
|
|
|
}
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2014-07-03 22:39:13 +00:00
|
|
|
|
ignored.insert(expressions[i]->getAliasOrColumnName());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2014-06-13 06:39:15 +00:00
|
|
|
|
/** Также нужно не учитывать идентификаторы столбцов, получающихся путём JOIN-а.
|
|
|
|
|
* (Не считать, что они требуются для чтения из "левой" таблицы).
|
|
|
|
|
*/
|
|
|
|
|
NameSet available_joined_columns;
|
|
|
|
|
collectJoinedColumns(available_joined_columns, columns_added_by_join);
|
|
|
|
|
|
|
|
|
|
NameSet required_joined_columns;
|
|
|
|
|
getRequiredColumnsImpl(ast, required, ignored, available_joined_columns, required_joined_columns);
|
|
|
|
|
|
|
|
|
|
for (NamesAndTypesList::iterator it = columns_added_by_join.begin(); it != columns_added_by_join.end();)
|
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
if (required_joined_columns.count(it->name))
|
2014-06-13 06:39:15 +00:00
|
|
|
|
++it;
|
|
|
|
|
else
|
|
|
|
|
columns_added_by_join.erase(it++);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 20:01:42 +00:00
|
|
|
|
/* for (const auto & name_type : columns_added_by_join)
|
2015-07-23 20:23:24 +00:00
|
|
|
|
std::cerr << "JOINed column (required, not key): " << name_type.name << std::endl;
|
2014-06-16 20:01:42 +00:00
|
|
|
|
std::cerr << std::endl;*/
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-12 21:12:47 +00:00
|
|
|
|
/// Вставляем в список требуемых столбцов столбцы, нужные для вычисления ARRAY JOIN.
|
2013-10-21 11:33:25 +00:00
|
|
|
|
NameSet array_join_sources;
|
2014-06-12 21:12:47 +00:00
|
|
|
|
for (const auto & result_source : array_join_result_to_source)
|
|
|
|
|
array_join_sources.insert(result_source.second);
|
|
|
|
|
|
|
|
|
|
for (const auto & column_name_type : columns)
|
2014-07-09 11:45:51 +00:00
|
|
|
|
if (array_join_sources.count(column_name_type.name))
|
|
|
|
|
required.insert(column_name_type.name);
|
2013-10-21 11:33:25 +00:00
|
|
|
|
|
2013-06-20 13:50:55 +00:00
|
|
|
|
/// Нужно прочитать хоть один столбец, чтобы узнать количество строк.
|
|
|
|
|
if (required.empty())
|
|
|
|
|
required.insert(ExpressionActions::getSmallestColumn(columns));
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-21 10:36:01 +00:00
|
|
|
|
unknown_required_columns = required;
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-20 13:50:55 +00:00
|
|
|
|
for (NamesAndTypesList::iterator it = columns.begin(); it != columns.end();)
|
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
unknown_required_columns.erase(it->name);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-09 11:45:51 +00:00
|
|
|
|
if (!required.count(it->name))
|
2013-06-21 10:09:02 +00:00
|
|
|
|
{
|
2014-07-09 11:45:51 +00:00
|
|
|
|
required.erase(it->name);
|
2014-06-12 21:12:47 +00:00
|
|
|
|
columns.erase(it++);
|
2013-06-21 10:09:02 +00:00
|
|
|
|
}
|
2014-06-12 21:12:47 +00:00
|
|
|
|
else
|
|
|
|
|
++it;
|
2013-06-20 13:50:55 +00:00
|
|
|
|
}
|
2014-01-16 14:52:13 +00:00
|
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
|
/// Возможно, среди неизвестных столбцов есть виртуальные. Удаляем их из списка неизвестных и добавляем
|
|
|
|
|
/// в columns list, чтобы при дальнейшей обработке запроса они воспринимались как настоящие.
|
|
|
|
|
if (storage)
|
|
|
|
|
{
|
|
|
|
|
for (auto it = unknown_required_columns.begin(); it != unknown_required_columns.end();)
|
|
|
|
|
{
|
|
|
|
|
if (storage->hasColumn(*it))
|
|
|
|
|
{
|
|
|
|
|
columns.push_back(storage->getColumn(*it));
|
|
|
|
|
unknown_required_columns.erase(it++);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-20 13:50:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 06:39:15 +00:00
|
|
|
|
void ExpressionAnalyzer::collectJoinedColumns(NameSet & joined_columns, NamesAndTypesList & joined_columns_name_type)
|
2014-06-12 23:21:38 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (!select_query)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const ASTTablesInSelectQueryElement * node = select_query->join();
|
|
|
|
|
|
|
|
|
|
if (!node)
|
2014-06-12 23:21:38 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const ASTTableJoin & table_join = static_cast<const ASTTableJoin &>(*node->table_join);
|
|
|
|
|
const ASTTableExpression & table_expression = static_cast<const ASTTableExpression &>(*node->table_expression);
|
2014-06-12 23:21:38 +00:00
|
|
|
|
|
2014-12-17 11:53:17 +00:00
|
|
|
|
Block nested_result_sample;
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (table_expression.database_and_table_name)
|
2014-12-17 11:53:17 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const auto & table = context.getTable("", static_cast<const ASTIdentifier &>(*table_expression.database_and_table_name).name);
|
2014-12-17 11:53:17 +00:00
|
|
|
|
nested_result_sample = table->getSampleBlockNonMaterialized();
|
|
|
|
|
}
|
2016-07-22 20:39:28 +00:00
|
|
|
|
else if (table_expression.subquery)
|
2014-12-17 11:53:17 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
const auto & subquery = table_expression.subquery->children.at(0);
|
2015-07-15 02:58:28 +00:00
|
|
|
|
nested_result_sample = InterpreterSelectQuery::getSampleBlock(subquery, context);
|
2014-12-17 11:53:17 +00:00
|
|
|
|
}
|
2014-06-12 23:21:38 +00:00
|
|
|
|
|
2016-07-22 20:39:28 +00:00
|
|
|
|
if (table_join.using_expression_list)
|
2014-07-02 20:23:48 +00:00
|
|
|
|
{
|
2016-07-22 20:39:28 +00:00
|
|
|
|
auto & keys = typeid_cast<ASTExpressionList &>(*table_join.using_expression_list);
|
2015-07-23 20:23:24 +00:00
|
|
|
|
for (const auto & key : keys.children)
|
|
|
|
|
{
|
2015-09-03 20:48:02 +00:00
|
|
|
|
if (join_key_names_left.end() == std::find(join_key_names_left.begin(), join_key_names_left.end(), key->getColumnName()))
|
|
|
|
|
join_key_names_left.push_back(key->getColumnName());
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Duplicate column " + key->getColumnName() + " in USING list", ErrorCodes::DUPLICATE_COLUMN);
|
2014-06-12 23:21:38 +00:00
|
|
|
|
|
2015-09-03 20:48:02 +00:00
|
|
|
|
if (join_key_names_right.end() == std::find(join_key_names_right.begin(), join_key_names_right.end(), key->getAliasOrColumnName()))
|
|
|
|
|
join_key_names_right.push_back(key->getAliasOrColumnName());
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Duplicate column " + key->getAliasOrColumnName() + " in USING list", ErrorCodes::DUPLICATE_COLUMN);
|
2015-07-23 20:23:24 +00:00
|
|
|
|
}
|
2014-07-02 20:23:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-17 11:53:17 +00:00
|
|
|
|
for (const auto i : ext::range(0, nested_result_sample.columns()))
|
2014-06-12 23:21:38 +00:00
|
|
|
|
{
|
2014-12-17 11:53:17 +00:00
|
|
|
|
const auto & col = nested_result_sample.getByPosition(i);
|
2015-09-09 00:52:35 +00:00
|
|
|
|
if (join_key_names_right.end() == std::find(join_key_names_right.begin(), join_key_names_right.end(), col.name)
|
|
|
|
|
&& !joined_columns.count(col.name)) /// Дублирующиеся столбцы в подзапросе для JOIN-а не имеют смысла.
|
2014-06-13 02:05:05 +00:00
|
|
|
|
{
|
2014-06-13 06:39:15 +00:00
|
|
|
|
joined_columns.insert(col.name);
|
|
|
|
|
joined_columns_name_type.emplace_back(col.name, col.type);
|
2014-06-13 02:05:05 +00:00
|
|
|
|
}
|
2014-06-12 23:21:38 +00:00
|
|
|
|
}
|
2014-06-13 06:39:15 +00:00
|
|
|
|
|
2015-09-03 20:48:02 +00:00
|
|
|
|
/* for (const auto & name : join_key_names_left)
|
2014-07-02 20:23:48 +00:00
|
|
|
|
std::cerr << "JOIN key (left): " << name << std::endl;
|
2015-09-03 20:48:02 +00:00
|
|
|
|
for (const auto & name : join_key_names_right)
|
2014-07-02 20:23:48 +00:00
|
|
|
|
std::cerr << "JOIN key (right): " << name << std::endl;
|
2014-06-13 06:39:15 +00:00
|
|
|
|
std::cerr << std::endl;
|
|
|
|
|
for (const auto & name : joined_columns)
|
|
|
|
|
std::cerr << "JOINed column: " << name << std::endl;
|
2014-07-16 02:13:26 +00:00
|
|
|
|
std::cerr << std::endl;*/
|
2014-06-12 23:21:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
|
2013-06-20 13:50:55 +00:00
|
|
|
|
Names ExpressionAnalyzer::getRequiredColumns()
|
|
|
|
|
{
|
2013-06-21 10:31:31 +00:00
|
|
|
|
if (!unknown_required_columns.empty())
|
|
|
|
|
throw Exception("Unknown identifier: " + *unknown_required_columns.begin(), ErrorCodes::UNKNOWN_IDENTIFIER);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-06-20 13:50:55 +00:00
|
|
|
|
Names res;
|
2014-06-12 19:23:06 +00:00
|
|
|
|
for (const auto & column_name_type : columns)
|
2014-07-09 11:45:51 +00:00
|
|
|
|
res.push_back(column_name_type.name);
|
2014-06-12 21:12:47 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 02:25:09 +00:00
|
|
|
|
|
2014-06-13 06:39:15 +00:00
|
|
|
|
void ExpressionAnalyzer::getRequiredColumnsImpl(ASTPtr ast,
|
|
|
|
|
NameSet & required_columns, NameSet & ignored_names,
|
|
|
|
|
const NameSet & available_joined_columns, NameSet & required_joined_columns)
|
2013-05-30 16:52:21 +00:00
|
|
|
|
{
|
2014-06-12 23:21:38 +00:00
|
|
|
|
/** Найдём все идентификаторы в запросе.
|
|
|
|
|
* Будем искать их рекурсивно, обходя в глубину AST.
|
|
|
|
|
* При этом:
|
|
|
|
|
* - для лямбда функций не будем брать формальные параметры;
|
|
|
|
|
* - не опускаемся в подзапросы (там свои идентификаторы);
|
2014-06-13 06:39:15 +00:00
|
|
|
|
* - некоторое исключение для секции ARRAY JOIN (в ней идентификаторы немного другие);
|
|
|
|
|
* - идентификаторы, доступные из JOIN-а, кладём в required_joined_columns.
|
2014-06-12 23:21:38 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTIdentifier * node = typeid_cast<ASTIdentifier *>(ast.get()))
|
2013-05-30 16:52:21 +00:00
|
|
|
|
{
|
2013-10-21 11:33:25 +00:00
|
|
|
|
if (node->kind == ASTIdentifier::Column
|
|
|
|
|
&& !ignored_names.count(node->name)
|
|
|
|
|
&& !ignored_names.count(DataTypeNested::extractNestedTableName(node->name)))
|
2013-08-01 14:43:04 +00:00
|
|
|
|
{
|
2014-06-13 06:39:15 +00:00
|
|
|
|
if (!available_joined_columns.count(node->name))
|
|
|
|
|
required_columns.insert(node->name);
|
|
|
|
|
else
|
|
|
|
|
required_joined_columns.insert(node->name);
|
2013-08-01 14:43:04 +00:00
|
|
|
|
}
|
2014-06-12 19:53:36 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
if (ASTFunction * node = typeid_cast<ASTFunction *>(ast.get()))
|
2013-05-30 16:52:21 +00:00
|
|
|
|
{
|
|
|
|
|
if (node->kind == ASTFunction::LAMBDA_EXPRESSION)
|
|
|
|
|
{
|
|
|
|
|
if (node->arguments->children.size() != 2)
|
|
|
|
|
throw Exception("lambda requires two arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTFunction * lambda_args_tuple = typeid_cast<ASTFunction *>(node->arguments->children.at(0).get());
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple")
|
|
|
|
|
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-12 23:21:38 +00:00
|
|
|
|
/// Не нужно добавлять формальные параметры лямбда-выражения в required_columns.
|
2013-05-30 16:52:21 +00:00
|
|
|
|
Names added_ignored;
|
2014-07-06 04:22:12 +00:00
|
|
|
|
for (auto & child : lambda_args_tuple->arguments->children)
|
2013-05-30 16:52:21 +00:00
|
|
|
|
{
|
2016-03-05 02:30:20 +00:00
|
|
|
|
ASTIdentifier * identifier = typeid_cast<ASTIdentifier *>(child.get());
|
2013-05-30 16:52:21 +00:00
|
|
|
|
if (!identifier)
|
|
|
|
|
throw Exception("lambda argument declarations must be identifiers", ErrorCodes::TYPE_MISMATCH);
|
2014-06-13 06:39:15 +00:00
|
|
|
|
|
|
|
|
|
String & name = identifier->name;
|
2013-05-30 16:52:21 +00:00
|
|
|
|
if (!ignored_names.count(name))
|
|
|
|
|
{
|
|
|
|
|
ignored_names.insert(name);
|
|
|
|
|
added_ignored.push_back(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-07-06 04:22:12 +00:00
|
|
|
|
getRequiredColumnsImpl(node->arguments->children.at(1),
|
2014-06-13 06:39:15 +00:00
|
|
|
|
required_columns, ignored_names,
|
|
|
|
|
available_joined_columns, required_joined_columns);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
for (size_t i = 0; i < added_ignored.size(); ++i)
|
|
|
|
|
ignored_names.erase(added_ignored[i]);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2013-05-30 16:52:21 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-15 23:10:29 +00:00
|
|
|
|
|
|
|
|
|
/// Особая функция indexHint. Всё, что внутри неё не вычисляется
|
|
|
|
|
/// (а используется только для анализа индекса, см. PKCondition).
|
|
|
|
|
if (node->name == "indexHint")
|
|
|
|
|
return;
|
2013-05-30 16:52:21 +00:00
|
|
|
|
}
|
2013-10-17 13:32:32 +00:00
|
|
|
|
|
2014-06-12 23:21:38 +00:00
|
|
|
|
/// Рекурсивный обход выражения.
|
|
|
|
|
for (auto & child : ast->children)
|
2013-06-21 11:32:27 +00:00
|
|
|
|
{
|
2014-06-12 23:21:38 +00:00
|
|
|
|
/** Не пойдем в секцию ARRAY JOIN, потому что там нужно смотреть на имена не-ARRAY-JOIN-енных столбцов.
|
2014-07-04 19:13:38 +00:00
|
|
|
|
* Туда collectUsedColumns отправит нас отдельно.
|
2014-06-12 23:21:38 +00:00
|
|
|
|
*/
|
2016-07-23 02:25:09 +00:00
|
|
|
|
if (!typeid_cast<ASTSelectQuery *>(child.get())
|
|
|
|
|
&& !typeid_cast<ASTArrayJoin *>(child.get()))
|
2014-06-13 06:39:15 +00:00
|
|
|
|
getRequiredColumnsImpl(child, required_columns, ignored_names, available_joined_columns, required_joined_columns);
|
2013-10-17 13:32:32 +00:00
|
|
|
|
}
|
2013-05-30 16:52:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|