Add cast type supprt to DateTimeTransformImpl

This commit is contained in:
Dmitry Kardymon 2023-06-01 14:22:57 +00:00
parent 3936c4dc52
commit 54d526c75c
5 changed files with 147 additions and 6 deletions

View File

@ -319,6 +319,49 @@ SELECT
## toDateOrNull
## toDateOrDefault
Converts an input value to [Date](/docs/en/sql-reference/data-types/date.md) data type.
If unsuccessful, returns the lower border value supported by [Date](/docs/en/sql-reference/data-types/date.md). The default value can be specified as a second argument.
Similar to [toDate](#todate).
**Syntax**
``` sql
toDateOrDefault(expr [, default_value])
```
**Arguments**
- `expr` — The value. [String](/docs/en/sql-reference/data-types/string.md), [Int](/docs/en/sql-reference/data-types/int-uint.md), [Date](/docs/en/sql-reference/data-types/date.md) or [DateTime](/docs/en/sql-reference/data-types/datetime.md).
- `default_value` — The default value. [Date](/docs/en/sql-reference/data-types/date.md)
If `expr` is a number and looks like a UNIX timestamp (is greater than 65535), it is interpreted as a DateTime, then truncated to Date in the current timezone. If `expr` is a number and it is smaller than 65536, it is interpreted as the number of days since 1970-01-01.
**Returned value**
- A calendar date. [Date](/docs/en/sql-reference/data-types/date.md)
**Example**
Query:
``` sql
SELECT
toDateOrDefault('2021-01-01', '2023-01-01'::Date),
toDateOrDefault('xx2021-01-01', '2023-01-01'::Date);
```
Result:
```response
┌─toDateOrDefault('2021-01-01', CAST('2023-01-01', 'Date'))─┬─toDateOrDefault('xx2021-01-01', CAST('2023-01-01', 'Date'))─┐
│ 2021-01-01 │ 2023-01-01 │
└───────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────┘
```
**See Also**
- [toDate](#todate)
- [toDate32OrDefault](#todate32ordefault)
## toDateTime
@ -327,6 +370,48 @@ SELECT
## toDateTimeOrNull
## toDateTimeOrDefault
Converts an input value to [DateTime](/docs/en/sql-reference/data-types/datetime.md) data type.
If unsuccessful, returns the lower border value supported by [DateTime](/docs/en/sql-reference/data-types/datetime.md). The default value can be specified as a third argument.
Similar to [toDateTime](#todatetime).
**Syntax**
``` sql
toDateTimeOrDefault(expr, [, time_zone [, default_value]])
```
**Arguments**
- `expr` — The value. [String](/docs/en/sql-reference/data-types/string.md), [Int](/docs/en/sql-reference/data-types/int-uint.md), [Date](/docs/en/sql-reference/data-types/date.md) or [DateTime](/docs/en/sql-reference/data-types/datetime.md).
- `time_zone` — Time zone.
- `default_value` — The default value. [DateTime](/docs/en/sql-reference/data-types/datetime.md)
If `expr` is a number, it is interpreted as the number of seconds since the beginning of the Unix Epoch (as Unix timestamp).
**Returned value**
- A date time. [DateTime](/docs/en/sql-reference/data-types/datetime.md)
**Example**
Query:
``` sql
SELECT
toDateTimeOrDefault('2021-01-01', 'UTC', '2023-01-01'::DateTime('UTC')),
toDateTimeOrDefault('xx2021-01-01', 'UTC', '2023-01-01'::DateTime('UTC'));
```
Result:
```response
┌─toDateTimeOrDefault('2021-01-01', 'UTC', CAST('2023-01-01', 'DateTime(\'UTC\')'))─┬─toDateTimeOrDefault('xx2021-01-01', 'UTC', CAST('2023-01-01', 'DateTime(\'UTC\')'))─┐
│ 2021-01-01 00:00:00 │ 2023-01-01 00:00:00 │
└───────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────┘
```
**See Also**
- [toDateTime](#todatetime)
## toDate32

View File

@ -21,6 +21,7 @@ namespace ErrorCodes
{
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int ILLEGAL_COLUMN;
extern const int CANNOT_CONVERT_TYPE;
}
/** Transformations.
@ -1425,8 +1426,10 @@ struct ToDateTimeComponentsImpl
using FactorTransform = ZeroTransform;
};
struct DateTimeAccurateConvertStrategyAdditions {};
struct DateTimeAccurateOrNullConvertStrategyAdditions {};
template <typename FromType, typename ToType, typename Transform, bool is_extended_result = false>
template <typename FromType, typename ToType, typename Transform, bool is_extended_result = false, typename Additions = void *>
struct Transformer
{
template <typename FromTypeVector, typename ToTypeVector>
@ -1438,6 +1441,33 @@ struct Transformer
for (size_t i = 0; i < size; ++i)
{
constexpr bool transformHasExtraCheck = requires(const Transform& t)
{
t.ExtraCheck(vec_from[i], time_zone);
};
if constexpr (transformHasExtraCheck)
{
// if constexpr (std::is_same_v<Additions, DateTimeAccurateConvertStrategyAdditions>
// || std::is_same_v<Additions, DateTimeAccurateOrNullConvertStrategyAdditions>)
{
bool checked = transform.ExtraCheck(vec_from[i], time_zone);
if (!checked)
{
if (std::is_same_v<Additions, DateTimeAccurateConvertStrategyAdditions>)
{
// vec_to[i] = 0;
// (*vec_null_map_to)[i] = true;
}
else
{
throw Exception(ErrorCodes::CANNOT_CONVERT_TYPE, "Value in column {} cannot be safely converted into type {}",
TypeName<ValueType>, TypeName<ValueType>);
}
}
}
}
if constexpr (is_extended_result)
vec_to[i] = static_cast<ValueType>(transform.executeExtendedResult(vec_from[i], time_zone));
else
@ -1446,14 +1476,14 @@ struct Transformer
}
};
template <typename FromDataType, typename ToDataType, typename Transform, bool is_extended_result = false>
struct DateTimeTransformImpl
{
template <typename Additions = void *>
static ColumnPtr execute(
const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t /*input_rows_count*/, const Transform & transform = {})
{
using Op = Transformer<typename FromDataType::FieldType, typename ToDataType::FieldType, Transform, is_extended_result>;
using Op = Transformer<typename FromDataType::FieldType, typename ToDataType::FieldType, Transform, is_extended_result, Additions>;
const ColumnPtr source_col = arguments[0].column;
if (const auto * sources = checkAndGetColumn<typename FromDataType::ColumnType>(source_col.get()))

View File

@ -400,7 +400,11 @@ template <typename FromType, typename ToType>
struct ToDateTransform8Or16Signed
{
static constexpr auto name = "toDate";
static NO_SANITIZE_UNDEFINED bool ExtraCheck(const FromType & from, const DateLUTImpl &)
{
return from >= 0;
}
static NO_SANITIZE_UNDEFINED ToType execute(const FromType & from, const DateLUTImpl &)
{
if (from < 0)
@ -2884,8 +2888,16 @@ private:
if constexpr (IsDataTypeNumber<LeftDataType> && IsDataTypeDateOrDateTime<RightDataType>)
{
result_column = ConvertImpl<LeftDataType, RightDataType, FunctionName>::execute(
arguments, result_type, input_rows_count);
if (wrapper_cast_type == CastType::accurate)
{
result_column = ConvertImpl<LeftDataType, RightDataType, FunctionName>::template execute<DateTimeAccurateConvertStrategyAdditions>(
arguments, result_type, input_rows_count);
}
else
{
result_column = ConvertImpl<LeftDataType, RightDataType, FunctionName>::template execute<DateTimeAccurateOrNullConvertStrategyAdditions>(
arguments, result_type, input_rows_count);
}
return true;
}

View File

@ -6,3 +6,7 @@
5
1
12
2023-05-30 14:38:20
1970-01-01 00:00:19
2023-05-30
1970-01-20

View File

@ -22,3 +22,13 @@ SELECT accurateCast(-10, 'Decimal32(9)'); -- { serverError 407 }
SELECT accurateCast('123', 'FixedString(2)'); -- { serverError 131 }
SELECT accurateCast('12', 'FixedString(2)');
SELECT accurateCast(-1, 'DateTime'); -- { serverError 70 }
SELECT accurateCast('1xxx', 'DateTime'); -- { serverError 41 }
SELECT accurateCast('2023-05-30 14:38:20', 'DateTime');
SELECT accurateCast(19, 'DateTime');
SELECT accurateCast(-1, 'Date'); -- { serverError 70 }
SELECT accurateCast('1xxx', 'Date'); -- { serverError 70 }
SELECT accurateCast('2023-05-30', 'Date');
SELECT accurateCast(19, 'Date');