Merge pull request #43999 from ClickHouse/if-transform-strings-to-enum-pass

Support `optimize_if_transform_strings_to_enum` in new analyzer
This commit is contained in:
Maksim Kita 2022-12-14 15:39:42 +03:00 committed by GitHub
commit 19d9e8d064
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 831 additions and 3 deletions

View File

@ -0,0 +1,197 @@
#include <Analyzer/Passes/IfTransformStringsToEnumPass.h>
#include <Analyzer/ConstantNode.h>
#include <Analyzer/FunctionNode.h>
#include <Analyzer/IQueryTreeNode.h>
#include <Analyzer/InDepthQueryTreeVisitor.h>
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypeEnum.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/IDataType.h>
#include <Functions/FunctionFactory.h>
namespace DB
{
namespace
{
/// We place strings in ascending order here under the assumption it could speed up String to Enum conversion.
template <typename EnumType>
auto getDataEnumType(const std::set<std::string> & string_values)
{
using EnumValues = typename EnumType::Values;
EnumValues enum_values;
enum_values.reserve(string_values.size());
size_t number = 1;
for (const auto & value : string_values)
enum_values.emplace_back(value, number++);
return std::make_shared<EnumType>(std::move(enum_values));
}
DataTypePtr getEnumType(const std::set<std::string> & string_values)
{
if (string_values.size() >= 255)
return getDataEnumType<DataTypeEnum16>(string_values);
else
return getDataEnumType<DataTypeEnum8>(string_values);
}
QueryTreeNodePtr createCastFunction(QueryTreeNodePtr from, DataTypePtr result_type, ContextPtr context)
{
auto enum_literal = std::make_shared<ConstantValue>(result_type->getName(), std::make_shared<DataTypeString>());
auto enum_literal_node = std::make_shared<ConstantNode>(std::move(enum_literal));
auto cast_function = FunctionFactory::instance().get("_CAST", std::move(context));
QueryTreeNodes arguments{std::move(from), std::move(enum_literal_node)};
auto function_node = std::make_shared<FunctionNode>("_CAST");
function_node->resolveAsFunction(std::move(cast_function), std::move(result_type));
function_node->getArguments().getNodes() = std::move(arguments);
return function_node;
}
/// if(arg1, arg2, arg3) will be transformed to if(arg1, _CAST(arg2, Enum...), _CAST(arg3, Enum...))
/// where Enum is generated based on the possible values stored in string_values
void changeIfArguments(
QueryTreeNodePtr & first, QueryTreeNodePtr & second, const std::set<std::string> & string_values, const ContextPtr & context)
{
auto result_type = getEnumType(string_values);
first = createCastFunction(first, result_type, context);
second = createCastFunction(second, result_type, context);
}
/// transform(value, array_from, array_to, default_value) will be transformed to transform(value, array_from, _CAST(array_to, Array(Enum...)), _CAST(default_value, Enum...))
/// where Enum is generated based on the possible values stored in string_values
void changeTransformArguments(
QueryTreeNodePtr & array_to,
QueryTreeNodePtr & default_value,
const std::set<std::string> & string_values,
const ContextPtr & context)
{
auto result_type = getEnumType(string_values);
array_to = createCastFunction(array_to, std::make_shared<DataTypeArray>(result_type), context);
default_value = createCastFunction(default_value, std::move(result_type), context);
}
void wrapIntoToString(FunctionNode & function_node, QueryTreeNodePtr arg, ContextPtr context)
{
assert(isString(function_node.getResultType()));
auto to_string_function = FunctionFactory::instance().get("toString", std::move(context));
QueryTreeNodes arguments{std::move(arg)};
function_node.resolveAsFunction(std::move(to_string_function), std::make_shared<DataTypeString>());
function_node.getArguments().getNodes() = std::move(arguments);
}
class ConvertStringsToEnumVisitor : public InDepthQueryTreeVisitor<ConvertStringsToEnumVisitor>
{
public:
explicit ConvertStringsToEnumVisitor(ContextPtr context_)
: context(std::move(context_))
{
}
void visitImpl(QueryTreeNodePtr & node)
{
auto * function_node = node->as<FunctionNode>();
if (!function_node)
return;
/// to preserve return type (String) of the current function_node, we wrap the newly
/// generated function nodes into toString
std::string_view function_name = function_node->getFunctionName();
if (function_name == "if")
{
if (function_node->getArguments().getNodes().size() != 3)
return;
auto modified_if_node = function_node->clone();
auto & argument_nodes = modified_if_node->as<FunctionNode>()->getArguments().getNodes();
const auto * first_literal = argument_nodes[1]->as<ConstantNode>();
const auto * second_literal = argument_nodes[2]->as<ConstantNode>();
if (!first_literal || !second_literal)
return;
if (!isString(first_literal->getResultType()) || !isString(second_literal->getResultType()))
return;
std::set<std::string> string_values;
string_values.insert(first_literal->getValue().get<std::string>());
string_values.insert(second_literal->getValue().get<std::string>());
changeIfArguments(argument_nodes[1], argument_nodes[2], string_values, context);
wrapIntoToString(*function_node, std::move(modified_if_node), context);
return;
}
if (function_name == "transform")
{
if (function_node->getArguments().getNodes().size() != 4)
return;
auto modified_transform_node = function_node->clone();
auto & argument_nodes = modified_transform_node->as<FunctionNode>()->getArguments().getNodes();
if (!isString(function_node->getResultType()))
return;
const auto * literal_to = argument_nodes[2]->as<ConstantNode>();
const auto * literal_default = argument_nodes[3]->as<ConstantNode>();
if (!literal_to || !literal_default)
return;
if (!isArray(literal_to->getResultType()) || !isString(literal_default->getResultType()))
return;
auto array_to = literal_to->getValue().get<Array>();
if (array_to.empty())
return;
if (!std::all_of(
array_to.begin(),
array_to.end(),
[](const auto & field) { return field.getType() == Field::Types::Which::String; }))
return;
/// collect possible string values
std::set<std::string> string_values;
for (const auto & value : array_to)
string_values.insert(value.get<std::string>());
string_values.insert(literal_default->getValue().get<std::string>());
changeTransformArguments(argument_nodes[2], argument_nodes[3], string_values, context);
wrapIntoToString(*function_node, std::move(modified_transform_node), context);
return;
}
}
private:
ContextPtr context;
};
}
void IfTransformStringsToEnumPass::run(QueryTreeNodePtr query, ContextPtr context)
{
ConvertStringsToEnumVisitor visitor(context);
visitor.visit(query);
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <Analyzer/IQueryTreePass.h>
namespace DB
{
/**
* This pass replaces string-type arguments in If and Transform to enum.
*
* E.g.
* -------------------------------
* SELECT if(number > 5, 'a', 'b')
* FROM system.numbers;
*
* will be transformed into
*
* SELECT if(number > 5, _CAST('a', 'Enum8(\'a\' = 1, \'b\' = 2)'), _CAST('b', 'Enum8(\'a\' = 1, \'b\' = 2)'))
* FROM system.numbers;
* -------------------------------
* SELECT transform(number, [2, 4], ['a', 'b'], 'c') FROM system.numbers;
*
* will be transformed into
*
* SELECT transform(number, [2, 4], _CAST(['a', 'b'], 'Array(Enum8(\'a\' = 1, \'b\' = 2, \'c\' = 3)'), _CAST('c', 'Enum8(\'a\' = 1, \'b\' = 2, \'c\' = 3)'))
* FROM system.numbers;
* -------------------------------
*/
class IfTransformStringsToEnumPass final : public IQueryTreePass
{
public:
String getName() override { return "IfTransformStringsToEnumPass"; }
String getDescription() override { return "Replaces string-type arguments in If and Transform to enum"; }
void run(QueryTreeNodePtr query_tree_node, ContextPtr context) override;
};
}

View File

@ -14,6 +14,7 @@
#include <Analyzer/Passes/UniqInjectiveFunctionsEliminationPass.h>
#include <Analyzer/Passes/OrderByLimitByDuplicateEliminationPass.h>
#include <Analyzer/Passes/FuseFunctionsPass.h>
#include <Analyzer/Passes/IfTransformStringsToEnumPass.h>
#include <IO/WriteHelpers.h>
#include <IO/Operators.h>
@ -77,7 +78,6 @@ public:
* TODO: Support setting optimize_duplicate_order_by_and_distinct.
* TODO: Support setting optimize_redundant_functions_in_order_by.
* TODO: Support setting optimize_monotonous_functions_in_order_by.
* TODO: Support setting optimize_if_transform_strings_to_enum.
* TODO: Support settings.optimize_or_like_chain.
* TODO: Add optimizations based on function semantics. Example: SELECT * FROM test_table WHERE id != id. (id is not nullable column).
*/
@ -193,6 +193,9 @@ void addQueryTreePasses(QueryTreePassManager & manager)
if (settings.optimize_syntax_fuse_functions)
manager.addPass(std::make_unique<FuseFunctionsPass>());
if (settings.optimize_if_transform_strings_to_enum)
manager.addPass(std::make_unique<IfTransformStringsToEnumPass>());
}
}

View File

@ -141,7 +141,7 @@ void ConvertStringsToEnumMatcher::visit(ASTFunction & function_node, Data & data
if (function_node.name == "if")
{
if (function_node.arguments->children.size() != 2)
if (function_node.arguments->children.size() != 3)
return;
const ASTLiteral * literal1 = function_node.arguments->children[1]->as<ASTLiteral>();

View File

@ -21,7 +21,7 @@ censor.net
censor.net
censor.net
censor.net
SELECT if(number > 5, \'censor.net\', \'google\')
SELECT if(number > 5, _CAST(\'censor.net\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'), _CAST(\'google\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'))
FROM system.numbers
LIMIT 10
other

View File

@ -0,0 +1,537 @@
other
other
google
other
censor.net
other
yahoo
other
other
other
SELECT transform(number, [2, 4, 6], _CAST([\'google\', \'censor.net\', \'yahoo\'], \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\'), _CAST(\'other\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\'))
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
transform(number, [2, 4, 6], [\'google\', \'censor.net\', \'yahoo\'], \'other\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 4
COLUMN id: 6, column_name: number, result_type: UInt64, source_id: 7
CONSTANT id: 8, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
FUNCTION id: 9, function_name: _CAST, function_type: ordinary, result_type: Array(Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4))
ARGUMENTS
LIST id: 10, nodes: 2
CONSTANT id: 11, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 12, constant_value: \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\', constant_value_type: String
FUNCTION id: 13, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4)
ARGUMENTS
LIST id: 14, nodes: 2
CONSTANT id: 15, constant_value: \'other\', constant_value_type: String
CONSTANT id: 16, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\', constant_value_type: String
JOIN TREE
TABLE id: 7, table_name: system.numbers
LIMIT
CONSTANT id: 17, constant_value: UInt64_10, constant_value_type: UInt8
google
google
google
google
google
google
censor.net
censor.net
censor.net
censor.net
SELECT if(number > 5, _CAST(\'censor.net\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'), _CAST(\'google\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'))
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
if(greater(number, 5), \'censor.net\', \'google\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 3
FUNCTION id: 6, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 7, nodes: 2
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 9
CONSTANT id: 10, constant_value: UInt64_5, constant_value_type: UInt8
FUNCTION id: 11, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 12, nodes: 2
CONSTANT id: 13, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 14, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 15, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 16, nodes: 2
CONSTANT id: 17, constant_value: \'google\', constant_value_type: String
CONSTANT id: 18, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
JOIN TREE
TABLE id: 9, table_name: system.numbers
LIMIT
CONSTANT id: 19, constant_value: UInt64_10, constant_value_type: UInt8
other1
other1
google1
other1
censor.net1
other1
yahoo1
other1
other1
other1
SELECT concat(transform(number, [2, 4, 6], [\'google\', \'censor.net\', \'yahoo\'], \'other\'), \'1\')
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
CONCAT(transform(number, [2, 4, 6], [\'google\', \'censor.net\', \'yahoo\'], \'other\'), \'1\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: concat, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 2
FUNCTION id: 4, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 1
FUNCTION id: 6, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 7, nodes: 4
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 9
CONSTANT id: 10, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
FUNCTION id: 11, function_name: _CAST, function_type: ordinary, result_type: Array(Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4))
ARGUMENTS
LIST id: 12, nodes: 2
CONSTANT id: 13, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 14, constant_value: \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\', constant_value_type: String
FUNCTION id: 15, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4)
ARGUMENTS
LIST id: 16, nodes: 2
CONSTANT id: 17, constant_value: \'other\', constant_value_type: String
CONSTANT id: 18, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\', constant_value_type: String
CONSTANT id: 19, constant_value: \'1\', constant_value_type: String
JOIN TREE
TABLE id: 9, table_name: system.numbers
LIMIT
CONSTANT id: 20, constant_value: UInt64_10, constant_value_type: UInt8
google1
google1
google1
google1
google1
google1
censor.net1
censor.net1
censor.net1
censor.net1
SELECT concat(if(number > 5, \'censor.net\', \'google\'), \'1\')
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
CONCAT(if(greater(number, 5), \'censor.net\', \'google\'), \'1\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: concat, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 2
FUNCTION id: 4, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 1
FUNCTION id: 6, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 7, nodes: 3
FUNCTION id: 8, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 9, nodes: 2
COLUMN id: 10, column_name: number, result_type: UInt64, source_id: 11
CONSTANT id: 12, constant_value: UInt64_5, constant_value_type: UInt8
FUNCTION id: 13, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 14, nodes: 2
CONSTANT id: 15, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 16, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 17, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 18, nodes: 2
CONSTANT id: 19, constant_value: \'google\', constant_value_type: String
CONSTANT id: 20, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
CONSTANT id: 21, constant_value: \'1\', constant_value_type: String
JOIN TREE
TABLE id: 11, table_name: system.numbers
LIMIT
CONSTANT id: 22, constant_value: UInt64_10, constant_value_type: UInt8
google
google
google
google
google
google
censor.net
censor.net
censor.net
censor.net
SELECT value
FROM
(
SELECT if(number > 5, _CAST(\'censor.net\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'), _CAST(\'google\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\')) AS value
FROM system.numbers
LIMIT 10
) AS t1
QUERY id: 0
PROJECTION COLUMNS
value String
PROJECTION
LIST id: 1, nodes: 1
COLUMN id: 2, column_name: value, result_type: String, source_id: 3
JOIN TREE
QUERY id: 3, alias: t1, is_subquery: 1
PROJECTION COLUMNS
value String
PROJECTION
LIST id: 4, nodes: 1
FUNCTION id: 5, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 6, nodes: 1
FUNCTION id: 7, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 8, nodes: 3
FUNCTION id: 9, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 10, nodes: 2
COLUMN id: 11, column_name: number, result_type: UInt64, source_id: 12
CONSTANT id: 13, constant_value: UInt64_5, constant_value_type: UInt8
FUNCTION id: 14, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 15, nodes: 2
CONSTANT id: 16, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 17, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 18, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 19, nodes: 2
CONSTANT id: 20, constant_value: \'google\', constant_value_type: String
CONSTANT id: 21, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
JOIN TREE
TABLE id: 12, table_name: system.numbers
LIMIT
CONSTANT id: 22, constant_value: UInt64_10, constant_value_type: UInt8
other
other
google
other
censor.net
other
yahoo
other
other
other
SELECT value
FROM
(
SELECT transform(number, [2, 4, 6], _CAST([\'google\', \'censor.net\', \'yahoo\'], \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\'), _CAST(\'other\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\')) AS value
FROM system.numbers
LIMIT 10
) AS t1
QUERY id: 0
PROJECTION COLUMNS
value String
PROJECTION
LIST id: 1, nodes: 1
COLUMN id: 2, column_name: value, result_type: String, source_id: 3
JOIN TREE
QUERY id: 3, alias: t1, is_subquery: 1
PROJECTION COLUMNS
value String
PROJECTION
LIST id: 4, nodes: 1
FUNCTION id: 5, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 6, nodes: 1
FUNCTION id: 7, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 8, nodes: 4
COLUMN id: 9, column_name: number, result_type: UInt64, source_id: 10
CONSTANT id: 11, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
FUNCTION id: 12, function_name: _CAST, function_type: ordinary, result_type: Array(Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4))
ARGUMENTS
LIST id: 13, nodes: 2
CONSTANT id: 14, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 15, constant_value: \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\', constant_value_type: String
FUNCTION id: 16, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4)
ARGUMENTS
LIST id: 17, nodes: 2
CONSTANT id: 18, constant_value: \'other\', constant_value_type: String
CONSTANT id: 19, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\', constant_value_type: String
JOIN TREE
TABLE id: 10, table_name: system.numbers
LIMIT
CONSTANT id: 20, constant_value: UInt64_10, constant_value_type: UInt8
google google
google google
google google
google google
google google
google google
censor.net censor.net
censor.net censor.net
censor.net censor.net
censor.net censor.net
SELECT
if(number > 5, _CAST(\'censor.net\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\'), _CAST(\'google\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\')) AS value,
value
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
value String
value String
PROJECTION
LIST id: 1, nodes: 2
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 3
FUNCTION id: 6, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 7, nodes: 2
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 9
CONSTANT id: 10, constant_value: UInt64_5, constant_value_type: UInt8
FUNCTION id: 11, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 12, nodes: 2
CONSTANT id: 13, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 14, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 15, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 16, nodes: 2
CONSTANT id: 17, constant_value: \'google\', constant_value_type: String
CONSTANT id: 18, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 3
FUNCTION id: 6, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 7, nodes: 2
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 9
CONSTANT id: 10, constant_value: UInt64_5, constant_value_type: UInt8
FUNCTION id: 11, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 12, nodes: 2
CONSTANT id: 13, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 14, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
FUNCTION id: 15, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2)
ARGUMENTS
LIST id: 16, nodes: 2
CONSTANT id: 17, constant_value: \'google\', constant_value_type: String
CONSTANT id: 18, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2)\', constant_value_type: String
JOIN TREE
TABLE id: 9, table_name: system.numbers
LIMIT
CONSTANT id: 19, constant_value: UInt64_10, constant_value_type: UInt8
other other
other other
google google
other other
censor.net censor.net
other other
yahoo yahoo
other other
other other
other other
SELECT
transform(number, [2, 4, 6], _CAST([\'google\', \'censor.net\', \'yahoo\'], \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\'), _CAST(\'other\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\')) AS value,
value
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
value String
value String
PROJECTION
LIST id: 1, nodes: 2
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 4
COLUMN id: 6, column_name: number, result_type: UInt64, source_id: 7
CONSTANT id: 8, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
FUNCTION id: 9, function_name: _CAST, function_type: ordinary, result_type: Array(Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4))
ARGUMENTS
LIST id: 10, nodes: 2
CONSTANT id: 11, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 12, constant_value: \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\', constant_value_type: String
FUNCTION id: 13, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4)
ARGUMENTS
LIST id: 14, nodes: 2
CONSTANT id: 15, constant_value: \'other\', constant_value_type: String
CONSTANT id: 16, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\', constant_value_type: String
FUNCTION id: 2, function_name: toString, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 1
FUNCTION id: 4, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 5, nodes: 4
COLUMN id: 6, column_name: number, result_type: UInt64, source_id: 7
CONSTANT id: 8, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
FUNCTION id: 9, function_name: _CAST, function_type: ordinary, result_type: Array(Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4))
ARGUMENTS
LIST id: 10, nodes: 2
CONSTANT id: 11, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 12, constant_value: \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\', constant_value_type: String
FUNCTION id: 13, function_name: _CAST, function_type: ordinary, result_type: Enum8(\'censor.net\' = 1, \'google\' = 2, \'other\' = 3, \'yahoo\' = 4)
ARGUMENTS
LIST id: 14, nodes: 2
CONSTANT id: 15, constant_value: \'other\', constant_value_type: String
CONSTANT id: 16, constant_value: \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\', constant_value_type: String
JOIN TREE
TABLE id: 7, table_name: system.numbers
LIMIT
CONSTANT id: 17, constant_value: UInt64_10, constant_value_type: UInt8
\N
\N
\N
\N
\N
\N
\N
\N
\N
\N
SELECT transform(number, [NULL], _CAST([\'google\', \'censor.net\', \'yahoo\'], \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\'), _CAST(\'other\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\'))
FROM
(
SELECT NULL AS number
FROM system.numbers
LIMIT 10
)
QUERY id: 0
PROJECTION COLUMNS
transform(number, [NULL], [\'google\', \'censor.net\', \'yahoo\'], \'other\') Nullable(Nothing)
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: transform, function_type: ordinary, result_type: Nullable(Nothing)
ARGUMENTS
LIST id: 3, nodes: 4
COLUMN id: 4, column_name: number, result_type: Nullable(Nothing), source_id: 5
CONSTANT id: 6, constant_value: Array_[NULL], constant_value_type: Array(Nullable(Nothing))
CONSTANT id: 7, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 8, constant_value: \'other\', constant_value_type: String
JOIN TREE
QUERY id: 5, is_subquery: 1
PROJECTION COLUMNS
number Nullable(Nothing)
PROJECTION
LIST id: 9, nodes: 1
CONSTANT id: 10, constant_value: NULL, constant_value_type: Nullable(Nothing)
JOIN TREE
TABLE id: 11, table_name: system.numbers
LIMIT
CONSTANT id: 12, constant_value: UInt64_10, constant_value_type: UInt8
\N
\N
\N
\N
\N
\N
\N
\N
\N
\N
SELECT transform(number, NULL, _CAST([\'google\', \'censor.net\', \'yahoo\'], \'Array(Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4))\'), _CAST(\'other\', \'Enum8(\\\'censor.net\\\' = 1, \\\'google\\\' = 2, \\\'other\\\' = 3, \\\'yahoo\\\' = 4)\'))
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
transform(number, NULL, [\'google\', \'censor.net\', \'yahoo\'], \'other\') Nullable(Nothing)
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: transform, function_type: ordinary, result_type: Nullable(Nothing)
ARGUMENTS
LIST id: 3, nodes: 4
COLUMN id: 4, column_name: number, result_type: UInt64, source_id: 5
CONSTANT id: 6, constant_value: NULL, constant_value_type: Nullable(Nothing)
CONSTANT id: 7, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 8, constant_value: \'other\', constant_value_type: String
JOIN TREE
TABLE id: 5, table_name: system.numbers
LIMIT
CONSTANT id: 9, constant_value: UInt64_10, constant_value_type: UInt8
other
other
google
other
censor.net
other
yahoo
other
other
other
SELECT transform(number, [2, 4, 6], [\'google\', \'censor.net\', \'yahoo\'], \'other\')
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
transform(number, [2, 4, 6], [\'google\', \'censor.net\', \'yahoo\'], \'other\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: transform, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 4
COLUMN id: 4, column_name: number, result_type: UInt64, source_id: 5
CONSTANT id: 6, constant_value: Array_[UInt64_2, UInt64_4, UInt64_6], constant_value_type: Array(UInt8)
CONSTANT id: 7, constant_value: Array_[\'google\', \'censor.net\', \'yahoo\'], constant_value_type: Array(String)
CONSTANT id: 8, constant_value: \'other\', constant_value_type: String
JOIN TREE
TABLE id: 5, table_name: system.numbers
LIMIT
CONSTANT id: 9, constant_value: UInt64_10, constant_value_type: UInt8
google
google
google
google
google
google
censor.net
censor.net
censor.net
censor.net
SELECT if(number > 5, \'censor.net\', \'google\')
FROM system.numbers
LIMIT 10
QUERY id: 0
PROJECTION COLUMNS
if(greater(number, 5), \'censor.net\', \'google\') String
PROJECTION
LIST id: 1, nodes: 1
FUNCTION id: 2, function_name: if, function_type: ordinary, result_type: String
ARGUMENTS
LIST id: 3, nodes: 3
FUNCTION id: 4, function_name: greater, function_type: ordinary, result_type: UInt8
ARGUMENTS
LIST id: 5, nodes: 2
COLUMN id: 6, column_name: number, result_type: UInt64, source_id: 7
CONSTANT id: 8, constant_value: UInt64_5, constant_value_type: UInt8
CONSTANT id: 9, constant_value: \'censor.net\', constant_value_type: String
CONSTANT id: 10, constant_value: \'google\', constant_value_type: String
JOIN TREE
TABLE id: 7, table_name: system.numbers
LIMIT
CONSTANT id: 11, constant_value: UInt64_10, constant_value_type: UInt8

View File

@ -0,0 +1,52 @@
SET allow_experimental_analyzer = 1;
SET optimize_if_transform_strings_to_enum = 1;
SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;
SELECT CONCAT(transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other'), '1') FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT CONCAT(transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other'), '1') FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT CONCAT(transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other'), '1') FROM system.numbers LIMIT 10;
SELECT CONCAT(number > 5 ? 'censor.net' : 'google', '1') FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT CONCAT(number > 5 ? 'censor.net' : 'google', '1') FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT CONCAT(number > 5 ? 'censor.net' : 'google', '1') FROM system.numbers LIMIT 10;
SELECT t1.value FROM (SELECT number > 5 ? 'censor.net' : 'google' as value FROM system.numbers LIMIT 10) as t1;
EXPLAIN SYNTAX SELECT t1.value FROM (SELECT number > 5 ? 'censor.net' : 'google' as value FROM system.numbers LIMIT 10) as t1;
EXPLAIN QUERY TREE run_passes = 1 SELECT t1.value FROM (SELECT number > 5 ? 'censor.net' : 'google' as value FROM system.numbers LIMIT 10) as t1;
SELECT t1.value FROM (SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value FROM system.numbers LIMIT 10) as t1;
EXPLAIN SYNTAX SELECT t1.value FROM (SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value FROM system.numbers LIMIT 10) as t1;
EXPLAIN QUERY TREE run_passes = 1 SELECT t1.value FROM (SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value FROM system.numbers LIMIT 10) as t1;
SELECT number > 5 ? 'censor.net' : 'google' as value, value FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT number > 5 ? 'censor.net' : 'google' as value, value FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT number > 5 ? 'censor.net' : 'google' as value, value FROM system.numbers LIMIT 10;
SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value, value FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value, value FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') as value, value FROM system.numbers LIMIT 10;
SELECT transform(number, [NULL], ['google', 'censor.net', 'yahoo'], 'other') FROM (SELECT NULL as number FROM system.numbers LIMIT 10);
EXPLAIN SYNTAX SELECT transform(number, [NULL], ['google', 'censor.net', 'yahoo'], 'other') FROM (SELECT NULL as number FROM system.numbers LIMIT 10);
EXPLAIN QUERY TREE run_passes = 1 SELECT transform(number, [NULL], ['google', 'censor.net', 'yahoo'], 'other') FROM (SELECT NULL as number FROM system.numbers LIMIT 10);
SELECT transform(number, NULL, ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT transform(number, NULL, ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT transform(number, NULL, ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
SET optimize_if_transform_strings_to_enum = 0;
SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT transform(number, [2, 4, 6], ['google', 'censor.net', 'yahoo'], 'other') FROM system.numbers LIMIT 10;
SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;
EXPLAIN SYNTAX SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;
EXPLAIN QUERY TREE run_passes = 1 SELECT number > 5 ? 'censor.net' : 'google' FROM system.numbers LIMIT 10;