mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 17:41:59 +00:00
Added IFunctonBase::getResultIfAlwaysReturnsConstantAndHasArguments
This commit is contained in:
parent
a4e2fcdd49
commit
d4363768e6
@ -159,7 +159,12 @@ public:
|
||||
*/
|
||||
virtual bool isSuitableForConstantFolding() const { return true; }
|
||||
|
||||
virtual bool alwaysReturnsConstant() const { return false; }
|
||||
/** Some functions like ignore(...) or toTypeName(...) always return constant result which doesn't depend on arguments.
|
||||
* In this case we can calculate result and assume that it's constant in stream header.
|
||||
* There is no need to implement function if it has zero arguments.
|
||||
* Must return ColumnConst with single row or nullptr.
|
||||
*/
|
||||
virtual ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block & /*block*/, const ColumnNumbers & /*arguments*/) const { return nullptr; }
|
||||
|
||||
/** Function is called "injective" if it returns different result for different values of arguments.
|
||||
* Example: hex, negate, tuple...
|
||||
@ -458,7 +463,10 @@ public:
|
||||
}
|
||||
|
||||
bool isSuitableForConstantFolding() const override { return function->isSuitableForConstantFolding(); }
|
||||
bool alwaysReturnsConstant() const override { return function->alwaysReturnsConstant(); }
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block & block, const ColumnNumbers & arguments_) const override
|
||||
{
|
||||
return function->getResultIfAlwaysReturnsConstantAndHasArguments(block, arguments_);
|
||||
}
|
||||
|
||||
bool isInjective(const Block & sample_block) override { return function->isInjective(sample_block); }
|
||||
|
||||
|
@ -37,6 +37,12 @@ public:
|
||||
const IDataType & type = *block.getByPosition(arguments[0]).type;
|
||||
block.getByPosition(result).column = type.createColumnConst(input_rows_count, type.getDefault());
|
||||
}
|
||||
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block & block, const ColumnNumbers & arguments) const override
|
||||
{
|
||||
const IDataType & type = *block.getByPosition(arguments[0]).type;
|
||||
return type.createColumnConst(1, type.getDefault());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -49,11 +49,16 @@ public:
|
||||
}
|
||||
|
||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
|
||||
{
|
||||
block.getByPosition(result).column = getResultIfAlwaysReturnsConstantAndHasArguments(block, arguments)->cloneResized(input_rows_count);
|
||||
}
|
||||
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block & block, const ColumnNumbers & arguments) const override
|
||||
{
|
||||
if (auto type8 = checkAndGetDataType<DataTypeEnum8>(block.getByPosition(arguments[0]).type.get()))
|
||||
block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, type8->getValues().size());
|
||||
return DataTypeUInt8().createColumnConst(1, type8->getValues().size());
|
||||
else if (auto type16 = checkAndGetDataType<DataTypeEnum16>(block.getByPosition(arguments[0]).type.get()))
|
||||
block.getByPosition(result).column = DataTypeUInt16().createColumnConst(input_rows_count, type16->getValues().size());
|
||||
return DataTypeUInt16().createColumnConst(1, type16->getValues().size());
|
||||
else
|
||||
throw Exception("The argument for function " + getName() + " must be Enum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
|
@ -43,7 +43,10 @@ public:
|
||||
block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, 0u);
|
||||
}
|
||||
|
||||
bool alwaysReturnsConstant() const override { return true; }
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block &, const ColumnNumbers &) const override
|
||||
{
|
||||
return DataTypeUInt8().createColumnConst(1, 0u);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,6 +38,11 @@ public:
|
||||
block.getByPosition(result).column
|
||||
= DataTypeString().createColumnConst(input_rows_count, block.getByPosition(arguments[0]).column->getName());
|
||||
}
|
||||
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block & block, const ColumnNumbers & arguments) const override
|
||||
{
|
||||
return DataTypeString().createColumnConst(1, block.getByPosition(arguments[0]).type->createColumn()->getName());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -9,33 +9,16 @@ namespace DB
|
||||
/** toTypeName(x) - get the type name
|
||||
* Returns name of IDataType instance (name of data type).
|
||||
*/
|
||||
class FunctionToTypeName : public IFunction
|
||||
class PreparedFunctionToTypeName : public PreparedFunctionImpl
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = "toTypeName";
|
||||
static FunctionPtr create(const Context &)
|
||||
{
|
||||
return std::make_shared<FunctionToTypeName>();
|
||||
}
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return name;
|
||||
}
|
||||
String getName() const override { return name; }
|
||||
|
||||
protected:
|
||||
bool useDefaultImplementationForNulls() const override { return false; }
|
||||
bool useDefaultImplementationForLowCardinalityColumns() const override { return false; }
|
||||
|
||||
size_t getNumberOfArguments() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override
|
||||
{
|
||||
return std::make_shared<DataTypeString>();
|
||||
}
|
||||
|
||||
/// Execute the function on the block.
|
||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
|
||||
{
|
||||
@ -45,9 +28,55 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class BaseFunctionToTypeName : public IFunctionBase
|
||||
{
|
||||
public:
|
||||
BaseFunctionToTypeName(DataTypes argument_types_, DataTypePtr return_type_)
|
||||
: argument_types(std::move(argument_types_)), return_type(std::move(return_type_)) {}
|
||||
|
||||
static constexpr auto name = "toTypeName";
|
||||
String getName() const override { return name; }
|
||||
|
||||
const DataTypes & getArgumentTypes() const override { return argument_types; }
|
||||
const DataTypePtr & getReturnType() const override { return return_type; }
|
||||
|
||||
PreparedFunctionPtr prepare(const Block &, const ColumnNumbers &, size_t) const override
|
||||
{
|
||||
return std::make_shared<PreparedFunctionToTypeName>();
|
||||
}
|
||||
|
||||
ColumnPtr getResultIfAlwaysReturnsConstantAndHasArguments(const Block &, const ColumnNumbers &) const override
|
||||
{
|
||||
return DataTypeString().createColumnConst(1, argument_types.at(0)->getName());
|
||||
}
|
||||
|
||||
private:
|
||||
DataTypes argument_types;
|
||||
DataTypePtr return_type;
|
||||
};
|
||||
|
||||
|
||||
class FunctionToTypeNameBuilder : public FunctionBuilderImpl
|
||||
{
|
||||
static constexpr auto name = "toTypeName";
|
||||
String getName() const override { return name; }
|
||||
static FunctionBuilderPtr create(const Context &) { return std::make_shared<FunctionToTypeNameBuilder>(); }
|
||||
|
||||
size_t getNumberOfArguments() const override { return 1; }
|
||||
|
||||
protected:
|
||||
DataTypePtr getReturnTypeImpl(const DataTypes &) const override { return std::make_shared<DataTypeString>(); }
|
||||
|
||||
FunctionBasePtr buildImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override
|
||||
{
|
||||
return std::make_shared<BaseFunctionToTypeName>(arguments, return_type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void registerFunctionToTypeName(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionToTypeName>();
|
||||
factory.registerFunction<FunctionToTypeNameBuilder>();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,10 @@ BlockInputStreamPtr createLocalStream(const ASTPtr & query_ast, const Context &
|
||||
* If you do not do this, different types (Const and non-Const) columns will be produced in different threads,
|
||||
* And this is not allowed, since all code is based on the assumption that in the block stream all types are the same.
|
||||
*/
|
||||
/// Already not.
|
||||
|
||||
/* Now we don't need to materialize constants, because RemoteBlockInputStream will ignore constant and take it from header.
|
||||
* So, streams from different threads will always have the same header.
|
||||
*/
|
||||
/// return std::make_shared<MaterializingBlockInputStream>(stream);
|
||||
|
||||
return stream;
|
||||
|
@ -246,11 +246,14 @@ void ExpressionAction::prepare(Block & sample_block, const Settings & settings,
|
||||
}
|
||||
|
||||
auto & res = sample_block.getByPosition(result_position);
|
||||
if (!res.column && function_base->alwaysReturnsConstant() && function_base->isSuitableForConstantFolding())
|
||||
if (!res.column && function_base->isSuitableForConstantFolding())
|
||||
{
|
||||
res.column = result_type->createColumnConstWithDefaultValue(1);
|
||||
if (auto col = function_base->getResultIfAlwaysReturnsConstantAndHasArguments(sample_block, arguments))
|
||||
{
|
||||
res.column = std::move(col);
|
||||
names_not_for_constant_folding.insert(result_name);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user