Skip to content

Commit

Permalink
Merge pull request #50880 from ClickHouse/backport/23.5/50834
Browse files Browse the repository at this point in the history
Backport #50834 to 23.5: Add compat setting for non-const timezones
  • Loading branch information
rschu1ze committed Jun 13, 2023
2 parents dd1ec5b + c28ed3f commit 9655251
Show file tree
Hide file tree
Showing 25 changed files with 165 additions and 63 deletions.
1 change: 1 addition & 0 deletions src/Core/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class IColumn;
M(Bool, enable_memory_bound_merging_of_aggregation_results, true, "Enable memory bound merging strategy for aggregation.", 0) \
M(Bool, enable_positional_arguments, true, "Enable positional arguments in ORDER BY, GROUP BY and LIMIT BY", 0) \
M(Bool, enable_extended_results_for_datetime_functions, false, "Enable date functions like toLastDayOfMonth return Date32 results (instead of Date results) for Date32/DateTime64 arguments.", 0) \
M(Bool, allow_nonconst_timezone_arguments, false, "Allow non-const timezone arguments in certain time-related functions like toTimeZone(), fromUnixTimestamp*(), snowflakeToDateTime*()", 0) \
\
M(Bool, group_by_use_nulls, false, "Treat columns mentioned in ROLLUP, CUBE or GROUPING SETS as Nullable", 0) \
\
Expand Down
1 change: 1 addition & 0 deletions src/Core/SettingsChangesHistory.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ static std::map<ClickHouseVersion, SettingsChangesHistory::SettingsChanges> sett
{"use_with_fill_by_sorting_prefix", false, true, "Columns preceding WITH FILL columns in ORDER BY clause form sorting prefix. Rows with different values in sorting prefix are filled independently"},
{"output_format_parquet_compliant_nested_types", false, true, "Change an internal field name in output Parquet file schema."}}},
{"23.4", {{"allow_suspicious_indices", true, false, "If true, index can defined with identical expressions"},
{"allow_nonconst_timezone_arguments", true, false, "Allow non-const timezone arguments in certain time-related functions like toTimeZone(), fromUnixTimestamp*(), snowflakeToDateTime*()."},
{"connect_timeout_with_failover_ms", 50, 1000, "Increase default connect timeout because of async connect"},
{"connect_timeout_with_failover_secure_ms", 100, 1000, "Increase default secure connect timeout because of async connect"},
{"hedged_connection_timeout_ms", 100, 50, "Start new connection in hedged requests after 50 ms instead of 100 to correspond with previous connect timeout"}}},
Expand Down
4 changes: 2 additions & 2 deletions src/Functions/FunctionDateOrDateTimeAddInterval.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ class FunctionDateOrDateTimeAddInterval : public IFunction
}
else if constexpr (std::is_same_v<ResultDataType, DataTypeDateTime>)
{
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0));
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0, false));
}
else if constexpr (std::is_same_v<ResultDataType, DataTypeDateTime64>)
{
Expand All @@ -696,7 +696,7 @@ class FunctionDateOrDateTimeAddInterval : public IFunction
return {};
});

auto timezone = extractTimeZoneNameFromFunctionArguments(arguments, 2, 0);
auto timezone = extractTimeZoneNameFromFunctionArguments(arguments, 2, 0, false);
if (const auto* datetime64_type = typeid_cast<const DataTypeDateTime64 *>(arguments[0].type.get()))
{
const auto from_scale = datetime64_type->getScale();
Expand Down
2 changes: 1 addition & 1 deletion src/Functions/FunctionDateOrDateTimeToDateOrDate32.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class FunctionDateOrDateTimeToDateOrDate32 : public IFunctionDateOrDateTime<Tran
/// If the time zone is specified but empty, throw an exception.
/// only validate the time_zone part if the number of arguments is 2.
if ((which.isDateTime() || which.isDateTime64()) && arguments.size() == 2
&& extractTimeZoneNameFromFunctionArguments(arguments, 1, 0).empty())
&& extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, false).empty())
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Function {} supports a 2nd argument (optional) that must be a valid time zone",
this->getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class FunctionDateOrDateTimeToDateTimeOrDateTime64 : public IFunctionDateOrDateT

WhichDataType which(from_type);

std::string time_zone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
std::string time_zone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, false);

/// If the time zone is specified but empty, throw an exception.
/// only validate the time_zone part if the number of arguments is 2.
Expand Down
4 changes: 2 additions & 2 deletions src/Functions/FunctionDateOrDateTimeToSomething.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class FunctionDateOrDateTimeToSomething : public IFunctionDateOrDateTime<Transfo
/// If the time zone is specified but empty, throw an exception.
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
{
std::string time_zone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
std::string time_zone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, false);
/// only validate the time_zone part if the number of arguments is 2. This is mainly
/// to accommodate functions like toStartOfDay(today()), toStartOfDay(yesterday()) etc.
if (arguments.size() == 2 && time_zone.empty())
Expand Down Expand Up @@ -53,7 +53,7 @@ class FunctionDateOrDateTimeToSomething : public IFunctionDateOrDateTime<Transfo
scale = std::max(source_scale, static_cast<Int64>(9));
}

return std::make_shared<ToDataType>(scale, extractTimeZoneNameFromFunctionArguments(arguments, 1, 0));
return std::make_shared<ToDataType>(scale, extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, false));
}
else
return std::make_shared<ToDataType>();
Expand Down
17 changes: 13 additions & 4 deletions src/Functions/FunctionSnowflake.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <DataTypes/DataTypeDateTime64.h>
#include <DataTypes/DataTypesNumber.h>
#include <Columns/ColumnsNumber.h>
#include <Interpreters/Context.h>

#include <base/arithmeticOverflow.h>

Expand Down Expand Up @@ -72,9 +73,13 @@ class FunctionSnowflakeToDateTime : public IFunction
{
private:
const char * name;
const bool allow_nonconst_timezone_arguments;

public:
explicit FunctionSnowflakeToDateTime(const char * name_) : name(name_) { }
explicit FunctionSnowflakeToDateTime(const char * name_, ContextPtr context)
: name(name_)
, allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
{}

String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 0; }
Expand All @@ -92,7 +97,7 @@ class FunctionSnowflakeToDateTime : public IFunction

std::string timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);

return std::make_shared<DataTypeDateTime>(timezone);
}
Expand Down Expand Up @@ -162,9 +167,13 @@ class FunctionSnowflakeToDateTime64 : public IFunction
{
private:
const char * name;
const bool allow_nonconst_timezone_arguments;

public:
explicit FunctionSnowflakeToDateTime64(const char * name_) : name(name_) { }
explicit FunctionSnowflakeToDateTime64(const char * name_, ContextPtr context)
: name(name_)
, allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
{}

String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 0; }
Expand All @@ -182,7 +191,7 @@ class FunctionSnowflakeToDateTime64 : public IFunction

std::string timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);

return std::make_shared<DataTypeDateTime64>(3, timezone);
}
Expand Down
13 changes: 8 additions & 5 deletions src/Functions/FunctionUnixTimestamp64.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <DataTypes/DataTypeDateTime64.h>
#include <DataTypes/DataTypesNumber.h>
#include <Columns/ColumnsNumber.h>
#include <Interpreters/Context.h>

#include <base/arithmeticOverflow.h>

Expand Down Expand Up @@ -99,11 +100,13 @@ class FunctionFromUnixTimestamp64 : public IFunction
private:
size_t target_scale;
const char * name;
const bool allow_nonconst_timezone_arguments;
public:
FunctionFromUnixTimestamp64(size_t target_scale_, const char * name_)
: target_scale(target_scale_), name(name_)
{
}
FunctionFromUnixTimestamp64(size_t target_scale_, const char * name_, ContextPtr context)
: target_scale(target_scale_)
, name(name_)
, allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
{}

String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 0; }
Expand All @@ -121,7 +124,7 @@ class FunctionFromUnixTimestamp64 : public IFunction

std::string timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);

return std::make_shared<DataTypeDateTime64>(target_scale, timezone);
}
Expand Down
10 changes: 5 additions & 5 deletions src/Functions/FunctionsConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -1796,13 +1796,13 @@ class FunctionConvert : public IFunction

if (to_datetime64 || scale != 0) /// toDateTime('xxxx-xx-xx xx:xx:xx', 0) return DateTime
return std::make_shared<DataTypeDateTime64>(scale,
extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0, false));

return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0, false));
}

if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0, false));
else if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected branch in code of conversion function: it is a bug.");
else
Expand Down Expand Up @@ -2067,7 +2067,7 @@ class FunctionConvertFromString : public IFunction
UInt64 scale = to_datetime64 ? DataTypeDateTime64::default_scale : 0;
if (arguments.size() > 1)
scale = extractToDecimalScale(arguments[1]);
const auto timezone = extractTimeZoneNameFromFunctionArguments(arguments, 2, 0);
const auto timezone = extractTimeZoneNameFromFunctionArguments(arguments, 2, 0, false);

res = scale == 0 ? res = std::make_shared<DataTypeDateTime>(timezone) : std::make_shared<DataTypeDateTime64>(scale, timezone);
}
Expand Down Expand Up @@ -2117,7 +2117,7 @@ class FunctionConvertFromString : public IFunction
}

if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
res = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 1, 0));
res = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, false));
else if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
throw Exception(ErrorCodes::LOGICAL_ERROR, "LOGICAL ERROR: It is a bug.");
else if constexpr (to_decimal)
Expand Down
4 changes: 2 additions & 2 deletions src/Functions/FunctionsTimeWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ struct TimeWindowImpl<TUMBLE>
if (result_type_is_date)
data_type = std::make_shared<DataTypeDate>();
else
data_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0));
data_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 0, false));

return std::make_shared<DataTypeTuple>(DataTypes{data_type, data_type});
}
Expand Down Expand Up @@ -322,7 +322,7 @@ struct TimeWindowImpl<HOP>
if (result_type_is_date)
data_type = std::make_shared<DataTypeDate>();
else
data_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 3, 0));
data_type = std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 3, 0, false));
return std::make_shared<DataTypeTuple>(DataTypes{data_type, data_type});
}

Expand Down
2 changes: 1 addition & 1 deletion src/Functions/date_trunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class FunctionDateTrunc : public IFunction
if (result_type_is_date)
return std::make_shared<DataTypeDate>();
else
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 1));
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 2, 1, false));
}

bool useDefaultImplementationForConstants() const override { return true; }
Expand Down
5 changes: 3 additions & 2 deletions src/Functions/extractTimeZoneFromFunctionArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ std::string extractTimeZoneNameFromColumn(const IColumn * column, const String &
}


std::string extractTimeZoneNameFromFunctionArguments(const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num)
std::string extractTimeZoneNameFromFunctionArguments(const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num, bool allow_nonconst_timezone_arguments)
{
/// Explicit time zone may be passed in last argument.
if (arguments.size() == time_zone_arg_num + 1)
if ((arguments.size() == time_zone_arg_num + 1)
&& (!allow_nonconst_timezone_arguments || arguments[time_zone_arg_num].column))
{
return extractTimeZoneNameFromColumn(arguments[time_zone_arg_num].column.get(), arguments[time_zone_arg_num].name);
}
Expand Down
10 changes: 9 additions & 1 deletion src/Functions/extractTimeZoneFromFunctionArguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ std::string extractTimeZoneNameFromColumn(const IColumn * column, const String &

/// Determine working timezone either from optional argument with time zone name or from time zone in DateTime type of argument.
/// Returns empty string if default time zone should be used.
///
/// Parameter allow_nonconst_timezone_arguments toggles if non-const timezone function arguments are accepted (legacy behavior) or not. The
/// problem with the old behavior is that the timezone is part of the type, and not part of the value. This lead to confusion and unexpected
/// results.
/// - For new functions, set allow_nonconst_timezone_arguments = false.
/// - For existing functions
/// - which disallow non-const timezone arguments anyways (e.g. getArgumentsThatAreAlwaysConstant()), set allow_nonconst_timezone_arguments = false,
/// - which allow non-const timezone arguments, set allow_nonconst_timezone_arguments according to the corresponding setting.
std::string extractTimeZoneNameFromFunctionArguments(
const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num);
const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num, bool allow_nonconst_timezone_arguments);

const DateLUTImpl & extractTimeZoneFromFunctionArguments(
const ColumnsWithTypeAndName & arguments, size_t time_zone_arg_num, size_t datetime_arg_num);
Expand Down
4 changes: 2 additions & 2 deletions src/Functions/fromUnixTimestamp64Micro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace DB
REGISTER_FUNCTION(FromUnixTimestamp64Micro)
{
factory.registerFunction("fromUnixTimestamp64Micro",
[](ContextPtr){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(6, "fromUnixTimestamp64Micro")); });
[](ContextPtr context){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(6, "fromUnixTimestamp64Micro", context)); });
}

}
4 changes: 2 additions & 2 deletions src/Functions/fromUnixTimestamp64Milli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace DB
REGISTER_FUNCTION(FromUnixTimestamp64Milli)
{
factory.registerFunction("fromUnixTimestamp64Milli",
[](ContextPtr){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(3, "fromUnixTimestamp64Milli")); });
[](ContextPtr context){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(3, "fromUnixTimestamp64Milli", context)); });
}

}
4 changes: 2 additions & 2 deletions src/Functions/fromUnixTimestamp64Nano.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace DB
REGISTER_FUNCTION(FromUnixTimestamp64Nano)
{
factory.registerFunction("fromUnixTimestamp64Nano",
[](ContextPtr){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(9, "fromUnixTimestamp64Nano")); });
[](ContextPtr context){ return std::make_unique<FunctionToOverloadResolverAdaptor>(
std::make_shared<FunctionFromUnixTimestamp64>(9, "fromUnixTimestamp64Nano", context)); });
}

}
12 changes: 9 additions & 3 deletions src/Functions/now.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <Functions/FunctionFactory.h>
#include <Functions/IFunction.h>
#include <Functions/extractTimeZoneFromFunctionArguments.h>
#include <Interpreters/Context.h>

namespace DB
{
Expand Down Expand Up @@ -87,7 +88,10 @@ class NowOverloadResolver : public IFunctionOverloadResolver
bool isVariadic() const override { return true; }

size_t getNumberOfArguments() const override { return 0; }
static FunctionOverloadResolverPtr create(ContextPtr) { return std::make_unique<NowOverloadResolver>(); }
static FunctionOverloadResolverPtr create(ContextPtr context) { return std::make_unique<NowOverloadResolver>(context); }
explicit NowOverloadResolver(ContextPtr context)
: allow_nonconst_timezone_arguments(context->getSettings().allow_nonconst_timezone_arguments)
{}

DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
Expand All @@ -102,7 +106,7 @@ class NowOverloadResolver : public IFunctionOverloadResolver
}
if (arguments.size() == 1)
{
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 0, 0));
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 0, 0, allow_nonconst_timezone_arguments));
}
return std::make_shared<DataTypeDateTime>();
}
Expand All @@ -121,10 +125,12 @@ class NowOverloadResolver : public IFunctionOverloadResolver
if (arguments.size() == 1)
return std::make_unique<FunctionBaseNow>(
time(nullptr), DataTypes{arguments.front().type},
std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 0, 0)));
std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, 0, 0, allow_nonconst_timezone_arguments)));

return std::make_unique<FunctionBaseNow>(time(nullptr), DataTypes(), std::make_shared<DataTypeDateTime>());
}
private:
const bool allow_nonconst_timezone_arguments;
};

}
Expand Down

0 comments on commit 9655251

Please sign in to comment.