[feature](function) support now/current_timestamp functions with precision (#12219)

* [feature](function) support now/current_timestamp functions with precision
This commit is contained in:
Gabriel
2022-09-01 14:35:12 +08:00
committed by GitHub
parent c5481dfdf7
commit 3bcab8bbef
16 changed files with 245 additions and 45 deletions

View File

@ -107,9 +107,14 @@ RuntimeState::RuntimeState(const TQueryGlobals& query_globals)
_is_cancelled(false),
_per_fragment_instance_idx(0) {
_query_options.batch_size = DEFAULT_BATCH_SIZE;
if (query_globals.__isset.time_zone) {
if (query_globals.__isset.time_zone && query_globals.__isset.nano_seconds) {
_timezone = query_globals.time_zone;
_timestamp_ms = query_globals.timestamp_ms;
_nano_seconds = query_globals.nano_seconds;
} else if (query_globals.__isset.time_zone) {
_timezone = query_globals.time_zone;
_timestamp_ms = query_globals.timestamp_ms;
_nano_seconds = 0;
} else if (!query_globals.now_string.empty()) {
_timezone = TimezoneUtils::default_time_zone;
DateTimeValue dt;
@ -117,10 +122,12 @@ RuntimeState::RuntimeState(const TQueryGlobals& query_globals)
int64_t timestamp;
dt.unix_timestamp(&timestamp, _timezone);
_timestamp_ms = timestamp * 1000;
_nano_seconds = 0;
} else {
//Unit test may set into here
_timezone = TimezoneUtils::default_time_zone;
_timestamp_ms = 0;
_nano_seconds = 0;
}
TimezoneUtils::find_cctz_time_zone(_timezone, _timezone_obj);
}
@ -135,6 +142,7 @@ RuntimeState::RuntimeState()
_query_options.batch_size = DEFAULT_BATCH_SIZE;
_timezone = TimezoneUtils::default_time_zone;
_timestamp_ms = 0;
_nano_seconds = 0;
TimezoneUtils::find_cctz_time_zone(_timezone, _timezone_obj);
_exec_env = ExecEnv::GetInstance();
}
@ -161,9 +169,14 @@ Status RuntimeState::init(const TUniqueId& fragment_instance_id, const TQueryOpt
const TQueryGlobals& query_globals, ExecEnv* exec_env) {
_fragment_instance_id = fragment_instance_id;
_query_options = query_options;
if (query_globals.__isset.time_zone) {
if (query_globals.__isset.time_zone && query_globals.__isset.nano_seconds) {
_timezone = query_globals.time_zone;
_timestamp_ms = query_globals.timestamp_ms;
_nano_seconds = query_globals.nano_seconds;
} else if (query_globals.__isset.time_zone) {
_timezone = query_globals.time_zone;
_timestamp_ms = query_globals.timestamp_ms;
_nano_seconds = 0;
} else if (!query_globals.now_string.empty()) {
_timezone = TimezoneUtils::default_time_zone;
DateTimeValue dt;
@ -171,10 +184,12 @@ Status RuntimeState::init(const TUniqueId& fragment_instance_id, const TQueryOpt
int64_t timestamp;
dt.unix_timestamp(&timestamp, _timezone);
_timestamp_ms = timestamp * 1000;
_nano_seconds = 0;
} else {
//Unit test may set into here
_timezone = TimezoneUtils::default_time_zone;
_timestamp_ms = 0;
_nano_seconds = 0;
}
TimezoneUtils::find_cctz_time_zone(_timezone, _timezone_obj);

View File

@ -114,6 +114,7 @@ public:
int num_scanner_threads() const { return _query_options.num_scanner_threads; }
TQueryType::type query_type() const { return _query_options.query_type; }
int64_t timestamp_ms() const { return _timestamp_ms; }
int32_t nano_seconds() const { return _nano_seconds; }
const std::string& timezone() const { return _timezone; }
const cctz::time_zone& timezone_obj() const { return _timezone_obj; }
const std::string& user() const { return _user; }
@ -428,6 +429,7 @@ private:
//Query-global timestamp_ms
int64_t _timestamp_ms;
int32_t _nano_seconds;
std::string _timezone;
cctz::time_zone _timezone_obj;

View File

@ -90,9 +90,10 @@ std::string DataTypeDateTimeV2::to_string(const IColumn& column, size_t row_num)
.get_data()[row_num];
DateV2Value<DateTimeV2ValueType> val =
binary_cast<UInt64, DateV2Value<DateTimeV2ValueType>>(int_val);
std::stringstream ss;
ss << val;
return ss.str();
char buf[64];
char* pos = val.to_string(buf, scale_);
return std::string(buf, pos - buf - 1);
}
void DataTypeDateTimeV2::to_string(const IColumn& column, size_t row_num,
@ -104,7 +105,7 @@ void DataTypeDateTimeV2::to_string(const IColumn& column, size_t row_num,
binary_cast<UInt64, DateV2Value<DateTimeV2ValueType>>(int_val);
char buf[64];
char* pos = value.to_string(buf);
char* pos = value.to_string(buf, scale_);
// DateTime to_string the end is /0
ostr.write(buf, pos - buf - 1);
}

View File

@ -205,12 +205,22 @@ struct LocalTimestampFunctionName {
static constexpr auto name = "localtimestamp";
};
using FunctionNow = FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<NowFunctionName>>;
using FunctionNow = FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<NowFunctionName, false>>;
using FunctionCurrentTimestamp =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<CurrentTimestampFunctionName>>;
using FunctionLocalTime = FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimeFunctionName>>;
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<CurrentTimestampFunctionName, false>>;
using FunctionLocalTime =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimeFunctionName, false>>;
using FunctionLocalTimestamp =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimestampFunctionName>>;
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimestampFunctionName, false>>;
using FunctionNowWithPrecision =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<NowFunctionName, true>>;
using FunctionCurrentTimestampWithPrecision =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<CurrentTimestampFunctionName, true>>;
using FunctionLocalTimeWithPrecision =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimeFunctionName, true>>;
using FunctionLocalTimestampWithPrecision =
FunctionCurrentDateOrDateTime<CurrentDateTimeImpl<LocalTimestampFunctionName, true>>;
struct CurDateFunctionName {
static constexpr auto name = "curdate";
@ -337,6 +347,10 @@ void register_function_date_time_computation(SimpleFunctionFactory& factory) {
factory.register_function<FunctionCurrentTimestamp>();
factory.register_function<FunctionLocalTime>();
factory.register_function<FunctionLocalTimestamp>();
factory.register_function<FunctionNowWithPrecision>();
factory.register_function<FunctionCurrentTimestampWithPrecision>();
factory.register_function<FunctionLocalTimeWithPrecision>();
factory.register_function<FunctionLocalTimestampWithPrecision>();
factory.register_function(CurrentDateFunctionName::name,
&createCurrentDateFunctionBuilderFunction);
factory.register_function(CurDateFunctionName::name, &createCurDateFunctionBuilderFunction);

View File

@ -579,6 +579,9 @@ public:
template <typename FunctionImpl>
class FunctionCurrentDateOrDateTime : public IFunction {
public:
static constexpr bool has_variadic_argument =
!std::is_void_v<decltype(has_variadic_argument_types(std::declval<FunctionImpl>()))>;
static constexpr auto name = FunctionImpl::name;
static FunctionPtr create() { return std::make_shared<FunctionCurrentDateOrDateTime>(); }
@ -590,51 +593,148 @@ public:
return std::make_shared<typename FunctionImpl::ReturnType>();
}
bool is_variadic() const override { return true; }
DataTypes get_variadic_argument_types_impl() const override {
if constexpr (has_variadic_argument) return FunctionImpl::get_variadic_argument_types();
return {};
}
Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) override {
DCHECK(arguments.empty());
return FunctionImpl::execute(context, block, result, input_rows_count);
return FunctionImpl::execute(context, block, arguments, result, input_rows_count);
}
};
template <typename FunctionName>
template <typename FunctionName, bool WithPrecision>
struct CurrentDateTimeImpl {
using ReturnType = DataTypeDateTime;
static constexpr auto name = FunctionName::name;
static Status execute(FunctionContext* context, Block& block, size_t result,
size_t input_rows_count) {
WhichDataType which(remove_nullable(block.get_by_position(result).type));
if (which.is_date_time_v2()) {
return executeImpl<DateV2Value<DateTimeV2ValueType>, UInt64>(context, block, result,
input_rows_count);
} else if (which.is_date_v2()) {
return executeImpl<DateV2Value<DateV2ValueType>, UInt32>(context, block, result,
input_rows_count);
using ReturnType = std::conditional_t<WithPrecision, DataTypeDateTimeV2, DataTypeDateTime>;
static DataTypes get_variadic_argument_types() {
if constexpr (WithPrecision) {
return {std::make_shared<DataTypeInt32>()};
} else {
return executeImpl<VecDateTimeValue, Int64>(context, block, result, input_rows_count);
return {};
}
}
static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) {
WhichDataType which(remove_nullable(block.get_by_position(result).type));
if constexpr (WithPrecision) {
DCHECK(which.is_date_time_v2() || which.is_date_v2());
if (which.is_date_time_v2()) {
return executeImpl<DateV2Value<DateTimeV2ValueType>, UInt64>(
context, block, arguments, result, input_rows_count);
} else {
return executeImpl<DateV2Value<DateV2ValueType>, UInt32>(context, block, arguments,
result, input_rows_count);
}
} else {
if (which.is_date_time_v2()) {
return executeImpl<DateV2Value<DateTimeV2ValueType>, UInt64>(
context, block, arguments, result, input_rows_count);
} else if (which.is_date_v2()) {
return executeImpl<DateV2Value<DateV2ValueType>, UInt32>(context, block, arguments,
result, input_rows_count);
} else {
return executeImpl<VecDateTimeValue, Int64>(context, block, arguments, result,
input_rows_count);
}
}
}
template <typename DateValueType, typename NativeType>
static Status executeImpl(FunctionContext* context, Block& block, size_t result,
static Status executeImpl(FunctionContext* context, Block& block,
const ColumnNumbers& arguments, size_t result,
size_t input_rows_count) {
auto col_to = ColumnVector<NativeType>::create();
DateValueType dtv;
if (dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
context->impl()->state()->timezone_obj())) {
if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
reinterpret_cast<DateValueType*>(&dtv)->set_type(TIME_DATETIME);
}
auto date_packed_int = binary_cast<DateValueType, NativeType>(dtv);
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)), 0);
if constexpr (WithPrecision) {
if (const ColumnConst* const_column = check_and_get_column<ColumnConst>(
block.get_by_position(arguments[0]).column)) {
int scale = const_column->get_int(0);
if (dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
context->impl()->state()->nano_seconds(),
context->impl()->state()->timezone_obj(), scale)) {
if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
reinterpret_cast<DateValueType*>(&dtv)->set_type(TIME_DATETIME);
}
auto date_packed_int = binary_cast<DateValueType, NativeType>(dtv);
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)),
0);
}
} else {
auto invalid_val = 0;
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&invalid_val)), 0);
}
}
} else if (const ColumnNullable* nullable_column = check_and_get_column<ColumnNullable>(
block.get_by_position(arguments[0]).column)) {
const auto& null_map = nullable_column->get_null_map_data();
const auto& nested_column = nullable_column->get_nested_column_ptr();
for (int i = 0; i < input_rows_count; i++) {
if (!null_map[i] &&
dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
context->impl()->state()->nano_seconds(),
context->impl()->state()->timezone_obj(),
nested_column->get64(i))) {
if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
reinterpret_cast<DateValueType*>(&dtv)->set_type(TIME_DATETIME);
}
auto date_packed_int = binary_cast<DateValueType, NativeType>(dtv);
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)),
0);
} else {
auto invalid_val = 0;
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&invalid_val)), 0);
}
}
} else {
auto& int_column = block.get_by_position(arguments[0]).column;
for (int i = 0; i < input_rows_count; i++) {
if (dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
context->impl()->state()->nano_seconds(),
context->impl()->state()->timezone_obj(),
int_column->get64(i))) {
if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
reinterpret_cast<DateValueType*>(&dtv)->set_type(TIME_DATETIME);
}
auto date_packed_int = binary_cast<DateValueType, NativeType>(dtv);
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)),
0);
} else {
auto invalid_val = 0;
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&invalid_val)), 0);
}
}
}
} else {
auto invalid_val = 0;
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&invalid_val)),
0);
if (dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
context->impl()->state()->timezone_obj())) {
if constexpr (std::is_same_v<DateValueType, VecDateTimeValue>) {
reinterpret_cast<DateValueType*>(&dtv)->set_type(TIME_DATETIME);
}
auto date_packed_int = binary_cast<DateValueType, NativeType>(dtv);
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)), 0);
}
} else {
auto invalid_val = 0;
for (int i = 0; i < input_rows_count; i++) {
col_to->insert_data(
const_cast<const char*>(reinterpret_cast<char*>(&invalid_val)), 0);
}
}
}
block.get_by_position(result).column = std::move(col_to);
@ -646,8 +746,8 @@ template <typename FunctionName, typename DateType, typename NativeType>
struct CurrentDateImpl {
using ReturnType = DateType;
static constexpr auto name = FunctionName::name;
static Status execute(FunctionContext* context, Block& block, size_t result,
size_t input_rows_count) {
static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) {
auto col_to = ColumnVector<NativeType>::create();
if constexpr (std::is_same_v<DateType, DataTypeDateV2>) {
DateV2Value<DateV2ValueType> dtv;
@ -694,8 +794,8 @@ template <typename FunctionName>
struct CurrentTimeImpl {
using ReturnType = DataTypeFloat64;
static constexpr auto name = FunctionName::name;
static Status execute(FunctionContext* context, Block& block, size_t result,
size_t input_rows_count) {
static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) {
auto col_to = ColumnVector<Float64>::create();
VecDateTimeValue dtv;
if (dtv.from_unixtime(context->impl()->state()->timestamp_ms() / 1000,
@ -719,8 +819,8 @@ struct CurrentTimeImpl {
struct UtcTimestampImpl {
using ReturnType = DataTypeDateTime;
static constexpr auto name = "utc_timestamp";
static Status execute(FunctionContext* context, Block& block, size_t result,
size_t input_rows_count) {
static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) {
WhichDataType which(remove_nullable(block.get_by_position(result).type));
if (which.is_date_time_v2()) {
return executeImpl<DateV2Value<DateTimeV2ValueType>, UInt64>(context, block, result,

View File

@ -2607,6 +2607,31 @@ bool DateV2Value<T>::from_unixtime(int64_t timestamp, const cctz::time_zone& ctz
return true;
}
template <typename T>
bool DateV2Value<T>::from_unixtime(int64_t timestamp, int32_t nano_seconds,
const std::string& timezone, const int scale) {
cctz::time_zone ctz;
if (!TimezoneUtils::find_cctz_time_zone(timezone, ctz)) {
return false;
}
return from_unixtime(timestamp, nano_seconds, ctz, scale);
}
template <typename T>
bool DateV2Value<T>::from_unixtime(int64_t timestamp, int32_t nano_seconds,
const cctz::time_zone& ctz, const int scale) {
static const cctz::time_point<cctz::sys_seconds> epoch =
std::chrono::time_point_cast<cctz::sys_seconds>(
std::chrono::system_clock::from_time_t(0));
cctz::time_point<cctz::sys_seconds> t = epoch + cctz::seconds(timestamp);
const auto tp = cctz::convert(t, ctz);
set_time(tp.year(), tp.month(), tp.day(), tp.hour(), tp.minute(), tp.second(),
nano_seconds / std::pow(10, 9 - scale) * std::pow(10, 6 - scale));
return true;
}
template <typename T>
const char* DateV2Value<T>::month_name() const {
if (date_v2_value_.month_ < 1 || date_v2_value_.month_ > 12) {

View File

@ -933,6 +933,9 @@ public:
bool from_unixtime(int64_t, const std::string& timezone);
bool from_unixtime(int64_t, const cctz::time_zone& ctz);
bool from_unixtime(int64_t, int32_t, const std::string& timezone, const int scale);
bool from_unixtime(int64_t, int32_t, const cctz::time_zone& ctz, const int scale);
bool operator==(const DateV2Value<T>& other) const {
// NOTE: This is not same with MySQL.
// MySQL convert both to int with left value type and then compare

View File

@ -81,6 +81,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@ -550,6 +551,7 @@ public class Analyzer {
Calendar currentDate = Calendar.getInstance();
String nowStr = formatter.format(currentDate.getTime());
queryGlobals.setNowString(nowStr);
queryGlobals.setNanoSeconds(LocalDateTime.now().getNano());
return queryGlobals;
}

View File

@ -82,6 +82,10 @@ public class FunctionCallExpr extends Expr {
.addAll(DECIMAL_SAME_TYPE_SET)
.addAll(DECIMAL_WIDER_TYPE_SET)
.addAll(STDDEV_FUNCTION_SET).build();
private static final ImmutableSet<String> TIME_FUNCTIONS_WITH_PRECISION =
new ImmutableSortedSet.Builder(String.CASE_INSENSITIVE_ORDER)
.add("now").add("current_timestamp").add("localtime").add("localtimestamp").build();
private static final int STDDEV_DECIMAL_SCALE = 9;
private static final String ELEMENT_EXTRACT_FN_NAME = "%element_extract%";
@ -1036,6 +1040,15 @@ public class FunctionCallExpr extends Expr {
}
}
if (TIME_FUNCTIONS_WITH_PRECISION.contains(fnName.getFunction().toLowerCase())
&& fn != null && fn.getReturnType().isDatetimeV2()) {
if (children.size() == 1 && children.get(0) instanceof IntLiteral) {
fn.setReturnType(ScalarType.createDatetimeV2Type((int) ((IntLiteral) children.get(0)).getLongValue()));
} else if (children.size() == 1) {
fn.setReturnType(ScalarType.createDatetimeV2Type(6));
}
}
if (fnName.getFunction().equalsIgnoreCase("from_unixtime")
|| fnName.getFunction().equalsIgnoreCase("date_format")) {
// if has only one child, it has default time format: yyyy-MM-dd HH:mm:ss.SSSSSS

View File

@ -61,6 +61,7 @@ import org.apache.logging.log4j.Logger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -204,6 +205,7 @@ public class StreamLoadPlanner {
queryGlobals.setTimestampMs(System.currentTimeMillis());
queryGlobals.setTimeZone(taskInfo.getTimezone());
queryGlobals.setLoadZeroTolerance(taskInfo.getMaxFilterRatio() <= 0.0);
queryGlobals.setNanoSeconds(LocalDateTime.now().getNano());
params.setQueryGlobals(queryGlobals);

View File

@ -115,6 +115,7 @@ import org.jetbrains.annotations.NotNull;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -251,6 +252,7 @@ public class Coordinator {
this.queryGlobals.setNowString(DATE_FORMAT.format(new Date()));
this.queryGlobals.setTimestampMs(System.currentTimeMillis());
this.queryGlobals.setNanoSeconds(LocalDateTime.now().getNano());
this.queryGlobals.setLoadZeroTolerance(false);
if (context.getSessionVariable().getTimeZone().equals("CST")) {
this.queryGlobals.setTimeZone(TimeUtils.DEFAULT_TIME_ZONE);

View File

@ -55,6 +55,7 @@ import org.apache.logging.log4j.Logger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -353,6 +354,7 @@ public class FoldConstantsRule implements ExprRewriteRule {
TQueryGlobals queryGlobals = new TQueryGlobals();
queryGlobals.setNowString(DATE_FORMAT.format(new Date()));
queryGlobals.setTimestampMs(System.currentTimeMillis());
queryGlobals.setNanoSeconds(LocalDateTime.now().getNano());
queryGlobals.setTimeZone(TimeUtils.DEFAULT_TIME_ZONE);
if (context.getSessionVariable().getTimeZone().equals("CST")) {
queryGlobals.setTimeZone(TimeUtils.DEFAULT_TIME_ZONE);

View File

@ -428,6 +428,9 @@ visible_functions = [
[['now', 'current_timestamp', 'localtime', 'localtimestamp'], 'DATETIME', [],
'_ZN5doris18TimestampFunctions3nowEPN9doris_udf15FunctionContextE',
'', '', 'vec', 'ALWAYS_NOT_NULLABLE'],
[['now', 'current_timestamp', 'localtime', 'localtimestamp'], 'DATETIMEV2', ['INT'],
'_ZN5doris18TimestampFunctions3nowEPN9doris_udf15FunctionContextE',
'', '', 'vec', 'ALWAYS_NOT_NULLABLE'],
[['curtime', 'current_time'], 'TIME', [],
'_ZN5doris18TimestampFunctions7curtimeEPN9doris_udf15FunctionContextE',
'', '', 'vec', 'ALWAYS_NOT_NULLABLE'],

View File

@ -260,7 +260,9 @@ struct TQueryGlobals {
3: optional string time_zone
// Set to true if in a load plan, the max_filter_ratio is 0.0
4: optional bool load_zero_tolerance = false;
4: optional bool load_zero_tolerance = false
5: optional i32 nano_seconds
}

View File

@ -383,3 +383,9 @@ true
-- !sql --
2018-04-02T15:03:28
-- !sql --
19 19 21 22 23 24 25 26
-- !sql --
19 19 21 22 23 24 25 26

View File

@ -303,4 +303,12 @@ suite("test_date_function") {
qt_sql """ select STR_TO_DATE('Tue Jul 12 20:00:45 CST 2022', '%a %b %e %H:%i:%s %Y'); """
qt_sql """ select STR_TO_DATE('Tue Jul 12 20:00:45 CST 2022', '%a %b %e %T CST %Y'); """
qt_sql """ select STR_TO_DATE('2018-4-2 15:3:28','%Y-%m-%d %H:%i:%s'); """
qt_sql """ select length(cast(now() as string)), length(cast(now(0) as string)), length(cast(now(1) as string)),
length(cast(now(2) as string)), length(cast(now(3) as string)), length(cast(now(4) as string)),
length(cast(now(5) as string)), length(cast(now(6) as string)); """
qt_sql """ select length(cast(current_timestamp() as string)), length(cast(current_timestamp(0) as string)),
length(cast(current_timestamp(1) as string)), length(cast(current_timestamp(2) as string)),
length(cast(current_timestamp(3) as string)), length(cast(current_timestamp(4) as string)),
length(cast(current_timestamp(5) as string)), length(cast(current_timestamp(6) as string)); """
}