dbms: added least and greatest functions [#METR-17233].

This commit is contained in:
Alexey Milovidov 2015-07-10 05:57:32 +03:00
parent 1f4f0f591b
commit 2af61829fe
5 changed files with 90 additions and 40 deletions

View File

@ -262,6 +262,30 @@ struct BitShiftRightImpl
} }
}; };
template<typename A, typename B>
struct LeastImpl
{
typedef typename NumberTraits::ResultOfIf<A, B>::Type ResultType;
template <typename Result = ResultType>
static inline Result apply(A a, B b)
{
return static_cast<Result>(a) < static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
}
};
template<typename A, typename B>
struct GreatestImpl
{
typedef typename NumberTraits::ResultOfIf<A, B>::Type ResultType;
template <typename Result = ResultType>
static inline Result apply(A a, B b)
{
return static_cast<Result>(a) > static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
}
};
template<typename A> template<typename A>
struct NegateImpl struct NegateImpl
{ {
@ -319,6 +343,12 @@ template <typename T> using Else = T;
/// Used to indicate undefined operation /// Used to indicate undefined operation
struct InvalidType; struct InvalidType;
template <>
struct DataTypeFromFieldType<NumberTraits::Error>
{
using Type = InvalidType;
};
template <typename DataType> struct IsIntegral { static constexpr auto value = false; }; template <typename DataType> struct IsIntegral { static constexpr auto value = false; };
template <> struct IsIntegral<DataTypeUInt8> { static constexpr auto value = true; }; template <> struct IsIntegral<DataTypeUInt8> { static constexpr auto value = true; };
template <> struct IsIntegral<DataTypeUInt16> { static constexpr auto value = true; }; template <> struct IsIntegral<DataTypeUInt16> { static constexpr auto value = true; };
@ -342,11 +372,13 @@ template <typename DataType> struct IsDateOrDateTime { static constexpr auto val
template <> struct IsDateOrDateTime<DataTypeDate> { static constexpr auto value = true; }; template <> struct IsDateOrDateTime<DataTypeDate> { static constexpr auto value = true; };
template <> struct IsDateOrDateTime<DataTypeDateTime> { static constexpr auto value = true; }; template <> struct IsDateOrDateTime<DataTypeDateTime> { static constexpr auto value = true; };
/** Returns appropriate result type for binary operator on dates: /** Returns appropriate result type for binary operator on dates (or datetimes):
* Date + Integral -> Date * Date + Integral -> Date
* Integral + Date -> Date * Integral + Date -> Date
* Date - Date -> Int32 * Date - Date -> Int32
* Date - Integral -> Date * Date - Integral -> Date
* least(Date, Date) -> Date
* greatest(Date, Date) -> Date
* All other operations are not defined and return InvalidType, operations on * All other operations are not defined and return InvalidType, operations on
* distinct date types are also undefined (e.g. DataTypeDate - DataTypeDateTime) */ * distinct date types are also undefined (e.g. DataTypeDate - DataTypeDateTime) */
template <template <typename, typename> class Operation, typename LeftDataType, typename RightDataType> template <template <typename, typename> class Operation, typename LeftDataType, typename RightDataType>
@ -387,7 +419,13 @@ struct DateBinaryOperationTraits
Else<InvalidType> Else<InvalidType>
> >
>, >,
Else<InvalidType> Else<
If<std::is_same<T0, T1>::value
&& (std::is_same<Op, LeastImpl<T0, T1>>::value || std::is_same<Op, GreatestImpl<T0, T1>>::value),
Then<LeftDataType>,
Else<InvalidType>
>
>
> >
> >
>; >;
@ -479,35 +517,27 @@ private:
} }
/// Overload for date operations /// Overload for date operations
template <typename LeftDataType, typename RightDataType, typename ColumnType, template <typename LeftDataType, typename RightDataType, typename ColumnType>
typename std::enable_if<IsDateOrDateTime<LeftDataType>::value || IsDateOrDateTime<RightDataType>::value>::type * = nullptr>
bool executeRightType(Block & block, const ColumnNumbers & arguments, const size_t result, const ColumnType * col_left) bool executeRightType(Block & block, const ColumnNumbers & arguments, const size_t result, const ColumnType * col_left)
{ {
if (!typeid_cast<const RightDataType *>(block.getByPosition(arguments[1]).type.get())) if (!typeid_cast<const RightDataType *>(block.getByPosition(arguments[1]).type.get()))
return false; return false;
using ResultDataType = typename DateBinaryOperationTraits<Op, LeftDataType, RightDataType>::ResultDataType; using ResultDataType = typename BinaryOperationTraits<Op, LeftDataType, RightDataType>::ResultDataType;
return executeRightTypeDispatch<LeftDataType, RightDataType, ResultDataType>( return executeRightTypeDispatch<LeftDataType, RightDataType, ResultDataType>(
block, arguments, result, col_left); block, arguments, result, col_left);
} }
/// Overload for numeric operations
template <typename LeftDataType, typename RightDataType, typename ColumnType,
typename T0 = typename LeftDataType::FieldType, typename T1 = typename RightDataType::FieldType,
typename std::enable_if<IsNumeric<LeftDataType>::value && IsNumeric<RightDataType>::value>::type * = nullptr>
bool executeRightType(Block & block, const ColumnNumbers & arguments, const size_t result, const ColumnType * col_left)
{
return executeRightTypeImpl<T0, T1>(block, arguments, result, col_left);
}
/// Overload for InvalidType /// Overload for InvalidType
template <typename LeftDataType, typename RightDataType, typename ResultDataType, typename ColumnType, template <typename LeftDataType, typename RightDataType, typename ResultDataType, typename ColumnType,
typename std::enable_if<std::is_same<ResultDataType, InvalidType>::value>::type * = nullptr> typename std::enable_if<std::is_same<ResultDataType, InvalidType>::value>::type * = nullptr>
bool executeRightTypeDispatch(Block & block, const ColumnNumbers & arguments, const size_t result, bool executeRightTypeDispatch(Block & block, const ColumnNumbers & arguments, const size_t result,
const ColumnType * col_left) const ColumnType * col_left)
{ {
return false; throw Exception("Types " + TypeName<typename LeftDataType::FieldType>::get()
+ " and " + TypeName<typename LeftDataType::FieldType>::get()
+ " are incompatible for function " + getName() + " or not upscaleable to common type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
} }
/// Overload for well-defined operations /// Overload for well-defined operations
@ -527,7 +557,7 @@ private:
template <typename T0, typename T1, typename ResultType = typename Op<T0, T1>::ResultType> template <typename T0, typename T1, typename ResultType = typename Op<T0, T1>::ResultType>
bool executeRightTypeImpl(Block & block, const ColumnNumbers & arguments, size_t result, const ColumnVector<T0> * col_left) bool executeRightTypeImpl(Block & block, const ColumnNumbers & arguments, size_t result, const ColumnVector<T0> * col_left)
{ {
if (auto col_right = typeid_cast<ColumnVector<T1> *>(block.getByPosition(arguments[1]).column.get())) if (auto col_right = typeid_cast<const ColumnVector<T1> *>(block.getByPosition(arguments[1]).column.get()))
{ {
auto col_res = new ColumnVector<ResultType>; auto col_res = new ColumnVector<ResultType>;
block.getByPosition(result).column = col_res; block.getByPosition(result).column = col_res;
@ -538,7 +568,7 @@ private:
return true; return true;
} }
else if (auto col_right = typeid_cast<ColumnConst<T1> *>(block.getByPosition(arguments[1]).column.get())) else if (auto col_right = typeid_cast<const ColumnConst<T1> *>(block.getByPosition(arguments[1]).column.get()))
{ {
auto col_res = new ColumnVector<ResultType>; auto col_res = new ColumnVector<ResultType>;
block.getByPosition(result).column = col_res; block.getByPosition(result).column = col_res;
@ -550,14 +580,14 @@ private:
return true; return true;
} }
return false; throw Exception("Logical error: unexpected type of column", ErrorCodes::LOGICAL_ERROR);
} }
/// ColumnConst overload /// ColumnConst overload
template <typename T0, typename T1, typename ResultType = typename Op<T0, T1>::ResultType> template <typename T0, typename T1, typename ResultType = typename Op<T0, T1>::ResultType>
bool executeRightTypeImpl(Block & block, const ColumnNumbers & arguments, size_t result, const ColumnConst<T0> * col_left) bool executeRightTypeImpl(Block & block, const ColumnNumbers & arguments, size_t result, const ColumnConst<T0> * col_left)
{ {
if (auto col_right = typeid_cast<ColumnVector<T1> *>(block.getByPosition(arguments[1]).column.get())) if (auto col_right = typeid_cast<const ColumnVector<T1> *>(block.getByPosition(arguments[1]).column.get()))
{ {
auto col_res = new ColumnVector<ResultType>; auto col_res = new ColumnVector<ResultType>;
block.getByPosition(result).column = col_res; block.getByPosition(result).column = col_res;
@ -568,7 +598,7 @@ private:
return true; return true;
} }
else if (auto col_right = typeid_cast<ColumnConst<T1> *>(block.getByPosition(arguments[1]).column.get())) else if (auto col_right = typeid_cast<const ColumnConst<T1> *>(block.getByPosition(arguments[1]).column.get()))
{ {
ResultType res = 0; ResultType res = 0;
BinaryOperationImpl<T0, T1, Op<T0, T1>, ResultType>::constant_constant(col_left->getData(), col_right->getData(), res); BinaryOperationImpl<T0, T1, Op<T0, T1>, ResultType>::constant_constant(col_left->getData(), col_right->getData(), res);
@ -582,26 +612,12 @@ private:
return false; return false;
} }
template <typename LeftDataType, template <typename LeftDataType>
typename std::enable_if<IsDateOrDateTime<LeftDataType>::value>::type * = nullptr>
bool executeLeftType(Block & block, const ColumnNumbers & arguments, const size_t result) bool executeLeftType(Block & block, const ColumnNumbers & arguments, const size_t result)
{ {
if (!typeid_cast<const LeftDataType *>(block.getByPosition(arguments[0]).type.get())) if (!typeid_cast<const LeftDataType *>(block.getByPosition(arguments[0]).type.get()))
return false; return false;
return executeLeftTypeDispatch<LeftDataType>(block, arguments, result);
}
template <typename LeftDataType,
typename std::enable_if<IsNumeric<LeftDataType>::value>::type * = nullptr>
bool executeLeftType(Block & block, const ColumnNumbers & arguments, const size_t result)
{
return executeLeftTypeDispatch<LeftDataType>(block, arguments, result);
}
template <typename LeftDataType>
bool executeLeftTypeDispatch(Block & block, const ColumnNumbers & arguments, const size_t result)
{
using T0 = typename LeftDataType::FieldType; using T0 = typename LeftDataType::FieldType;
if ( executeLeftTypeImpl<LeftDataType, ColumnVector<T0>>(block, arguments, result) if ( executeLeftTypeImpl<LeftDataType, ColumnVector<T0>>(block, arguments, result)
@ -614,7 +630,7 @@ private:
template <typename LeftDataType, typename ColumnType> template <typename LeftDataType, typename ColumnType>
bool executeLeftTypeImpl(Block & block, const ColumnNumbers & arguments, const size_t result) bool executeLeftTypeImpl(Block & block, const ColumnNumbers & arguments, const size_t result)
{ {
if (auto col_left = typeid_cast<ColumnType *>(block.getByPosition(arguments[0]).column.get())) if (auto col_left = typeid_cast<const ColumnType *>(block.getByPosition(arguments[0]).column.get()))
{ {
if ( executeRightType<LeftDataType, DataTypeDate>(block, arguments, result, col_left) if ( executeRightType<LeftDataType, DataTypeDate>(block, arguments, result, col_left)
|| executeRightType<LeftDataType, DataTypeDateTime>(block, arguments, result, col_left) || executeRightType<LeftDataType, DataTypeDateTime>(block, arguments, result, col_left)
@ -718,7 +734,7 @@ private:
template <typename T0> template <typename T0>
bool executeType(Block & block, const ColumnNumbers & arguments, size_t result) bool executeType(Block & block, const ColumnNumbers & arguments, size_t result)
{ {
if (ColumnVector<T0> * col = typeid_cast<ColumnVector<T0> *>(&*block.getByPosition(arguments[0]).column)) if (const ColumnVector<T0> * col = typeid_cast<const ColumnVector<T0> *>(&*block.getByPosition(arguments[0]).column))
{ {
typedef typename Op<T0>::ResultType ResultType; typedef typename Op<T0>::ResultType ResultType;
@ -731,7 +747,7 @@ private:
return true; return true;
} }
else if (ColumnConst<T0> * col = typeid_cast<ColumnConst<T0> *>(&*block.getByPosition(arguments[0]).column)) else if (const ColumnConst<T0> * col = typeid_cast<const ColumnConst<T0> *>(&*block.getByPosition(arguments[0]).column))
{ {
typedef typename Op<T0>::ResultType ResultType; typedef typename Op<T0>::ResultType ResultType;
@ -815,6 +831,8 @@ struct NameBitXor { static constexpr auto name = "bitXor"; };
struct NameBitNot { static constexpr auto name = "bitNot"; }; struct NameBitNot { static constexpr auto name = "bitNot"; };
struct NameBitShiftLeft { static constexpr auto name = "bitShiftLeft"; }; struct NameBitShiftLeft { static constexpr auto name = "bitShiftLeft"; };
struct NameBitShiftRight { static constexpr auto name = "bitShiftRight"; }; struct NameBitShiftRight { static constexpr auto name = "bitShiftRight"; };
struct NameLeast { static constexpr auto name = "least"; };
struct NameGreatest { static constexpr auto name = "greatest"; };
typedef FunctionBinaryArithmetic<PlusImpl, NamePlus> FunctionPlus; typedef FunctionBinaryArithmetic<PlusImpl, NamePlus> FunctionPlus;
typedef FunctionBinaryArithmetic<MinusImpl, NameMinus> FunctionMinus; typedef FunctionBinaryArithmetic<MinusImpl, NameMinus> FunctionMinus;
@ -831,7 +849,8 @@ typedef FunctionBinaryArithmetic<BitXorImpl, NameBitXor> FunctionBitXor;
typedef FunctionUnaryArithmetic<BitNotImpl, NameBitNot> FunctionBitNot; typedef FunctionUnaryArithmetic<BitNotImpl, NameBitNot> FunctionBitNot;
typedef FunctionBinaryArithmetic<BitShiftLeftImpl, NameBitShiftLeft> FunctionBitShiftLeft; typedef FunctionBinaryArithmetic<BitShiftLeftImpl, NameBitShiftLeft> FunctionBitShiftLeft;
typedef FunctionBinaryArithmetic<BitShiftRightImpl, NameBitShiftRight> FunctionBitShiftRight; typedef FunctionBinaryArithmetic<BitShiftRightImpl, NameBitShiftRight> FunctionBitShiftRight;
typedef FunctionBinaryArithmetic<LeastImpl, NameLeast> FunctionLeast;
typedef FunctionBinaryArithmetic<GreatestImpl, NameGreatest> FunctionGreatest;
/// Оптимизации для целочисленного деления на константу. /// Оптимизации для целочисленного деления на константу.

View File

@ -725,7 +725,11 @@ public:
column_first_array = column_array; column_first_array = column_array;
} }
temp_block.insert(ColumnWithNameAndType(column_array->getDataPtr(), argument_type, argument_name)); temp_block.insert(ColumnWithNameAndType(
column_array->getDataPtr(),
argument_type,
argument_name));
argument_names.insert(argument_name); argument_names.insert(argument_name);
} }
@ -745,6 +749,7 @@ public:
replicated_column.name = name; replicated_column.name = name;
replicated_column.column = typeid_cast<ColumnArray &>(*replicated_column.column).getDataPtr(); replicated_column.column = typeid_cast<ColumnArray &>(*replicated_column.column).getDataPtr();
replicated_column.type = typeid_cast<const DataTypeArray &>(*replicated_column.type).getNestedType(),
temp_block.insert(replicated_column); temp_block.insert(replicated_column);
++prerequisite_index; ++prerequisite_index;

View File

@ -21,6 +21,8 @@ void registerFunctionsArithmetic(FunctionFactory & factory)
factory.registerFunction<FunctionBitNot>(); factory.registerFunction<FunctionBitNot>();
factory.registerFunction<FunctionBitShiftLeft>(); factory.registerFunction<FunctionBitShiftLeft>();
factory.registerFunction<FunctionBitShiftRight>(); factory.registerFunction<FunctionBitShiftRight>();
factory.registerFunction<FunctionLeast>();
factory.registerFunction<FunctionGreatest>();
} }
} }

View File

@ -0,0 +1,12 @@
1 2 1 2 1 2 2 UInt8
1.1 2 1.1 2 1.1 2 2 Float64
-1 2 -1 2 -1 2 2 Int16
1 2 1 2 1 2 2 Float64
1 2000 1 2000 1 2000 2000 UInt16
1 200000 1 200000 1 200000 200000 UInt32
1 20000000000 1 20000000000 1 20000000000 20000000000 UInt64
123 123 123 123 123 123 123 UInt8
2010-01-02 2011-02-03 2010-01-02 2011-02-03 2010-01-02 2011-02-03 2011-02-03 Date
2010-01-02 03:04:05 2011-02-03 04:05:06 2010-01-02 03:04:05 2011-02-03 04:05:06 2010-01-02 03:04:05 2011-02-03 04:05:06 2011-02-03 04:05:06 DateTime
10
9

View File

@ -0,0 +1,12 @@
SELECT 1 AS x, 2 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 1.1 AS x, 2 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT -1 AS x, 2 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 1.0 AS x, 2.0 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 1 AS x, 2000 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 1 AS x, 200000 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 1 AS x, 20000000000 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT 123 AS x, 123 AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT toDate('2010-01-02') AS x, toDate('2011-02-03') AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT toDateTime('2010-01-02 03:04:05') AS x, toDateTime('2011-02-03 04:05:06') AS y, least(x, y), greatest(x, y), least(x, materialize(y)), greatest(materialize(x), y), greatest(materialize(x), materialize(y)), toTypeName(least(x, y));
SELECT greatest(now(), now() + 10) - now();
SELECT greatest(today(), yesterday() + 10) - today();