Added IFunctonBase::getResultIfAlwaysReturnsConstantAndHasArguments

This commit is contained in:
Nikolai Kochetov 2019-08-19 20:48:19 +03:00
parent a4e2fcdd49
commit d4363768e6
8 changed files with 92 additions and 30 deletions

View File

@ -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); }

View File

@ -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());
}
};

View File

@ -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);
}

View File

@ -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);
}
};

View File

@ -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());
}
};

View File

@ -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>();
}
}

View File

@ -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;

View File

@ -246,10 +246,13 @@ 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);
names_not_for_constant_folding.insert(result_name);
if (auto col = function_base->getResultIfAlwaysReturnsConstantAndHasArguments(sample_block, arguments))
{
res.column = std::move(col);
names_not_for_constant_folding.insert(result_name);
}
}
break;