Merge remote-tracking branch 'upstream/master' into fix4

This commit is contained in:
proller 2017-10-30 13:22:20 +03:00
commit 956e1513c5
66 changed files with 1784 additions and 644 deletions

View File

@ -1,6 +1,6 @@
# This strings autochanged from release_lib.sh: # This strings autochanged from release_lib.sh:
set(VERSION_DESCRIBE v1.1.54300-testing) set(VERSION_DESCRIBE v1.1.54306-testing)
set(VERSION_REVISION 54300) set(VERSION_REVISION 54306)
# end of autochange # end of autochange
set (VERSION_MAJOR 1) set (VERSION_MAJOR 1)

View File

@ -92,7 +92,7 @@ private:
} }
public: public:
AggregateFunctionForEach(AggregateFunctionPtr nested_) explicit AggregateFunctionForEach(AggregateFunctionPtr nested_)
: nested_func_owner(nested_), nested_func(nested_func_owner.get()) : nested_func_owner(nested_), nested_func(nested_func_owner.get())
{ {
} }

View File

@ -26,6 +26,8 @@ private:
Array parameters; Array parameters;
public: public:
static constexpr bool is_parametric = true;
DataTypeAggregateFunction(const AggregateFunctionPtr & function_, const DataTypes & argument_types_, const Array & parameters_) DataTypeAggregateFunction(const AggregateFunctionPtr & function_, const DataTypes & argument_types_, const Array & parameters_)
: function(function_), argument_types(argument_types_), parameters(parameters_) : function(function_), argument_types(argument_types_), parameters(parameters_)
{ {

View File

@ -19,6 +19,8 @@ private:
DataTypePtr offsets; DataTypePtr offsets;
public: public:
static constexpr bool is_parametric = true;
DataTypeArray(const DataTypePtr & nested_); DataTypeArray(const DataTypePtr & nested_);
DataTypeArray(const DataTypeTraits::EnrichedDataTypePtr & enriched_nested_); DataTypeArray(const DataTypeTraits::EnrichedDataTypePtr & enriched_nested_);

View File

@ -36,6 +36,8 @@ public:
using NameToValueMap = HashMap<StringRef, FieldType, StringRefHash>; using NameToValueMap = HashMap<StringRef, FieldType, StringRefHash>;
using ValueToNameMap = std::unordered_map<FieldType, StringRef>; using ValueToNameMap = std::unordered_map<FieldType, StringRef>;
static constexpr bool is_parametric = true;
private: private:
Values values; Values values;
NameToValueMap name_to_value_map; NameToValueMap name_to_value_map;

View File

@ -15,6 +15,8 @@ private:
DataTypePtr return_type; DataTypePtr return_type;
public: public:
static constexpr bool is_parametric = true;
/// Some types could be still unknown. /// Some types could be still unknown.
DataTypeExpression(const DataTypes & argument_types_ = DataTypes(), const DataTypePtr & return_type_ = nullptr) DataTypeExpression(const DataTypes & argument_types_ = DataTypes(), const DataTypePtr & return_type_ = nullptr)
: argument_types(argument_types_), return_type(return_type_) {} : argument_types(argument_types_), return_type(return_type_) {}

View File

@ -117,6 +117,7 @@ void registerDataTypeNull(DataTypeFactory & factory);
void registerDataTypeUUID(DataTypeFactory & factory); void registerDataTypeUUID(DataTypeFactory & factory);
void registerDataTypeAggregateFunction(DataTypeFactory & factory); void registerDataTypeAggregateFunction(DataTypeFactory & factory);
void registerDataTypeNested(DataTypeFactory & factory); void registerDataTypeNested(DataTypeFactory & factory);
void registerDataTypeInterval(DataTypeFactory & factory);
DataTypeFactory::DataTypeFactory() DataTypeFactory::DataTypeFactory()
@ -134,6 +135,7 @@ DataTypeFactory::DataTypeFactory()
registerDataTypeUUID(*this); registerDataTypeUUID(*this);
registerDataTypeAggregateFunction(*this); registerDataTypeAggregateFunction(*this);
registerDataTypeNested(*this); registerDataTypeNested(*this);
registerDataTypeInterval(*this);
} }
} }

View File

@ -18,6 +18,8 @@ private:
size_t n; size_t n;
public: public:
static constexpr bool is_parametric = true;
DataTypeFixedString(size_t n_) : n(n_) DataTypeFixedString(size_t n_) : n(n_)
{ {
if (n == 0) if (n == 0)

View File

@ -0,0 +1,19 @@
#include <DataTypes/DataTypeInterval.h>
#include <DataTypes/DataTypeFactory.h>
namespace DB
{
void registerDataTypeInterval(DataTypeFactory & factory)
{
factory.registerSimpleDataType("IntervalSecond", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Second)); });
factory.registerSimpleDataType("IntervalMinute", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Minute)); });
factory.registerSimpleDataType("IntervalHour", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Hour)); });
factory.registerSimpleDataType("IntervalDay", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Day)); });
factory.registerSimpleDataType("IntervalWeek", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Week)); });
factory.registerSimpleDataType("IntervalMonth", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Month)); });
factory.registerSimpleDataType("IntervalYear", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(DataTypeInterval::Year)); });
}
}

View File

@ -0,0 +1,66 @@
#pragma once
#include <DataTypes/DataTypeNumberBase.h>
namespace DB
{
/** Data type to deal with INTERVAL in SQL (arithmetic on time intervals).
*
* Mostly the same as Int64.
* But also tagged with interval kind.
*
* Intended isage is for temporary elements in expressions,
* not for storing values in tables.
*/
class DataTypeInterval final : public DataTypeNumberBase<Int64>
{
public:
enum Kind
{
Second,
Minute,
Hour,
Day,
Week,
Month,
Year
};
private:
Kind kind;
public:
static constexpr bool is_parametric = true;
Kind getKind() const { return kind; }
const char * kindToString() const
{
switch (kind)
{
case Second: return "Second";
case Minute: return "Minute";
case Hour: return "Hour";
case Day: return "Day";
case Week: return "Week";
case Month: return "Month";
case Year: return "Year";
default: __builtin_unreachable();
}
}
DataTypeInterval(Kind kind) : kind(kind) {};
std::string getName() const override { return std::string("Interval") + kindToString(); }
const char * getFamilyName() const override { return "Interval"; }
bool behavesAsNumber() const override { return false; }
bool notForTables() const override { return true; }
DataTypePtr clone() const override { return std::make_shared<DataTypeInterval>(kind); }
};
}

View File

@ -17,6 +17,8 @@ private:
NamesAndTypesListPtr nested; NamesAndTypesListPtr nested;
public: public:
static constexpr bool is_parametric = true;
DataTypeNested(const NamesAndTypesListPtr & nested_); DataTypeNested(const NamesAndTypesListPtr & nested_);
std::string getName() const override; std::string getName() const override;

View File

@ -16,6 +16,8 @@ public:
using FieldType = Null; using FieldType = Null;
public: public:
static constexpr bool is_parametric = false;
String getName() const override String getName() const override
{ {
return "Null"; return "Null";

View File

@ -11,6 +11,8 @@ namespace DB
class DataTypeNullable final : public IDataType class DataTypeNullable final : public IDataType
{ {
public: public:
static constexpr bool is_parametric = true;
DataTypeNullable(const DataTypePtr & nested_data_type_); DataTypeNullable(const DataTypePtr & nested_data_type_);
std::string getName() const override { return "Nullable(" + nested_data_type->getName() + ")"; } std::string getName() const override { return "Nullable(" + nested_data_type->getName() + ")"; }
const char * getFamilyName() const override { return "Nullable"; } const char * getFamilyName() const override { return "Nullable"; }

View File

@ -12,6 +12,7 @@ template <typename T>
class DataTypeNumberBase : public IDataType class DataTypeNumberBase : public IDataType
{ {
public: public:
static constexpr bool is_parametric = false;
using FieldType = T; using FieldType = T;
std::string getName() const override { return TypeName<T>::get(); } std::string getName() const override { return TypeName<T>::get(); }

View File

@ -12,6 +12,7 @@ namespace DB
class DataTypeSet final : public IDataTypeDummy class DataTypeSet final : public IDataTypeDummy
{ {
public: public:
static constexpr bool is_parametric = true;
std::string getName() const override { return "Set"; } std::string getName() const override { return "Set"; }
const char * getFamilyName() const override { return "Set"; } const char * getFamilyName() const override { return "Set"; }
DataTypePtr clone() const override { return std::make_shared<DataTypeSet>(); } DataTypePtr clone() const override { return std::make_shared<DataTypeSet>(); }

View File

@ -12,6 +12,7 @@ class DataTypeString final : public IDataType
{ {
public: public:
using FieldType = String; using FieldType = String;
static constexpr bool is_parametric = false;
std::string getName() const override std::string getName() const override
{ {

View File

@ -16,6 +16,7 @@ class DataTypeTuple final : public IDataType
private: private:
DataTypes elems; DataTypes elems;
public: public:
static constexpr bool is_parametric = true;
DataTypeTuple(const DataTypes & elems_) : elems(elems_) {} DataTypeTuple(const DataTypes & elems_) : elems(elems_) {}
std::string getName() const override; std::string getName() const override;

View File

@ -33,6 +33,7 @@ class DataTypeNumber<void> final : public IDataTypeDummy
{ {
public: public:
using FieldType = void; using FieldType = void;
static constexpr bool is_parametric = false;
std::string getName() const override { return "Void"; } std::string getName() const override { return "Void"; }
const char * getFamilyName() const override { return "Void"; } const char * getFamilyName() const override { return "Void"; }
@ -46,6 +47,7 @@ class DataTypeNumber<Null> final : public IDataTypeDummy
{ {
public: public:
using FieldType = Null; using FieldType = Null;
static constexpr bool is_parametric = false;
std::string getName() const override { return "Null"; } std::string getName() const override { return "Null"; }
const char * getFamilyName() const override { return "Null"; } const char * getFamilyName() const override { return "Null"; }

View File

@ -29,6 +29,12 @@ using DataTypes = std::vector<DataTypePtr>;
class IDataType class IDataType
{ {
public: public:
/// Compile time flag. If false, then if C++ types are the same, then SQL types are also the same.
/// Example: DataTypeString is not parametric: thus all instances of DataTypeString are the same SQL type.
/// Example: DataTypeFixedString is parametric: different instances of DataTypeFixedString may be different SQL types.
/// Place it in descendants:
/// static constexpr bool is_parametric = false;
/// Name of data type (examples: UInt64, Array(String)). /// Name of data type (examples: UInt64, Array(String)).
virtual String getName() const = 0; virtual String getName() const = 0;

View File

@ -13,6 +13,11 @@
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int EMPTY_LIST_OF_COLUMNS_PASSED;
}
String getTableDefinitionFromCreateQuery(const ASTPtr & query) String getTableDefinitionFromCreateQuery(const ASTPtr & query)
{ {
@ -22,8 +27,6 @@ String getTableDefinitionFromCreateQuery(const ASTPtr & query)
/// We remove everything that is not needed for ATTACH from the query. /// We remove everything that is not needed for ATTACH from the query.
create.attach = true; create.attach = true;
create.database.clear(); create.database.clear();
create.as_database.clear();
create.as_table.clear();
create.if_not_exists = false; create.if_not_exists = false;
create.is_populate = false; create.is_populate = false;
@ -31,6 +34,13 @@ String getTableDefinitionFromCreateQuery(const ASTPtr & query)
if (!create.is_view && !create.is_materialized_view) if (!create.is_view && !create.is_materialized_view)
create.select = nullptr; create.select = nullptr;
/// For "MATERIALIZED VIEW x TO y" it's necessary to save destination table
if (!(create.is_materialized_view && !create.storage))
{
create.as_database.clear();
create.as_table.clear();
}
std::ostringstream statement_stream; std::ostringstream statement_stream;
formatAST(create, statement_stream, 0, false); formatAST(create, statement_stream, 0, false);
statement_stream << '\n'; statement_stream << '\n';
@ -56,6 +66,8 @@ std::pair<String, StoragePtr> createTableFromDefinition(
/// We do not directly use `InterpreterCreateQuery::execute`, because /// We do not directly use `InterpreterCreateQuery::execute`, because
/// - the database has not been created yet; /// - the database has not been created yet;
/// - the code is simpler, since the query is already brought to a suitable form. /// - the code is simpler, since the query is already brought to a suitable form.
if (!ast_create_query.columns)
throw Exception("Missing definition of columns.", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED);
InterpreterCreateQuery::ColumnsInfo columns_info = InterpreterCreateQuery::getColumnsInfo(*ast_create_query.columns, context); InterpreterCreateQuery::ColumnsInfo columns_info = InterpreterCreateQuery::getColumnsInfo(*ast_create_query.columns, context);

View File

@ -3,10 +3,12 @@
#include <DataTypes/DataTypesNumber.h> #include <DataTypes/DataTypesNumber.h>
#include <DataTypes/DataTypeDate.h> #include <DataTypes/DataTypeDate.h>
#include <DataTypes/DataTypeDateTime.h> #include <DataTypes/DataTypeDateTime.h>
#include <DataTypes/DataTypeInterval.h>
#include <Columns/ColumnVector.h> #include <Columns/ColumnVector.h>
#include <Columns/ColumnConst.h> #include <Columns/ColumnConst.h>
#include <Functions/IFunction.h> #include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h> #include <Functions/FunctionHelpers.h>
#include <Functions/FunctionFactory.h>
#include <DataTypes/NumberTraits.h> #include <DataTypes/NumberTraits.h>
#include <Core/AccurateComparison.h> #include <Core/AccurateComparison.h>
#include <Core/FieldVisitors.h> #include <Core/FieldVisitors.h>
@ -542,9 +544,13 @@ class FunctionBinaryArithmetic : public IFunction
{ {
public: public:
static constexpr auto name = Name::name; static constexpr auto name = Name::name;
static FunctionPtr create(const Context & context) { return std::make_shared<FunctionBinaryArithmetic>(); } static FunctionPtr create(const Context & context) { return std::make_shared<FunctionBinaryArithmetic>(context); }
FunctionBinaryArithmetic(const Context & context) : context(context) {}
private: private:
const Context & context;
/// Overload for InvalidType /// Overload for InvalidType
template <typename ResultDataType, template <typename ResultDataType,
typename std::enable_if<std::is_same<ResultDataType, InvalidType>::value>::type * = nullptr> typename std::enable_if<std::is_same<ResultDataType, InvalidType>::value>::type * = nullptr>
@ -745,6 +751,47 @@ private:
return false; return false;
} }
FunctionPtr getFunctionForIntervalArithmetic(const DataTypePtr & type0, const DataTypePtr & type1) const
{
/// Special case when the function is plus or minus, one of arguments is Date/DateTime and another is Interval.
/// We construct another function (example: addMonths) and call it.
bool function_is_plus = std::is_same<Op<UInt8, UInt8>, PlusImpl<UInt8, UInt8>>::value;
bool function_is_minus = std::is_same<Op<UInt8, UInt8>, MinusImpl<UInt8, UInt8>>::value;
if (!function_is_plus && !function_is_minus)
return {};
int interval_arg = 1;
const DataTypeInterval * interval_data_type = checkAndGetDataType<DataTypeInterval>(type1.get());
if (!interval_data_type)
{
interval_arg = 0;
interval_data_type = checkAndGetDataType<DataTypeInterval>(type0.get());
}
if (!interval_data_type)
return {};
if (interval_arg == 0 && function_is_minus)
throw Exception("Wrong order of arguments for function " + getName() + ": argument of type Interval cannot be first.",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
const DataTypeDate * date_data_type = checkAndGetDataType<DataTypeDate>(interval_arg == 0 ? type1.get() : type0.get());
const DataTypeDateTime * date_time_data_type = nullptr;
if (!date_data_type)
{
date_time_data_type = checkAndGetDataType<DataTypeDateTime>(interval_arg == 0 ? type1.get() : type0.get());
if (!date_time_data_type)
throw Exception("Wrong argument types for function " + getName() + ": if one argument is Interval, then another must be Date or DateTime.",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
std::stringstream function_name;
function_name << (function_is_plus ? "add" : "subtract") << interval_data_type->kindToString() << 's';
return FunctionFactory::instance().get(function_name.str(), context);
}
public: public:
String getName() const override String getName() const override
{ {
@ -755,6 +802,21 @@ public:
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
/// Special case when the function is plus or minus, one of arguments is Date/DateTime and another is Interval.
if (FunctionPtr function = getFunctionForIntervalArithmetic(arguments[0], arguments[1]))
{
DataTypes new_arguments = arguments;
/// Interval argument must be second.
if (checkDataType<DataTypeInterval>(new_arguments[0].get()))
std::swap(new_arguments[0], new_arguments[1]);
/// Change interval argument to its representation
new_arguments[1] = std::make_shared<DataTypeNumber<DataTypeInterval::FieldType>>();
return function->getReturnTypeImpl(new_arguments);
}
DataTypePtr type_res; DataTypePtr type_res;
if (!( checkLeftType<DataTypeDate>(arguments, type_res) if (!( checkLeftType<DataTypeDate>(arguments, type_res)
@ -777,6 +839,25 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{ {
/// Special case when the function is plus or minus, one of arguments is Date/DateTime and another is Interval.
if (FunctionPtr function = getFunctionForIntervalArithmetic(block.getByPosition(arguments[0]).type, block.getByPosition(arguments[1]).type))
{
ColumnNumbers new_arguments = arguments;
/// Interval argument must be second.
if (checkDataType<DataTypeInterval>(block.getByPosition(arguments[0]).type.get()))
std::swap(new_arguments[0], new_arguments[1]);
/// Change interval argument type to its representation
Block new_block = block;
new_block.getByPosition(new_arguments[1]).type = std::make_shared<DataTypeNumber<DataTypeInterval::FieldType>>();
function->executeImpl(new_block, new_arguments, result);
block.getByPosition(result).column = new_block.getByPosition(result).column;
return;
}
if (!( executeLeftType<DataTypeDate>(block, arguments, result) if (!( executeLeftType<DataTypeDate>(block, arguments, result)
|| executeLeftType<DataTypeDateTime>(block, arguments, result) || executeLeftType<DataTypeDateTime>(block, arguments, result)
|| executeLeftType<DataTypeUInt8>(block, arguments, result) || executeLeftType<DataTypeUInt8>(block, arguments, result)

View File

@ -57,13 +57,16 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToInt64>(); factory.registerFunction<FunctionToInt64>();
factory.registerFunction<FunctionToFloat32>(); factory.registerFunction<FunctionToFloat32>();
factory.registerFunction<FunctionToFloat64>(); factory.registerFunction<FunctionToFloat64>();
factory.registerFunction<FunctionToDate>(); factory.registerFunction<FunctionToDate>();
factory.registerFunction<FunctionToDateTime>(); factory.registerFunction<FunctionToDateTime>();
factory.registerFunction<FunctionToUUID>(); factory.registerFunction<FunctionToUUID>();
factory.registerFunction<FunctionToString>(); factory.registerFunction<FunctionToString>();
factory.registerFunction<FunctionToFixedString>(); factory.registerFunction<FunctionToFixedString>();
factory.registerFunction<FunctionToUnixTimestamp>(); factory.registerFunction<FunctionToUnixTimestamp>();
factory.registerFunction<FunctionCast>(); factory.registerFunction<FunctionCast>();
factory.registerFunction<FunctionToUInt8OrZero>(); factory.registerFunction<FunctionToUInt8OrZero>();
factory.registerFunction<FunctionToUInt16OrZero>(); factory.registerFunction<FunctionToUInt16OrZero>();
factory.registerFunction<FunctionToUInt32OrZero>(); factory.registerFunction<FunctionToUInt32OrZero>();
@ -74,6 +77,14 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToInt64OrZero>(); factory.registerFunction<FunctionToInt64OrZero>();
factory.registerFunction<FunctionToFloat32OrZero>(); factory.registerFunction<FunctionToFloat32OrZero>();
factory.registerFunction<FunctionToFloat64OrZero>(); factory.registerFunction<FunctionToFloat64OrZero>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalSecond, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalMinute, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalHour, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalDay, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalWeek, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalMonth, PositiveMonotonicity>>();
factory.registerFunction<FunctionConvert<DataTypeInterval, NameToIntervalYear, PositiveMonotonicity>>();
} }
} }

View File

@ -19,6 +19,7 @@
#include <DataTypes/DataTypeTuple.h> #include <DataTypes/DataTypeTuple.h>
#include <DataTypes/DataTypeNullable.h> #include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypeUUID.h> #include <DataTypes/DataTypeUUID.h>
#include <DataTypes/DataTypeInterval.h>
#include <Columns/ColumnString.h> #include <Columns/ColumnString.h>
#include <Columns/ColumnFixedString.h> #include <Columns/ColumnFixedString.h>
#include <Columns/ColumnConst.h> #include <Columns/ColumnConst.h>
@ -94,6 +95,8 @@ struct ConvertImpl
*/ */
struct ToDateTimeImpl struct ToDateTimeImpl
{ {
static constexpr auto name = "toDateTime";
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
return time_zone.fromDayNum(DayNum_t(d)); return time_zone.fromDayNum(DayNum_t(d));
@ -101,7 +104,7 @@ struct ToDateTimeImpl
}; };
template <typename Name> struct ConvertImpl<DataTypeDate, DataTypeDateTime, Name> template <typename Name> struct ConvertImpl<DataTypeDate, DataTypeDateTime, Name>
: DateTimeTransformImpl<UInt16, UInt32, ToDateTimeImpl, Name> {}; : DateTimeTransformImpl<UInt16, UInt32, ToDateTimeImpl> {};
/// Implementation of toDate function. /// Implementation of toDate function.
@ -109,6 +112,8 @@ template <typename Name> struct ConvertImpl<DataTypeDate, DataTypeDateTime, Name
template <typename FromType, typename ToType> template <typename FromType, typename ToType>
struct ToDateTransform32Or64 struct ToDateTransform32Or64
{ {
static constexpr auto name = "toDate";
static inline ToType execute(const FromType & from, const DateLUTImpl & time_zone) static inline ToType execute(const FromType & from, const DateLUTImpl & time_zone)
{ {
return (from < 0xFFFF) ? from : time_zone.toDayNum(from); return (from < 0xFFFF) ? from : time_zone.toDayNum(from);
@ -118,7 +123,7 @@ struct ToDateTransform32Or64
/** Conversion of DateTime to Date: throw off time component. /** Conversion of DateTime to Date: throw off time component.
*/ */
template <typename Name> struct ConvertImpl<DataTypeDateTime, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeDateTime, DataTypeDate, Name>
: DateTimeTransformImpl<UInt32, UInt16, ToDateImpl, Name> {}; : DateTimeTransformImpl<UInt32, UInt16, ToDateImpl> {};
/** Special case of converting (U)Int32 or (U)Int64 (and also, for convenience, Float32, Float64) to Date. /** Special case of converting (U)Int32 or (U)Int64 (and also, for convenience, Float32, Float64) to Date.
* If number is less than 65536, then it is treated as DayNum, and if greater or equals, then as unix timestamp. * If number is less than 65536, then it is treated as DayNum, and if greater or equals, then as unix timestamp.
@ -128,17 +133,17 @@ template <typename Name> struct ConvertImpl<DataTypeDateTime, DataTypeDate, Name
* (otherwise such usage would be frequent mistake). * (otherwise such usage would be frequent mistake).
*/ */
template <typename Name> struct ConvertImpl<DataTypeUInt32, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeUInt32, DataTypeDate, Name>
: DateTimeTransformImpl<UInt32, UInt16, ToDateTransform32Or64<UInt32, UInt16>, Name> {}; : DateTimeTransformImpl<UInt32, UInt16, ToDateTransform32Or64<UInt32, UInt16>> {};
template <typename Name> struct ConvertImpl<DataTypeUInt64, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeUInt64, DataTypeDate, Name>
: DateTimeTransformImpl<UInt64, UInt16, ToDateTransform32Or64<UInt64, UInt16>, Name> {}; : DateTimeTransformImpl<UInt64, UInt16, ToDateTransform32Or64<UInt64, UInt16>> {};
template <typename Name> struct ConvertImpl<DataTypeInt32, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeInt32, DataTypeDate, Name>
: DateTimeTransformImpl<Int32, UInt16, ToDateTransform32Or64<Int32, UInt16>, Name> {}; : DateTimeTransformImpl<Int32, UInt16, ToDateTransform32Or64<Int32, UInt16>> {};
template <typename Name> struct ConvertImpl<DataTypeInt64, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeInt64, DataTypeDate, Name>
: DateTimeTransformImpl<Int64, UInt16, ToDateTransform32Or64<Int64, UInt16>, Name> {}; : DateTimeTransformImpl<Int64, UInt16, ToDateTransform32Or64<Int64, UInt16>> {};
template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeFloat32, DataTypeDate, Name>
: DateTimeTransformImpl<Float32, UInt16, ToDateTransform32Or64<Float32, UInt16>, Name> {}; : DateTimeTransformImpl<Float32, UInt16, ToDateTransform32Or64<Float32, UInt16>> {};
template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDate, Name> template <typename Name> struct ConvertImpl<DataTypeFloat64, DataTypeDate, Name>
: DateTimeTransformImpl<Float64, UInt16, ToDateTransform32Or64<Float64, UInt16>, Name> {}; : DateTimeTransformImpl<Float64, UInt16, ToDateTransform32Or64<Float64, UInt16>> {};
/** Transformation of numbers, dates, datetimes to strings: through formatting. /** Transformation of numbers, dates, datetimes to strings: through formatting.
@ -196,7 +201,7 @@ const DateLUTImpl * extractTimeZoneFromFunctionArguments(Block & block, const Co
template <typename FromDataType, typename Name> template <typename FromDataType, typename Name>
struct ConvertImpl<FromDataType, DataTypeString, Name> struct ConvertImpl<FromDataType, typename std::enable_if<!std::is_same<FromDataType, DataTypeString>::value, DataTypeString>::type, Name>
{ {
using FromFieldType = typename FromDataType::FieldType; using FromFieldType = typename FromDataType::FieldType;
@ -261,7 +266,7 @@ struct ConvertImplGenericToString
ColumnString::Chars_t & data_to = col_to->getChars(); ColumnString::Chars_t & data_to = col_to->getChars();
ColumnString::Offsets_t & offsets_to = col_to->getOffsets(); ColumnString::Offsets_t & offsets_to = col_to->getOffsets();
data_to.resize(size * 2); /// Using coefficient 2 for initial size is arbitary. data_to.resize(size * 2); /// Using coefficient 2 for initial size is arbitary.
offsets_to.resize(size); offsets_to.resize(size);
WriteBufferFromVector<ColumnString::Chars_t> write_buffer(data_to); WriteBufferFromVector<ColumnString::Chars_t> write_buffer(data_to);
@ -326,7 +331,7 @@ void throwExceptionForIncompletelyParsedValue(
template <typename ToDataType, typename Name> template <typename ToDataType, typename Name>
struct ConvertImpl<DataTypeString, ToDataType, Name> struct ConvertImpl<typename std::enable_if<!std::is_same<ToDataType, DataTypeString>::value, DataTypeString>::type, ToDataType, Name>
{ {
using ToFieldType = typename ToDataType::FieldType; using ToFieldType = typename ToDataType::FieldType;
@ -479,7 +484,7 @@ struct ConvertImplGenericFromString
/// Function toUnixTimestamp has exactly the same implementation as toDateTime of String type. /// Function toUnixTimestamp has exactly the same implementation as toDateTime of String type.
/// Note that time zone argument could be passed only for toUnixTimestamp function. /// Note that time zone argument could be passed only for toUnixTimestamp function.
struct NameToUnixTimestamp { static constexpr auto name = "toUnixTimestamp"; }; struct NameToUnixTimestamp { static constexpr auto name = "toUnixTimestamp"; };
template <> template <>
struct ConvertImpl<DataTypeString, DataTypeUInt32, NameToUnixTimestamp> struct ConvertImpl<DataTypeString, DataTypeUInt32, NameToUnixTimestamp>
@ -488,8 +493,8 @@ struct ConvertImpl<DataTypeString, DataTypeUInt32, NameToUnixTimestamp>
/** If types are identical, just take reference to column. /** If types are identical, just take reference to column.
*/ */
template <typename Name> template <typename T, typename Name>
struct ConvertImpl<DataTypeString, DataTypeString, Name> struct ConvertImpl<typename std::enable_if<!T::is_parametric, T>::type, T, Name>
{ {
static void execute(Block & block, const ColumnNumbers & arguments, size_t result) static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
{ {
@ -566,7 +571,7 @@ struct ConvertImpl<DataTypeFixedString, DataTypeString, Name>
ColumnString::Offsets_t & offsets_to = col_to->getOffsets(); ColumnString::Offsets_t & offsets_to = col_to->getOffsets();
size_t size = col_from->size(); size_t size = col_from->size();
size_t n = col_from->getN(); size_t n = col_from->getN();
data_to.resize(size * (n + 1)); /// + 1 - zero terminator data_to.resize(size * (n + 1)); /// + 1 - zero terminator
offsets_to.resize(size); offsets_to.resize(size);
size_t offset_from = 0; size_t offset_from = 0;
@ -596,8 +601,26 @@ struct ConvertImpl<DataTypeFixedString, DataTypeString, Name>
/// Declared early because used below. /// Declared early because used below.
struct NameToDate { static constexpr auto name = "toDate"; }; struct NameToDate { static constexpr auto name = "toDate"; };
struct NameToString { static constexpr auto name = "toString"; }; struct NameToString { static constexpr auto name = "toString"; };
#define DEFINE_NAME_TO_INTERVAL(INTERVAL_KIND) \
struct NameToInterval ## INTERVAL_KIND \
{ \
static constexpr auto name = "toInterval" #INTERVAL_KIND; \
static constexpr auto kind = DataTypeInterval::INTERVAL_KIND; \
};
DEFINE_NAME_TO_INTERVAL(Second)
DEFINE_NAME_TO_INTERVAL(Minute)
DEFINE_NAME_TO_INTERVAL(Hour)
DEFINE_NAME_TO_INTERVAL(Day)
DEFINE_NAME_TO_INTERVAL(Week)
DEFINE_NAME_TO_INTERVAL(Month)
DEFINE_NAME_TO_INTERVAL(Year)
#undef DEFINE_NAME_TO_INTERVAL
template <typename ToDataType, typename Name, typename MonotonicityImpl> template <typename ToDataType, typename Name, typename MonotonicityImpl>
@ -707,9 +730,11 @@ private:
template <typename ToDataType2 = ToDataType, typename Name2 = Name> template <typename ToDataType2 = ToDataType, typename Name2 = Name>
DataTypePtr getReturnTypeInternal(const DataTypes & arguments, DataTypePtr getReturnTypeInternal(const DataTypes & arguments,
typename std::enable_if<!(std::is_same<ToDataType2, DataTypeString>::value || typename std::enable_if<!(
std::is_same<Name2, NameToUnixTimestamp>::value || std::is_same<ToDataType2, DataTypeString>::value
std::is_same<Name2, NameToDate>::value)>::type * = nullptr) const || std::is_same<ToDataType2, DataTypeInterval>::value
|| std::is_same<Name2, NameToUnixTimestamp>::value
|| std::is_same<Name2, NameToDate>::value)>::type * = nullptr) const
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
@ -791,6 +816,18 @@ private:
return std::make_shared<ToDataType2>(); return std::make_shared<ToDataType2>();
} }
template <typename ToDataType2 = ToDataType, typename Name2 = Name>
DataTypePtr getReturnTypeInternal(const DataTypes & arguments,
typename std::enable_if<std::is_same<ToDataType2, DataTypeInterval>::value>::type * = nullptr) const
{
if (arguments.size() != 1)
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
+ toString(arguments.size()) + ", should be 1.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
return std::make_shared<DataTypeInterval>(Name::kind);
}
}; };
@ -1066,36 +1103,39 @@ struct ToStringMonotonicity
} }
}; };
struct NameToUInt8 { static constexpr auto name = "toUInt8"; };
struct NameToUInt16 { static constexpr auto name = "toUInt16"; };
struct NameToUInt32 { static constexpr auto name = "toUInt32"; };
struct NameToUInt64 { static constexpr auto name = "toUInt64"; };
struct NameToInt8 { static constexpr auto name = "toInt8"; };
struct NameToInt16 { static constexpr auto name = "toInt16"; };
struct NameToInt32 { static constexpr auto name = "toInt32"; };
struct NameToInt64 { static constexpr auto name = "toInt64"; };
struct NameToFloat32 { static constexpr auto name = "toFloat32"; };
struct NameToFloat64 { static constexpr auto name = "toFloat64"; };
struct NameToDateTime { static constexpr auto name = "toDateTime"; };
struct NameToUUID { static constexpr auto name = "toUUID"; };
using FunctionToUInt8 = FunctionConvert<DataTypeUInt8, NameToUInt8, ToIntMonotonicity<UInt8>>; struct NameToUInt8 { static constexpr auto name = "toUInt8"; };
using FunctionToUInt16 = FunctionConvert<DataTypeUInt16, NameToUInt16, ToIntMonotonicity<UInt16>>; struct NameToUInt16 { static constexpr auto name = "toUInt16"; };
using FunctionToUInt32 = FunctionConvert<DataTypeUInt32, NameToUInt32, ToIntMonotonicity<UInt32>>; struct NameToUInt32 { static constexpr auto name = "toUInt32"; };
using FunctionToUInt64 = FunctionConvert<DataTypeUInt64, NameToUInt64, ToIntMonotonicity<UInt64>>; struct NameToUInt64 { static constexpr auto name = "toUInt64"; };
using FunctionToInt8 = FunctionConvert<DataTypeInt8, NameToInt8, ToIntMonotonicity<Int8>>; struct NameToInt8 { static constexpr auto name = "toInt8"; };
using FunctionToInt16 = FunctionConvert<DataTypeInt16, NameToInt16, ToIntMonotonicity<Int16>>; struct NameToInt16 { static constexpr auto name = "toInt16"; };
using FunctionToInt32 = FunctionConvert<DataTypeInt32, NameToInt32, ToIntMonotonicity<Int32>>; struct NameToInt32 { static constexpr auto name = "toInt32"; };
using FunctionToInt64 = FunctionConvert<DataTypeInt64, NameToInt64, ToIntMonotonicity<Int64>>; struct NameToInt64 { static constexpr auto name = "toInt64"; };
using FunctionToFloat32 = FunctionConvert<DataTypeFloat32, NameToFloat32, PositiveMonotonicity>; struct NameToFloat32 { static constexpr auto name = "toFloat32"; };
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, PositiveMonotonicity>; struct NameToFloat64 { static constexpr auto name = "toFloat64"; };
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToIntMonotonicity<UInt16>>; struct NameToDateTime { static constexpr auto name = "toDateTime"; };
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToIntMonotonicity<UInt32>>; struct NameToUUID { static constexpr auto name = "toUUID"; };
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToIntMonotonicity<UInt128>>;
using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>; using FunctionToUInt8 = FunctionConvert<DataTypeUInt8, NameToUInt8, ToIntMonotonicity<UInt8>>;
using FunctionToUnixTimestamp = FunctionConvert<DataTypeUInt32, NameToUnixTimestamp, ToIntMonotonicity<UInt32>>; using FunctionToUInt16 = FunctionConvert<DataTypeUInt16, NameToUInt16, ToIntMonotonicity<UInt16>>;
using FunctionToUInt32 = FunctionConvert<DataTypeUInt32, NameToUInt32, ToIntMonotonicity<UInt32>>;
using FunctionToUInt64 = FunctionConvert<DataTypeUInt64, NameToUInt64, ToIntMonotonicity<UInt64>>;
using FunctionToInt8 = FunctionConvert<DataTypeInt8, NameToInt8, ToIntMonotonicity<Int8>>;
using FunctionToInt16 = FunctionConvert<DataTypeInt16, NameToInt16, ToIntMonotonicity<Int16>>;
using FunctionToInt32 = FunctionConvert<DataTypeInt32, NameToInt32, ToIntMonotonicity<Int32>>;
using FunctionToInt64 = FunctionConvert<DataTypeInt64, NameToInt64, ToIntMonotonicity<Int64>>;
using FunctionToFloat32 = FunctionConvert<DataTypeFloat32, NameToFloat32, PositiveMonotonicity>;
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, PositiveMonotonicity>;
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToIntMonotonicity<UInt16>>;
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToIntMonotonicity<UInt32>>;
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToIntMonotonicity<UInt128>>;
using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>;
using FunctionToUnixTimestamp = FunctionConvert<DataTypeUInt32, NameToUnixTimestamp, ToIntMonotonicity<UInt32>>;
template <typename DataType> struct FunctionTo; template <typename DataType> struct FunctionTo;
template <> struct FunctionTo<DataTypeUInt8> { using Type = FunctionToUInt8; }; template <> struct FunctionTo<DataTypeUInt8> { using Type = FunctionToUInt8; };
template <> struct FunctionTo<DataTypeUInt16> { using Type = FunctionToUInt16; }; template <> struct FunctionTo<DataTypeUInt16> { using Type = FunctionToUInt16; };
template <> struct FunctionTo<DataTypeUInt32> { using Type = FunctionToUInt32; }; template <> struct FunctionTo<DataTypeUInt32> { using Type = FunctionToUInt32; };
@ -1111,32 +1151,33 @@ template <> struct FunctionTo<DataTypeDateTime> { using Type = FunctionToDateTim
template <> struct FunctionTo<DataTypeUUID> { using Type = FunctionToUUID; }; template <> struct FunctionTo<DataTypeUUID> { using Type = FunctionToUUID; };
template <> struct FunctionTo<DataTypeString> { using Type = FunctionToString; }; template <> struct FunctionTo<DataTypeString> { using Type = FunctionToString; };
template <> struct FunctionTo<DataTypeFixedString> { using Type = FunctionToFixedString; }; template <> struct FunctionTo<DataTypeFixedString> { using Type = FunctionToFixedString; };
template <typename FieldType> struct FunctionTo<DataTypeEnum<FieldType>> template <typename FieldType> struct FunctionTo<DataTypeEnum<FieldType>>
: FunctionTo<DataTypeNumber<FieldType>> : FunctionTo<DataTypeNumber<FieldType>>
{ {
}; };
struct NameToUInt8OrZero { static constexpr auto name = "toUInt8OrZero"; }; struct NameToUInt8OrZero { static constexpr auto name = "toUInt8OrZero"; };
struct NameToUInt16OrZero { static constexpr auto name = "toUInt16OrZero"; }; struct NameToUInt16OrZero { static constexpr auto name = "toUInt16OrZero"; };
struct NameToUInt32OrZero { static constexpr auto name = "toUInt32OrZero"; }; struct NameToUInt32OrZero { static constexpr auto name = "toUInt32OrZero"; };
struct NameToUInt64OrZero { static constexpr auto name = "toUInt64OrZero"; }; struct NameToUInt64OrZero { static constexpr auto name = "toUInt64OrZero"; };
struct NameToInt8OrZero { static constexpr auto name = "toInt8OrZero"; }; struct NameToInt8OrZero { static constexpr auto name = "toInt8OrZero"; };
struct NameToInt16OrZero { static constexpr auto name = "toInt16OrZero"; }; struct NameToInt16OrZero { static constexpr auto name = "toInt16OrZero"; };
struct NameToInt32OrZero { static constexpr auto name = "toInt32OrZero"; }; struct NameToInt32OrZero { static constexpr auto name = "toInt32OrZero"; };
struct NameToInt64OrZero { static constexpr auto name = "toInt64OrZero"; }; struct NameToInt64OrZero { static constexpr auto name = "toInt64OrZero"; };
struct NameToFloat32OrZero { static constexpr auto name = "toFloat32OrZero"; }; struct NameToFloat32OrZero { static constexpr auto name = "toFloat32OrZero"; };
struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; }; struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; };
using FunctionToUInt8OrZero = FunctionConvertOrZero<DataTypeUInt8, NameToUInt8OrZero>; using FunctionToUInt8OrZero = FunctionConvertOrZero<DataTypeUInt8, NameToUInt8OrZero>;
using FunctionToUInt16OrZero = FunctionConvertOrZero<DataTypeUInt16, NameToUInt16OrZero>; using FunctionToUInt16OrZero = FunctionConvertOrZero<DataTypeUInt16, NameToUInt16OrZero>;
using FunctionToUInt32OrZero = FunctionConvertOrZero<DataTypeUInt32, NameToUInt32OrZero>; using FunctionToUInt32OrZero = FunctionConvertOrZero<DataTypeUInt32, NameToUInt32OrZero>;
using FunctionToUInt64OrZero = FunctionConvertOrZero<DataTypeUInt64, NameToUInt64OrZero>; using FunctionToUInt64OrZero = FunctionConvertOrZero<DataTypeUInt64, NameToUInt64OrZero>;
using FunctionToInt8OrZero = FunctionConvertOrZero<DataTypeInt8, NameToInt8OrZero>; using FunctionToInt8OrZero = FunctionConvertOrZero<DataTypeInt8, NameToInt8OrZero>;
using FunctionToInt16OrZero = FunctionConvertOrZero<DataTypeInt16, NameToInt16OrZero>; using FunctionToInt16OrZero = FunctionConvertOrZero<DataTypeInt16, NameToInt16OrZero>;
using FunctionToInt32OrZero = FunctionConvertOrZero<DataTypeInt32, NameToInt32OrZero>; using FunctionToInt32OrZero = FunctionConvertOrZero<DataTypeInt32, NameToInt32OrZero>;
using FunctionToInt64OrZero = FunctionConvertOrZero<DataTypeInt64, NameToInt64OrZero>; using FunctionToInt64OrZero = FunctionConvertOrZero<DataTypeInt64, NameToInt64OrZero>;
using FunctionToFloat32OrZero = FunctionConvertOrZero<DataTypeFloat32, NameToFloat32OrZero>; using FunctionToFloat32OrZero = FunctionConvertOrZero<DataTypeFloat32, NameToFloat32OrZero>;
using FunctionToFloat64OrZero = FunctionConvertOrZero<DataTypeFloat64, NameToFloat64OrZero>; using FunctionToFloat64OrZero = FunctionConvertOrZero<DataTypeFloat64, NameToFloat64OrZero>;
class FunctionCast final : public IFunction class FunctionCast final : public IFunction

View File

@ -37,6 +37,22 @@ void registerFunctionsDateTime(FunctionFactory & factory)
factory.registerFunction<FunctionToYYYYMM>(); factory.registerFunction<FunctionToYYYYMM>();
factory.registerFunction<FunctionToYYYYMMDD>(); factory.registerFunction<FunctionToYYYYMMDD>();
factory.registerFunction<FunctionToYYYYMMDDhhmmss>(); factory.registerFunction<FunctionToYYYYMMDDhhmmss>();
factory.registerFunction<FunctionAddSeconds>();
factory.registerFunction<FunctionAddMinutes>();
factory.registerFunction<FunctionAddHours>();
factory.registerFunction<FunctionAddDays>();
factory.registerFunction<FunctionAddWeeks>();
factory.registerFunction<FunctionAddMonths>();
factory.registerFunction<FunctionAddYears>();
factory.registerFunction<FunctionSubtractSeconds>();
factory.registerFunction<FunctionSubtractMinutes>();
factory.registerFunction<FunctionSubtractHours>();
factory.registerFunction<FunctionSubtractDays>();
factory.registerFunction<FunctionSubtractWeeks>();
factory.registerFunction<FunctionSubtractMonths>();
factory.registerFunction<FunctionSubtractYears>();
} }
} }

View File

@ -85,6 +85,8 @@ struct ZeroTransform
struct ToDateImpl struct ToDateImpl
{ {
static constexpr auto name = "toDate";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return UInt16(time_zone.toDayNum(t)); return UInt16(time_zone.toDayNum(t));
@ -99,6 +101,8 @@ struct ToDateImpl
struct ToStartOfDayImpl struct ToStartOfDayImpl
{ {
static constexpr auto name = "toStartOfDay";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toDate(t); return time_zone.toDate(t);
@ -113,6 +117,8 @@ struct ToStartOfDayImpl
struct ToMondayImpl struct ToMondayImpl
{ {
static constexpr auto name = "toMonday";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t)); return time_zone.toFirstDayNumOfWeek(time_zone.toDayNum(t));
@ -127,6 +133,8 @@ struct ToMondayImpl
struct ToStartOfMonthImpl struct ToStartOfMonthImpl
{ {
static constexpr auto name = "toStartOfMonth";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toFirstDayNumOfMonth(time_zone.toDayNum(t)); return time_zone.toFirstDayNumOfMonth(time_zone.toDayNum(t));
@ -141,6 +149,8 @@ struct ToStartOfMonthImpl
struct ToStartOfQuarterImpl struct ToStartOfQuarterImpl
{ {
static constexpr auto name = "toStartOfQuarter";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toFirstDayNumOfQuarter(time_zone.toDayNum(t)); return time_zone.toFirstDayNumOfQuarter(time_zone.toDayNum(t));
@ -155,6 +165,8 @@ struct ToStartOfQuarterImpl
struct ToStartOfYearImpl struct ToStartOfYearImpl
{ {
static constexpr auto name = "toStartOfYear";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toFirstDayNumOfYear(time_zone.toDayNum(t)); return time_zone.toFirstDayNumOfYear(time_zone.toDayNum(t));
@ -170,6 +182,8 @@ struct ToStartOfYearImpl
struct ToTimeImpl struct ToTimeImpl
{ {
static constexpr auto name = "toTime";
/// When transforming to time, the date will be equated to 1970-01-02. /// When transforming to time, the date will be equated to 1970-01-02.
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
@ -186,9 +200,11 @@ struct ToTimeImpl
struct ToStartOfMinuteImpl struct ToStartOfMinuteImpl
{ {
static constexpr auto name = "toStartOfMinute";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toStartOfMinuteInaccurate(t); return time_zone.toStartOfMinute(t);
} }
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
@ -200,9 +216,11 @@ struct ToStartOfMinuteImpl
struct ToStartOfFiveMinuteImpl struct ToStartOfFiveMinuteImpl
{ {
static constexpr auto name = "toStartOfFiveMinute";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toStartOfFiveMinuteInaccurate(t); return time_zone.toStartOfFiveMinute(t);
} }
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
@ -214,10 +232,13 @@ struct ToStartOfFiveMinuteImpl
struct ToStartOfHourImpl struct ToStartOfHourImpl
{ {
static constexpr auto name = "toStartOfHour";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toStartOfHourInaccurate(t); return time_zone.toStartOfHour(t);
} }
static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
throw Exception("Illegal type Date of argument for function toStartOfHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); throw Exception("Illegal type Date of argument for function toStartOfHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -228,6 +249,8 @@ struct ToStartOfHourImpl
struct ToYearImpl struct ToYearImpl
{ {
static constexpr auto name = "toYear";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toYear(t); return time_zone.toYear(t);
@ -242,6 +265,8 @@ struct ToYearImpl
struct ToMonthImpl struct ToMonthImpl
{ {
static constexpr auto name = "toMonth";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toMonth(t); return time_zone.toMonth(t);
@ -256,6 +281,8 @@ struct ToMonthImpl
struct ToDayOfMonthImpl struct ToDayOfMonthImpl
{ {
static constexpr auto name = "toDayOfMonth";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfMonth(t); return time_zone.toDayOfMonth(t);
@ -270,6 +297,8 @@ struct ToDayOfMonthImpl
struct ToDayOfWeekImpl struct ToDayOfWeekImpl
{ {
static constexpr auto name = "toDayOfWeek";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayOfWeek(t); return time_zone.toDayOfWeek(t);
@ -284,10 +313,13 @@ struct ToDayOfWeekImpl
struct ToHourImpl struct ToHourImpl
{ {
static constexpr auto name = "toHour";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toHour(t); return time_zone.toHour(t);
} }
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
throw Exception("Illegal type Date of argument for function toHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); throw Exception("Illegal type Date of argument for function toHour", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -298,9 +330,11 @@ struct ToHourImpl
struct ToMinuteImpl struct ToMinuteImpl
{ {
static constexpr auto name = "toMinute";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toMinuteInaccurate(t); return time_zone.toMinute(t);
} }
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
@ -312,9 +346,11 @@ struct ToMinuteImpl
struct ToSecondImpl struct ToSecondImpl
{ {
static constexpr auto name = "toSecond";
static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toSecondInaccurate(t); return time_zone.toSecond(t);
} }
static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone) static inline UInt8 execute(UInt16 d, const DateLUTImpl & time_zone)
{ {
@ -326,6 +362,8 @@ struct ToSecondImpl
struct ToRelativeYearNumImpl struct ToRelativeYearNumImpl
{ {
static constexpr auto name = "toRelativeYearNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toYear(t); return time_zone.toYear(t);
@ -340,6 +378,8 @@ struct ToRelativeYearNumImpl
struct ToRelativeMonthNumImpl struct ToRelativeMonthNumImpl
{ {
static constexpr auto name = "toRelativeMonthNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toRelativeMonthNum(t); return time_zone.toRelativeMonthNum(t);
@ -354,6 +394,8 @@ struct ToRelativeMonthNumImpl
struct ToRelativeWeekNumImpl struct ToRelativeWeekNumImpl
{ {
static constexpr auto name = "toRelativeWeekNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toRelativeWeekNum(t); return time_zone.toRelativeWeekNum(t);
@ -368,6 +410,8 @@ struct ToRelativeWeekNumImpl
struct ToRelativeDayNumImpl struct ToRelativeDayNumImpl
{ {
static constexpr auto name = "toRelativeDayNum";
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toDayNum(t); return time_zone.toDayNum(t);
@ -383,6 +427,8 @@ struct ToRelativeDayNumImpl
struct ToRelativeHourNumImpl struct ToRelativeHourNumImpl
{ {
static constexpr auto name = "toRelativeHourNum";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toRelativeHourNum(t); return time_zone.toRelativeHourNum(t);
@ -397,6 +443,8 @@ struct ToRelativeHourNumImpl
struct ToRelativeMinuteNumImpl struct ToRelativeMinuteNumImpl
{ {
static constexpr auto name = "toRelativeMinuteNum";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toRelativeMinuteNum(t); return time_zone.toRelativeMinuteNum(t);
@ -411,6 +459,8 @@ struct ToRelativeMinuteNumImpl
struct ToRelativeSecondNumImpl struct ToRelativeSecondNumImpl
{ {
static constexpr auto name = "toRelativeSecondNum";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return t; return t;
@ -425,6 +475,8 @@ struct ToRelativeSecondNumImpl
struct ToYYYYMMImpl struct ToYYYYMMImpl
{ {
static constexpr auto name = "toYYYYMM";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toNumYYYYMM(t); return time_zone.toNumYYYYMM(t);
@ -439,6 +491,8 @@ struct ToYYYYMMImpl
struct ToYYYYMMDDImpl struct ToYYYYMMDDImpl
{ {
static constexpr auto name = "toYYYYMMDD";
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toNumYYYYMMDD(t); return time_zone.toNumYYYYMMDD(t);
@ -453,6 +507,8 @@ struct ToYYYYMMDDImpl
struct ToYYYYMMDDhhmmssImpl struct ToYYYYMMDDhhmmssImpl
{ {
static constexpr auto name = "toYYYYMMDDhhmmss";
static inline UInt64 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt64 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toNumYYYYMMDDhhmmss(t); return time_zone.toNumYYYYMMDDhhmmss(t);
@ -477,24 +533,16 @@ struct Transformer
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
vec_to[i] = Transform::execute(vec_from[i], time_zone); vec_to[i] = Transform::execute(vec_from[i], time_zone);
} }
static void constant(const FromType & from, ToType & to, const DateLUTImpl & time_zone)
{
to = Transform::execute(from, time_zone);
}
}; };
template <typename FromType, typename ToType, typename Transform, typename Name> template <typename FromType, typename ToType, typename Transform>
struct DateTimeTransformImpl struct DateTimeTransformImpl
{ {
static void execute(Block & block, const ColumnNumbers & arguments, size_t result) static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
{ {
using Op = Transformer<FromType, ToType, Transform>; using Op = Transformer<FromType, ToType, Transform>;
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get());
const ColumnConst * time_zone_column = nullptr; const ColumnConst * time_zone_column = nullptr;
if (arguments.size() == 2) if (arguments.size() == 2)
@ -503,7 +551,7 @@ struct DateTimeTransformImpl
if (!time_zone_column) if (!time_zone_column)
throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName() throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName()
+ " of second (time zone) argument of function " + Name::name + ", must be constant string", + " of second (time zone) argument of function " + Transform::name + ", must be constant string",
ErrorCodes::ILLEGAL_COLUMN); ErrorCodes::ILLEGAL_COLUMN);
} }
@ -511,7 +559,8 @@ struct DateTimeTransformImpl
? DateLUT::instance(time_zone_column->getValue<String>()) ? DateLUT::instance(time_zone_column->getValue<String>())
: DateLUT::instance(); : DateLUT::instance();
if (sources) const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
{ {
auto col_to = std::make_shared<ColumnVector<ToType>>(); auto col_to = std::make_shared<ColumnVector<ToType>>();
block.getByPosition(result).column = col_to; block.getByPosition(result).column = col_to;
@ -520,18 +569,18 @@ struct DateTimeTransformImpl
else else
{ {
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
+ " of first argument of function " + Name::name, + " of first argument of function " + Transform::name,
ErrorCodes::ILLEGAL_COLUMN); ErrorCodes::ILLEGAL_COLUMN);
} }
} }
}; };
template <typename ToDataType, typename Transform, typename Name> template <typename ToDataType, typename Transform>
class FunctionDateOrDateTimeToSomething : public IFunction class FunctionDateOrDateTimeToSomething : public IFunction
{ {
public: public:
static constexpr auto name = Name::name; static constexpr auto name = Transform::name;
static FunctionPtr create(const Context & context) { return std::make_shared<FunctionDateOrDateTimeToSomething>(); }; static FunctionPtr create(const Context & context) { return std::make_shared<FunctionDateOrDateTimeToSomething>(); };
String getName() const override String getName() const override
@ -576,12 +625,12 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{ {
IDataType * from_type = block.getByPosition(arguments[0]).type.get(); const IDataType * from_type = block.getByPosition(arguments[0]).type.get();
if (checkDataType<DataTypeDate>(from_type)) if (checkDataType<DataTypeDate>(from_type))
DateTimeTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform, Name>::execute(block, arguments, result); DateTimeTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform>::execute(block, arguments, result);
else if (checkDataType<DataTypeDateTime>(from_type)) else if (checkDataType<DataTypeDateTime>(from_type))
DateTimeTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform, Name>::execute(block, arguments, result); DateTimeTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform>::execute(block, arguments, result);
else else
throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(), throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -628,6 +677,296 @@ public:
}; };
struct AddSecondsImpl
{
static constexpr auto name = "addSeconds";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return t + delta;
}
static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum_t(d)) + delta;
}
};
struct AddMinutesImpl
{
static constexpr auto name = "addMinutes";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return t + delta * 60;
}
static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum_t(d)) + delta * 60;
}
};
struct AddHoursImpl
{
static constexpr auto name = "addHours";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return t + delta * 3600;
}
static inline UInt32 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.fromDayNum(DayNum_t(d)) + delta * 3600;
}
};
struct AddDaysImpl
{
static constexpr auto name = "addDays";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addDays(t, delta);
}
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return d + delta;
}
};
struct AddWeeksImpl
{
static constexpr auto name = "addWeeks";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addWeeks(t, delta);
}
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return d + delta * 7;
}
};
struct AddMonthsImpl
{
static constexpr auto name = "addMonths";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addMonths(t, delta);
}
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addMonths(DayNum_t(d), delta);
}
};
struct AddYearsImpl
{
static constexpr auto name = "addYears";
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addYears(t, delta);
}
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return time_zone.addYears(DayNum_t(d), delta);
}
};
template <typename Transform>
struct SubtractIntervalImpl
{
static inline UInt32 execute(UInt32 t, Int64 delta, const DateLUTImpl & time_zone)
{
return Transform::execute(t, -delta, time_zone);
}
static inline UInt16 execute(UInt16 d, Int64 delta, const DateLUTImpl & time_zone)
{
return Transform::execute(d, -delta, time_zone);
}
};
struct SubtractSecondsImpl : SubtractIntervalImpl<AddSecondsImpl> { static constexpr auto name = "subtractSeconds"; };
struct SubtractMinutesImpl : SubtractIntervalImpl<AddMinutesImpl> { static constexpr auto name = "subtractMinutes"; };
struct SubtractHoursImpl : SubtractIntervalImpl<AddHoursImpl> { static constexpr auto name = "subtractHours"; };
struct SubtractDaysImpl : SubtractIntervalImpl<AddDaysImpl> { static constexpr auto name = "subtractDays"; };
struct SubtractWeeksImpl : SubtractIntervalImpl<AddWeeksImpl> { static constexpr auto name = "subtractWeeks"; };
struct SubtractMonthsImpl : SubtractIntervalImpl<AddMonthsImpl> { static constexpr auto name = "subtractMonths"; };
struct SubtractYearsImpl : SubtractIntervalImpl<AddYearsImpl> { static constexpr auto name = "subtractYears"; };
template <typename FromType, typename ToType, typename Transform>
struct Adder
{
static void vector_vector(const PaddedPODArray<FromType> & vec_from, PaddedPODArray<ToType> & vec_to, const IColumn & delta, const DateLUTImpl & time_zone)
{
size_t size = vec_from.size();
vec_to.resize(size);
for (size_t i = 0; i < size; ++i)
vec_to[i] = Transform::execute(vec_from[i], delta.getInt(i), time_zone);
}
static void vector_constant(const PaddedPODArray<FromType> & vec_from, PaddedPODArray<ToType> & vec_to, Int64 delta, const DateLUTImpl & time_zone)
{
size_t size = vec_from.size();
vec_to.resize(size);
for (size_t i = 0; i < size; ++i)
vec_to[i] = Transform::execute(vec_from[i], delta, time_zone);
}
static void constant_vector(const FromType & from, PaddedPODArray<ToType> & vec_to, const IColumn & delta, const DateLUTImpl & time_zone)
{
size_t size = delta.size();
vec_to.resize(size);
for (size_t i = 0; i < size; ++i)
vec_to[i] = Transform::execute(from, delta.getInt(i), time_zone);
}
};
template <typename FromType, typename Transform>
struct DateTimeAddIntervalImpl
{
static void execute(Block & block, const ColumnNumbers & arguments, size_t result)
{
using ToType = decltype(Transform::execute(FromType(), 0, std::declval<DateLUTImpl>()));
using Op = Adder<FromType, ToType, Transform>;
const ColumnConst * time_zone_column = nullptr;
if (arguments.size() == 3)
{
time_zone_column = checkAndGetColumnConst<ColumnString>(block.getByPosition(arguments[2]).column.get());
if (!time_zone_column)
throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName()
+ " of second (time zone) argument of function " + Transform::name + ", must be constant string",
ErrorCodes::ILLEGAL_COLUMN);
}
const DateLUTImpl & time_zone = time_zone_column
? DateLUT::instance(time_zone_column->getValue<String>())
: DateLUT::instance();
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
{
auto col_to = std::make_shared<ColumnVector<ToType>>();
block.getByPosition(result).column = col_to;
const IColumn & delta_column = *block.getByPosition(arguments[1]).column;
if (const auto * delta_const_column = typeid_cast<const ColumnConst *>(&delta_column))
Op::vector_constant(sources->getData(), col_to->getData(), delta_const_column->getValue<Int64>(), time_zone);
else
Op::vector_vector(sources->getData(), col_to->getData(), delta_column, time_zone);
}
else if (const auto * sources = checkAndGetColumnConst<ColumnVector<FromType>>(source_col.get()))
{
auto col_to = std::make_shared<ColumnVector<ToType>>();
block.getByPosition(result).column = col_to;
Op::constant_vector(sources->template getValue<FromType>(), col_to->getData(), *block.getByPosition(arguments[1]).column, time_zone);
}
else
{
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName()
+ " of first argument of function " + Transform::name,
ErrorCodes::ILLEGAL_COLUMN);
}
}
};
template <typename Transform>
class FunctionDateOrDateTimeAddInterval : public IFunction
{
public:
static constexpr auto name = Transform::name;
static FunctionPtr create(const Context & context) { return std::make_shared<FunctionDateOrDateTimeAddInterval>(); };
String getName() const override
{
return name;
}
bool isVariadic() const override { return true; }
size_t getNumberOfArguments() const override { return 0; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (arguments.size() != 2 && arguments.size() != 3)
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
+ toString(arguments.size()) + ", should be 2 or 3",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
if (!arguments[1]->behavesAsNumber())
throw Exception("Second argument for function " + getName() + " (delta) must be number",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
if (arguments.size() == 2)
{
if (!checkDataType<DataTypeDate>(arguments[0].get())
&& !checkDataType<DataTypeDateTime>(arguments[0].get()))
throw Exception{
"Illegal type " + arguments[0]->getName() + " of argument of function " + getName() +
". Should be a date or a date with time", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
}
else
{
if (!checkDataType<DataTypeDateTime>(arguments[0].get())
|| !checkDataType<DataTypeString>(arguments[1].get()))
throw Exception{
"Function " + getName() + " supports 2 or 3 arguments. The 1st argument "
"must be of type Date or DateTime. The 2nd argument must be number. "
"The 3rd argument (optional) must be "
"a constant string with timezone name. The timezone argument is allowed "
"only when the 1st argument has the type DateTime",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
}
if (checkDataType<DataTypeDate>(arguments[0].get()))
return std::make_shared<typename std::conditional<std::is_same<
decltype(Transform::execute(DataTypeDate::FieldType(), 0, std::declval<DateLUTImpl>())), UInt16>::value,
DataTypeDate, DataTypeDateTime>::type>();
else
return std::make_shared<typename std::conditional<std::is_same<
decltype(Transform::execute(DataTypeDateTime::FieldType(), 0, std::declval<DateLUTImpl>())), UInt16>::value,
DataTypeDate, DataTypeDateTime>::type>();
}
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {2}; }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{
const IDataType * from_type = block.getByPosition(arguments[0]).type.get();
if (checkDataType<DataTypeDate>(from_type))
DateTimeAddIntervalImpl<DataTypeDate::FieldType, Transform>::execute(block, arguments, result);
else if (checkDataType<DataTypeDateTime>(from_type))
DateTimeAddIntervalImpl<DataTypeDateTime::FieldType, Transform>::execute(block, arguments, result);
else
throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
};
/// Get the current time. (It is a constant, it is evaluated once for the entire query.) /// Get the current time. (It is a constant, it is evaluated once for the entire query.)
class FunctionNow : public IFunction class FunctionNow : public IFunction
{ {
@ -906,62 +1245,50 @@ public:
}; };
struct NameToYear { static constexpr auto name = "toYear"; }; using FunctionToYear = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToYearImpl>;
struct NameToMonth { static constexpr auto name = "toMonth"; }; using FunctionToMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMonthImpl>;
struct NameToDayOfMonth { static constexpr auto name = "toDayOfMonth"; }; using FunctionToDayOfMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfMonthImpl>;
struct NameToDayOfWeek { static constexpr auto name = "toDayOfWeek"; }; using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfWeekImpl>;
struct NameToHour { static constexpr auto name = "toHour"; }; using FunctionToHour = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToHourImpl>;
struct NameToMinute { static constexpr auto name = "toMinute"; }; using FunctionToMinute = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMinuteImpl>;
struct NameToSecond { static constexpr auto name = "toSecond"; }; using FunctionToSecond = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToSecondImpl>;
struct NameToStartOfDay { static constexpr auto name = "toStartOfDay"; }; using FunctionToStartOfDay = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfDayImpl>;
struct NameToMonday { static constexpr auto name = "toMonday"; }; using FunctionToMonday = FunctionDateOrDateTimeToSomething<DataTypeDate, ToMondayImpl>;
struct NameToStartOfMonth { static constexpr auto name = "toStartOfMonth"; }; using FunctionToStartOfMonth = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfMonthImpl>;
struct NameToStartOfQuarter { static constexpr auto name = "toStartOfQuarter"; }; using FunctionToStartOfQuarter = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfQuarterImpl>;
struct NameToStartOfYear { static constexpr auto name = "toStartOfYear"; }; using FunctionToStartOfYear = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfYearImpl>;
struct NameToStartOfMinute { static constexpr auto name = "toStartOfMinute"; }; using FunctionToStartOfMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfMinuteImpl>;
struct NameToStartOfFiveMinute { static constexpr auto name = "toStartOfFiveMinute"; }; using FunctionToStartOfFiveMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfFiveMinuteImpl>;
struct NameToStartOfHour { static constexpr auto name = "toStartOfHour"; }; using FunctionToStartOfHour = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfHourImpl>;
struct NameToTime { static constexpr auto name = "toTime"; }; using FunctionToTime = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToTimeImpl>;
struct NameToRelativeYearNum { static constexpr auto name = "toRelativeYearNum"; };
struct NameToRelativeMonthNum { static constexpr auto name = "toRelativeMonthNum"; };
struct NameToRelativeWeekNum { static constexpr auto name = "toRelativeWeekNum"; };
struct NameToRelativeDayNum { static constexpr auto name = "toRelativeDayNum"; };
struct NameToRelativeHourNum { static constexpr auto name = "toRelativeHourNum"; };
struct NameToRelativeMinuteNum { static constexpr auto name = "toRelativeMinuteNum"; };
struct NameToRelativeSecondNum { static constexpr auto name = "toRelativeSecondNum"; };
struct NameToYYYYMM { static constexpr auto name = "toYYYYMM"; };
struct NameToYYYYMMDD { static constexpr auto name = "toYYYYMMDD"; };
struct NameToYYYYMMDDhhmmss { static constexpr auto name = "toYYYYMMDDhhmmss"; };
using FunctionToRelativeYearNum = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToRelativeYearNumImpl>;
using FunctionToRelativeMonthNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMonthNumImpl>;
using FunctionToRelativeWeekNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeWeekNumImpl>;
using FunctionToRelativeDayNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeDayNumImpl>;
using FunctionToYear = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToYearImpl, NameToYear>; using FunctionToRelativeHourNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeHourNumImpl>;
using FunctionToMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMonthImpl, NameToMonth>; using FunctionToRelativeMinuteNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMinuteNumImpl>;
using FunctionToDayOfMonth = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfMonthImpl, NameToDayOfMonth>; using FunctionToRelativeSecondNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeSecondNumImpl>;
using FunctionToDayOfWeek = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToDayOfWeekImpl, NameToDayOfWeek>;
using FunctionToHour = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToHourImpl, NameToHour>;
using FunctionToMinute = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToMinuteImpl, NameToMinute>;
using FunctionToSecond = FunctionDateOrDateTimeToSomething<DataTypeUInt8, ToSecondImpl, NameToSecond>;
using FunctionToStartOfDay = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfDayImpl, NameToStartOfDay>;
using FunctionToMonday = FunctionDateOrDateTimeToSomething<DataTypeDate, ToMondayImpl, NameToMonday>;
using FunctionToStartOfMonth = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfMonthImpl, NameToStartOfMonth>;
using FunctionToStartOfQuarter = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfQuarterImpl, NameToStartOfQuarter>;
using FunctionToStartOfYear = FunctionDateOrDateTimeToSomething<DataTypeDate, ToStartOfYearImpl, NameToStartOfYear>;
using FunctionToStartOfMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfMinuteImpl, NameToStartOfMinute>;
using FunctionToStartOfFiveMinute = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfFiveMinuteImpl, NameToStartOfFiveMinute>;
using FunctionToStartOfHour = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToStartOfHourImpl, NameToStartOfHour>;
using FunctionToTime = FunctionDateOrDateTimeToSomething<DataTypeDateTime, ToTimeImpl, NameToTime>;
using FunctionToRelativeYearNum = FunctionDateOrDateTimeToSomething<DataTypeUInt16, ToRelativeYearNumImpl, NameToRelativeYearNum>; using FunctionToYYYYMM = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMImpl>;
using FunctionToRelativeMonthNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMonthNumImpl, NameToRelativeMonthNum>; using FunctionToYYYYMMDD = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMDDImpl>;
using FunctionToRelativeWeekNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeWeekNumImpl, NameToRelativeWeekNum>; using FunctionToYYYYMMDDhhmmss = FunctionDateOrDateTimeToSomething<DataTypeUInt64, ToYYYYMMDDhhmmssImpl>;
using FunctionToRelativeDayNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeDayNumImpl, NameToRelativeDayNum>;
using FunctionToRelativeHourNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeHourNumImpl, NameToRelativeHourNum>; using FunctionAddSeconds = FunctionDateOrDateTimeAddInterval<AddSecondsImpl>;
using FunctionToRelativeMinuteNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeMinuteNumImpl, NameToRelativeMinuteNum>; using FunctionAddMinutes = FunctionDateOrDateTimeAddInterval<AddMinutesImpl>;
using FunctionToRelativeSecondNum = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToRelativeSecondNumImpl, NameToRelativeSecondNum>; using FunctionAddHours = FunctionDateOrDateTimeAddInterval<AddHoursImpl>;
using FunctionAddDays = FunctionDateOrDateTimeAddInterval<AddDaysImpl>;
using FunctionAddWeeks = FunctionDateOrDateTimeAddInterval<AddWeeksImpl>;
using FunctionAddMonths = FunctionDateOrDateTimeAddInterval<AddMonthsImpl>;
using FunctionAddYears = FunctionDateOrDateTimeAddInterval<AddYearsImpl>;
using FunctionToYYYYMM = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMImpl, NameToYYYYMM>; using FunctionSubtractSeconds = FunctionDateOrDateTimeAddInterval<SubtractSecondsImpl>;
using FunctionToYYYYMMDD = FunctionDateOrDateTimeToSomething<DataTypeUInt32, ToYYYYMMDDImpl, NameToYYYYMMDD>; using FunctionSubtractMinutes = FunctionDateOrDateTimeAddInterval<SubtractMinutesImpl>;
using FunctionToYYYYMMDDhhmmss = FunctionDateOrDateTimeToSomething<DataTypeUInt64, ToYYYYMMDDhhmmssImpl, NameToYYYYMMDDhhmmss>; using FunctionSubtractHours = FunctionDateOrDateTimeAddInterval<SubtractHoursImpl>;
using FunctionSubtractDays = FunctionDateOrDateTimeAddInterval<SubtractDaysImpl>;
using FunctionSubtractWeeks = FunctionDateOrDateTimeAddInterval<SubtractWeeksImpl>;
using FunctionSubtractMonths = FunctionDateOrDateTimeAddInterval<SubtractMonthsImpl>;
using FunctionSubtractYears = FunctionDateOrDateTimeAddInterval<SubtractYearsImpl>;
} }

View File

@ -15,6 +15,7 @@
#include <DataTypes/DataTypeString.h> #include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypeTuple.h> #include <DataTypes/DataTypeTuple.h>
#include <DataTypes/DataTypesNumber.h> #include <DataTypes/DataTypesNumber.h>
#include <DataTypes/DataTypeEnum.h>
#include <Functions/FunctionFactory.h> #include <Functions/FunctionFactory.h>
#include <Interpreters/Cluster.h> #include <Interpreters/Cluster.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
@ -215,6 +216,51 @@ public:
}; };
/// Returns number of fields in Enum data type of passed value.
class FunctionGetSizeOfEnumType : public IFunction
{
public:
static constexpr auto name = "getSizeOfEnumType";
static FunctionPtr create(const Context & context)
{
return std::make_shared<FunctionGetSizeOfEnumType>();
}
String getName() const override
{
return name;
}
bool useDefaultImplementationForNulls() const override { return false; }
size_t getNumberOfArguments() const override
{
return 1;
}
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (checkDataType<DataTypeEnum8>(arguments[0].get()))
return std::make_shared<DataTypeUInt8>();
else if (checkDataType<DataTypeEnum16>(arguments[0].get()))
return std::make_shared<DataTypeUInt16>();
throw Exception("The argument for function " + getName() + " must be Enum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{
if (auto type = checkAndGetDataType<DataTypeEnum8>(block.getByPosition(arguments[0]).type.get()))
block.getByPosition(result).column = DataTypeUInt8().createConstColumn(block.rows(), UInt64(type->getValues().size()));
else if (auto type = checkAndGetDataType<DataTypeEnum16>(block.getByPosition(arguments[0]).type.get()))
block.getByPosition(result).column = DataTypeUInt16().createConstColumn(block.rows(), UInt64(type->getValues().size()));
else
throw Exception("The argument for function " + getName() + " must be Enum", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
};
/// Returns name of IColumn instance. /// Returns name of IColumn instance.
class FunctionToColumnTypeName : public IFunction class FunctionToColumnTypeName : public IFunction
{ {
@ -1733,6 +1779,7 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory)
factory.registerFunction<FunctionHostName>(); factory.registerFunction<FunctionHostName>();
factory.registerFunction<FunctionVisibleWidth>(); factory.registerFunction<FunctionVisibleWidth>();
factory.registerFunction<FunctionToTypeName>(); factory.registerFunction<FunctionToTypeName>();
factory.registerFunction<FunctionGetSizeOfEnumType>();
factory.registerFunction<FunctionToColumnTypeName>(); factory.registerFunction<FunctionToColumnTypeName>();
factory.registerFunction<FunctionDefaultValueOfArgumentType>(); factory.registerFunction<FunctionDefaultValueOfArgumentType>();
factory.registerFunction<FunctionBlockSize>(); factory.registerFunction<FunctionBlockSize>();

View File

@ -3,8 +3,5 @@ include_directories (${CMAKE_CURRENT_BINARY_DIR})
add_executable (number_traits number_traits.cpp) add_executable (number_traits number_traits.cpp)
target_link_libraries (number_traits dbms) target_link_libraries (number_traits dbms)
add_executable (functions_arithmetic functions_arithmetic.cpp)
target_link_libraries (functions_arithmetic dbms clickhouse_functions)
add_executable (logical_functions_performance logical_functions_performance.cpp) add_executable (logical_functions_performance logical_functions_performance.cpp)
target_link_libraries (logical_functions_performance dbms) target_link_libraries (logical_functions_performance dbms)

View File

@ -1,83 +0,0 @@
#include <iostream>
#include <iomanip>
#include <Common/Stopwatch.h>
#include <DataTypes/DataTypesNumber.h>
#include <Columns/ColumnsNumber.h>
#include <Functions/FunctionsArithmetic.h>
int main(int argc, char ** argv)
try
{
using namespace DB;
size_t n = atoi(argv[1]);
ColumnWithTypeAndName descr1;
auto col1 = std::make_shared<ColumnUInt8>();
descr1.type = std::make_shared<DataTypeUInt8>();
descr1.column = col1;
descr1.name = "x";
col1->getData().resize(n);
ColumnWithTypeAndName descr2;
auto col2 = std::make_shared<ColumnInt16>();
descr2.type = std::make_shared<DataTypeInt16>();
descr2.column = col2;
descr2.name = "x";
Block block;
block.insert(descr1);
block.insert(descr2);
col2->getData().resize(n);
for (size_t i = 0; i < n; ++i)
{
col1->getData()[i] = 10;
col2->getData()[i] = 3;
}
FunctionDivideFloating f;
DataTypes arg_types;
arg_types.push_back(descr1.type);
arg_types.push_back(descr2.type);
ColumnNumbers arg_nums;
arg_nums.push_back(0);
arg_nums.push_back(1);
DataTypePtr res_type = f.getReturnType(arg_types);
ColumnWithTypeAndName descr_res;
descr_res.type = res_type;
descr_res.name = "z";
{
Stopwatch stopwatch;
stopwatch.start();
size_t res_num = 2;
f.execute(block, arg_nums, res_num);
stopwatch.stop();
std::cout << std::fixed << std::setprecision(2)
<< "Elapsed " << stopwatch.elapsedSeconds() << " sec."
<< ", " << n / stopwatch.elapsedSeconds() << " rows/sec."
<< std::endl;
}
Float64 x = 0;
for (size_t i = 0; i < n; ++i)
x += get<Float64>((*block.getByPosition(2).column)[i]);
std::cout << x << std::endl;
return 0;
}
catch (const DB::Exception & e)
{
std::cerr << e.displayText() << std::endl;
throw;
}

View File

@ -563,8 +563,8 @@ inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTI
s[9] += values.day_of_month % 10; s[9] += values.day_of_month % 10;
UInt8 hour = date_lut.toHour(datetime); UInt8 hour = date_lut.toHour(datetime);
UInt8 minute = date_lut.toMinuteInaccurate(datetime); UInt8 minute = date_lut.toMinute(datetime);
UInt8 second = date_lut.toSecondInaccurate(datetime); UInt8 second = date_lut.toSecond(datetime);
s[11] += hour / 10; s[11] += hour / 10;
s[12] += hour % 10; s[12] += hour % 10;

View File

@ -5,17 +5,23 @@
#include <DataStreams/LazyBlockInputStream.h> #include <DataStreams/LazyBlockInputStream.h>
#include <Storages/StorageReplicatedMergeTree.h> #include <Storages/StorageReplicatedMergeTree.h>
#include <Common/Exception.h> #include <Common/Exception.h>
#include <Common/ProfileEvents.h>
#include <common/logger_useful.h> #include <common/logger_useful.h>
namespace ProfileEvents
{
extern const Event DistributedConnectionMissingTable;
extern const Event DistributedConnectionStaleReplica;
}
namespace DB namespace DB
{ {
namespace ErrorCodes namespace ErrorCodes
{ {
extern const int ALL_REPLICAS_ARE_STALE;
extern const int ALL_REPLICAS_ARE_STALE;
} }
namespace ClusterProxy namespace ClusterProxy
@ -72,6 +78,7 @@ void SelectStreamFactory::createForShard(
StoragePtr main_table_storage = context.tryGetTable(main_table.database, main_table.table); StoragePtr main_table_storage = context.tryGetTable(main_table.database, main_table.table);
if (!main_table_storage) /// Table is absent on a local server. if (!main_table_storage) /// Table is absent on a local server.
{ {
ProfileEvents::increment(ProfileEvents::DistributedConnectionMissingTable);
if (shard_info.pool) if (shard_info.pool)
{ {
LOG_WARNING( LOG_WARNING(
@ -117,6 +124,10 @@ void SelectStreamFactory::createForShard(
} }
/// If we reached this point, local replica is stale. /// If we reached this point, local replica is stale.
ProfileEvents::increment(ProfileEvents::DistributedConnectionStaleReplica);
LOG_WARNING(
&Logger::get("ClusterProxy::SelectStreamFactory"),
"Local replica of shard " << shard_info.shard_num << " is stale (delay: " << local_delay << "s.)");
if (!settings.fallback_to_stale_replicas_for_distributed_queries) if (!settings.fallback_to_stale_replicas_for_distributed_queries)
{ {
@ -128,9 +139,9 @@ void SelectStreamFactory::createForShard(
} }
else else
throw Exception( throw Exception(
"Local replica for shard " + toString(shard_info.shard_num) "Local replica of shard " + toString(shard_info.shard_num)
+ " is stale (delay: " + toString(local_delay) + "), but no other replica configured.", + " is stale (delay: " + toString(local_delay) + "s.), but no other replica configured",
ErrorCodes::ALL_REPLICAS_ARE_STALE); ErrorCodes::ALL_REPLICAS_ARE_STALE);
} }
if (!shard_info.pool) if (!shard_info.pool)
@ -144,13 +155,25 @@ void SelectStreamFactory::createForShard(
/// Do it lazily to avoid connecting in the main thread. /// Do it lazily to avoid connecting in the main thread.
auto lazily_create_stream = [ auto lazily_create_stream = [
pool = shard_info.pool, query, query_ast, context, throttler, pool = shard_info.pool, shard_num = shard_info.shard_num, query, query_ast, context, throttler,
main_table = main_table, external_tables = external_tables, stage = processed_stage, main_table = main_table, external_tables = external_tables, stage = processed_stage,
local_delay]() local_delay]()
-> BlockInputStreamPtr -> BlockInputStreamPtr
{ {
std::vector<ConnectionPoolWithFailover::TryResult> try_results = std::vector<ConnectionPoolWithFailover::TryResult> try_results;
pool->getManyChecked(&context.getSettingsRef(), PoolMode::GET_MANY, main_table); try
{
try_results = pool->getManyChecked(&context.getSettingsRef(), PoolMode::GET_MANY, main_table);
}
catch (const Exception & ex)
{
if (ex.code() == ErrorCodes::ALL_CONNECTION_TRIES_FAILED)
LOG_WARNING(
&Logger::get("ClusterProxy::SelectStreamFactory"),
"Connections to remote replicas of local shard " << shard_num << " failed, will use stale local replica");
else
throw;
}
double max_remote_delay = 0.0; double max_remote_delay = 0.0;
for (const auto & try_result : try_results) for (const auto & try_result : try_results)
@ -159,7 +182,7 @@ void SelectStreamFactory::createForShard(
max_remote_delay = std::max(try_result.staleness, max_remote_delay); max_remote_delay = std::max(try_result.staleness, max_remote_delay);
} }
if (local_delay < max_remote_delay) if (try_results.empty() || local_delay < max_remote_delay)
return createLocalStream(query_ast, context, stage); return createLocalStream(query_ast, context, stage);
else else
{ {

View File

@ -470,6 +470,16 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
String data_path = path + "data/" + database_name_escaped + "/"; String data_path = path + "data/" + database_name_escaped + "/";
String metadata_path = path + "metadata/" + database_name_escaped + "/" + table_name_escaped + ".sql"; String metadata_path = path + "metadata/" + database_name_escaped + "/" + table_name_escaped + ".sql";
// If this is a stub ATTACH query, read the query definition from the database
if (create.attach && !create.storage && !create.columns)
{
// Table SQL definition is available even if the table is detached
auto query = context.getCreateQuery(database_name, table_name);
auto & as_create = typeid_cast<const ASTCreateQuery &>(*query);
create = as_create; // Copy the saved create query, but use ATTACH instead of CREATE
create.attach = true;
}
std::unique_ptr<InterpreterSelectQuery> interpreter_select; std::unique_ptr<InterpreterSelectQuery> interpreter_select;
Block as_select_sample; Block as_select_sample;
/// For `view` type tables, you may need `sample_block` to get the columns. /// For `view` type tables, you may need `sample_block` to get the columns.

View File

@ -168,7 +168,8 @@ protected:
if (!as_table.empty()) if (!as_table.empty())
{ {
settings.ostr << (settings.hilite ? hilite_keyword : "") << " AS " << (settings.hilite ? hilite_none : "") std::string what = (!is_materialized_view ? " AS " : " TO ");
settings.ostr << (settings.hilite ? hilite_keyword : "") << what << (settings.hilite ? hilite_none : "")
<< (!as_database.empty() ? backQuoteIfNeed(as_database) + "." : "") << backQuoteIfNeed(as_table); << (!as_database.empty() ? backQuoteIfNeed(as_database) + "." : "") << backQuoteIfNeed(as_table);
} }

View File

@ -607,4 +607,58 @@ bool ParserNullityChecking::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
} }
bool ParserIntervalOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Pos begin = pos;
/// If no INTERVAL keyword, go to nested parser.
if (!ParserKeyword("INTERVAL").ignore(pos, expected))
return next_parser.parse(pos, node, expected);
ASTPtr expr;
/// Any expression can be inside, because operator surrounds it.
if (!ParserExpressionWithOptionalAlias(false).parse(pos, expr, expected))
return false;
const char * function_name = nullptr;
if (ParserKeyword("SECOND").ignore(pos, expected))
function_name = "toIntervalSecond";
else if (ParserKeyword("MINUTE").ignore(pos, expected))
function_name = "toIntervalMinute";
else if (ParserKeyword("HOUR").ignore(pos, expected))
function_name = "toIntervalHour";
else if (ParserKeyword("DAY").ignore(pos, expected))
function_name = "toIntervalDay";
else if (ParserKeyword("WEEK").ignore(pos, expected))
function_name = "toIntervalWeek";
else if (ParserKeyword("MONTH").ignore(pos, expected))
function_name = "toIntervalMonth";
else if (ParserKeyword("YEAR").ignore(pos, expected))
function_name = "toIntervalYear";
else
return false;
/// the function corresponding to the operator
auto function = std::make_shared<ASTFunction>();
/// function arguments
auto exp_list = std::make_shared<ASTExpressionList>();
/// the first argument of the function is the previous element, the second is the next one
function->range.first = begin->begin;
function->range.second = pos->begin;
function->name = function_name;
function->arguments = exp_list;
function->children.push_back(exp_list);
exp_list->children.push_back(expr);
exp_list->range.first = begin->begin;
exp_list->range.second = pos->begin;
node = function;
return true;
}
} }

View File

@ -164,11 +164,22 @@ protected:
}; };
/// Optional conversion to INTERVAL data type. Example: "INTERVAL x SECOND" parsed as "toIntervalSecond(x)".
class ParserIntervalOperatorExpression : public IParserBase
{
protected:
ParserMultiplicativeExpression next_parser;
const char * getName() const { return "INTERVAL operator expression"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected);
};
class ParserAdditiveExpression : public IParserBase class ParserAdditiveExpression : public IParserBase
{ {
private: private:
static const char * operators[]; static const char * operators[];
ParserLeftAssociativeBinaryOperatorList operator_parser {operators, std::make_unique<ParserMultiplicativeExpression>()}; ParserLeftAssociativeBinaryOperatorList operator_parser {operators, std::make_unique<ParserIntervalOperatorExpression>()};
protected: protected:
const char * getName() const { return "additive expression"; } const char * getName() const { return "additive expression"; }
@ -323,6 +334,7 @@ protected:
} }
}; };
class ParserExpressionInCastExpression : public IParserBase class ParserExpressionInCastExpression : public IParserBase
{ {
public: public:
@ -344,7 +356,7 @@ class ParserExpressionList : public IParserBase
{ {
public: public:
ParserExpressionList(bool allow_alias_without_as_keyword_, bool prefer_alias_to_column_name_ = false) ParserExpressionList(bool allow_alias_without_as_keyword_, bool prefer_alias_to_column_name_ = false)
: allow_alias_without_as_keyword(allow_alias_without_as_keyword_), prefer_alias_to_column_name(prefer_alias_to_column_name_) {} : allow_alias_without_as_keyword(allow_alias_without_as_keyword_), prefer_alias_to_column_name(prefer_alias_to_column_name_) {}
protected: protected:
bool allow_alias_without_as_keyword; bool allow_alias_without_as_keyword;
@ -359,7 +371,7 @@ class ParserNotEmptyExpressionList : public IParserBase
{ {
public: public:
ParserNotEmptyExpressionList(bool allow_alias_without_as_keyword, bool prefer_alias_to_column_name = false) ParserNotEmptyExpressionList(bool allow_alias_without_as_keyword, bool prefer_alias_to_column_name = false)
: nested_parser(allow_alias_without_as_keyword, prefer_alias_to_column_name) {} : nested_parser(allow_alias_without_as_keyword, prefer_alias_to_column_name) {}
private: private:
ParserExpressionList nested_parser; ParserExpressionList nested_parser;
protected: protected:

View File

@ -219,6 +219,7 @@ bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
bool is_materialized_view = false; bool is_materialized_view = false;
bool is_populate = false; bool is_populate = false;
bool is_temporary = false; bool is_temporary = false;
bool to_table = false;
if (!s_create.ignore(pos, expected)) if (!s_create.ignore(pos, expected))
{ {
@ -254,6 +255,23 @@ bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
return false; return false;
} }
// Shortcut for ATTACH a previously detached table
if (attach && (!pos.isValid() || pos.get().type == TokenType::Semicolon))
{
auto query = std::make_shared<ASTCreateQuery>(StringRange(begin, pos));
node = query;
query->attach = attach;
query->if_not_exists = if_not_exists;
if (database)
query->database = typeid_cast<ASTIdentifier &>(*database).name;
if (table)
query->table = typeid_cast<ASTIdentifier &>(*table).name;
return true;
}
/// List of columns. /// List of columns.
if (s_lparen.ignore(pos, expected)) if (s_lparen.ignore(pos, expected))
{ {
@ -341,6 +359,22 @@ bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
return false; return false;
} }
// TO [db.]table
if (ParserKeyword{"TO"}.ignore(pos, expected))
{
to_table = true;
if (!name_p.parse(pos, as_table, expected))
return false;
if (s_dot.ignore(pos, expected))
{
as_database = as_table;
if (!name_p.parse(pos, as_table, expected))
return false;
}
}
/// Optional - a list of columns can be specified. It must fully comply with SELECT. /// Optional - a list of columns can be specified. It must fully comply with SELECT.
if (s_lparen.ignore(pos, expected)) if (s_lparen.ignore(pos, expected))
{ {
@ -351,7 +385,7 @@ bool ParserCreateQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
return false; return false;
} }
if (is_materialized_view) if (is_materialized_view && !to_table)
{ {
/// Internal ENGINE for MATERIALIZED VIEW must be specified. /// Internal ENGINE for MATERIALIZED VIEW must be specified.
if (!storage_p.parse(pos, storage, expected)) if (!storage_p.parse(pos, storage, expected))

View File

@ -214,7 +214,7 @@ protected:
* CREATE|ATTACH DATABASE db [ENGINE = engine] * CREATE|ATTACH DATABASE db [ENGINE = engine]
* *
* Or: * Or:
* CREATE|ATTACH [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ... * CREATE|ATTACH [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO [db.]name] [ENGINE = engine] [POPULATE] AS SELECT ...
*/ */
class ParserCreateQuery : public IParserBase class ParserCreateQuery : public IParserBase
{ {

View File

@ -70,8 +70,8 @@ StorageMaterializedView::StorageMaterializedView(
if (!query.select) if (!query.select)
throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY); throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY);
if (!query.storage) if (!query.storage && query.as_table.empty())
throw Exception("ENGINE of MaterializedView must be specified explicitly", ErrorCodes::INCORRECT_QUERY); throw Exception("ENGINE of MaterializedView should be specified explicitly", ErrorCodes::INCORRECT_QUERY);
extractDependentTable(*query.select, select_database_name, select_table_name); extractDependentTable(*query.select, select_database_name, select_table_name);
@ -80,16 +80,28 @@ StorageMaterializedView::StorageMaterializedView(
DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(select_database_name, select_table_name),
DatabaseAndTableName(database_name, table_name)); DatabaseAndTableName(database_name, table_name));
String inner_table_name = getInnerTableName(); // If the destination table is not set, use inner table
if (!query.storage)
{
target_database_name = query.as_database;
target_table_name = query.as_table;
}
else
{
target_database_name = database_name;
target_table_name = ".inner." + table_name;
has_inner_table = true;
}
inner_query = query.select->ptr(); inner_query = query.select->ptr();
/// If there is an ATTACH request, then the internal table must already be connected. /// If there is an ATTACH request, then the internal table must already be connected.
if (!attach_) if (!attach_ && has_inner_table)
{ {
/// We will create a query to create an internal table. /// We will create a query to create an internal table.
auto manual_create_query = std::make_shared<ASTCreateQuery>(); auto manual_create_query = std::make_shared<ASTCreateQuery>();
manual_create_query->database = database_name; manual_create_query->database = target_database_name;
manual_create_query->table = inner_table_name; manual_create_query->table = target_table_name;
manual_create_query->set(manual_create_query->columns, query.columns->ptr()); manual_create_query->set(manual_create_query->columns, query.columns->ptr());
manual_create_query->set(manual_create_query->storage, query.storage->ptr()); manual_create_query->set(manual_create_query->storage, query.storage->ptr());
@ -114,12 +126,12 @@ StorageMaterializedView::StorageMaterializedView(
NameAndTypePair StorageMaterializedView::getColumn(const String & column_name) const NameAndTypePair StorageMaterializedView::getColumn(const String & column_name) const
{ {
return getInnerTable()->getColumn(column_name); return getTargetTable()->getColumn(column_name);
} }
bool StorageMaterializedView::hasColumn(const String & column_name) const bool StorageMaterializedView::hasColumn(const String & column_name) const
{ {
return getInnerTable()->hasColumn(column_name); return getTargetTable()->hasColumn(column_name);
} }
BlockInputStreams StorageMaterializedView::read( BlockInputStreams StorageMaterializedView::read(
@ -130,12 +142,12 @@ BlockInputStreams StorageMaterializedView::read(
const size_t max_block_size, const size_t max_block_size,
const unsigned num_streams) const unsigned num_streams)
{ {
return getInnerTable()->read(column_names, query_info, context, processed_stage, max_block_size, num_streams); return getTargetTable()->read(column_names, query_info, context, processed_stage, max_block_size, num_streams);
} }
BlockOutputStreamPtr StorageMaterializedView::write(const ASTPtr & query, const Settings & settings) BlockOutputStreamPtr StorageMaterializedView::write(const ASTPtr & query, const Settings & settings)
{ {
return getInnerTable()->write(query, settings); return getTargetTable()->write(query, settings);
} }
void StorageMaterializedView::drop() void StorageMaterializedView::drop()
@ -144,14 +156,12 @@ void StorageMaterializedView::drop()
DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(select_database_name, select_table_name),
DatabaseAndTableName(database_name, table_name)); DatabaseAndTableName(database_name, table_name));
auto inner_table_name = getInnerTableName(); if (has_inner_table && global_context.tryGetTable(target_database_name, target_table_name))
if (global_context.tryGetTable(database_name, inner_table_name))
{ {
/// We create and execute `drop` query for internal table. /// We create and execute `drop` query for internal table.
auto drop_query = std::make_shared<ASTDropQuery>(); auto drop_query = std::make_shared<ASTDropQuery>();
drop_query->database = database_name; drop_query->database = target_database_name;
drop_query->table = inner_table_name; drop_query->table = target_table_name;
ASTPtr ast_drop_query = drop_query; ASTPtr ast_drop_query = drop_query;
InterpreterDropQuery drop_interpreter(ast_drop_query, global_context); InterpreterDropQuery drop_interpreter(ast_drop_query, global_context);
drop_interpreter.execute(); drop_interpreter.execute();
@ -160,12 +170,12 @@ void StorageMaterializedView::drop()
bool StorageMaterializedView::optimize(const ASTPtr & query, const ASTPtr & partition, bool final, bool deduplicate, const Context & context) bool StorageMaterializedView::optimize(const ASTPtr & query, const ASTPtr & partition, bool final, bool deduplicate, const Context & context)
{ {
return getInnerTable()->optimize(query, partition, final, deduplicate, context); return getTargetTable()->optimize(query, partition, final, deduplicate, context);
} }
StoragePtr StorageMaterializedView::getInnerTable() const StoragePtr StorageMaterializedView::getTargetTable() const
{ {
return global_context.getTable(database_name, getInnerTableName()); return global_context.getTable(target_database_name, target_table_name);
} }
} }

View File

@ -20,18 +20,17 @@ public:
std::string getName() const override { return "MaterializedView"; } std::string getName() const override { return "MaterializedView"; }
std::string getTableName() const override { return table_name; } std::string getTableName() const override { return table_name; }
const NamesAndTypesList & getColumnsListImpl() const override { return *columns; } const NamesAndTypesList & getColumnsListImpl() const override { return *columns; }
std::string getInnerTableName() const { return ".inner." + table_name; }
ASTPtr getInnerQuery() const { return inner_query->clone(); }; ASTPtr getInnerQuery() const { return inner_query->clone(); };
StoragePtr getInnerTable() const; StoragePtr getTargetTable() const;
NameAndTypePair getColumn(const String & column_name) const override; NameAndTypePair getColumn(const String & column_name) const override;
bool hasColumn(const String & column_name) const override; bool hasColumn(const String & column_name) const override;
bool supportsSampling() const override { return getInnerTable()->supportsSampling(); } bool supportsSampling() const override { return getTargetTable()->supportsSampling(); }
bool supportsPrewhere() const override { return getInnerTable()->supportsPrewhere(); } bool supportsPrewhere() const override { return getTargetTable()->supportsPrewhere(); }
bool supportsFinal() const override { return getInnerTable()->supportsFinal(); } bool supportsFinal() const override { return getTargetTable()->supportsFinal(); }
bool supportsParallelReplicas() const override { return getInnerTable()->supportsParallelReplicas(); } bool supportsParallelReplicas() const override { return getTargetTable()->supportsParallelReplicas(); }
bool supportsIndexForIn() const override { return getInnerTable()->supportsIndexForIn(); } bool supportsIndexForIn() const override { return getTargetTable()->supportsIndexForIn(); }
BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override; BlockOutputStreamPtr write(const ASTPtr & query, const Settings & settings) override;
void drop() override; void drop() override;
@ -48,11 +47,14 @@ public:
private: private:
String select_database_name; String select_database_name;
String select_table_name; String select_table_name;
String target_database_name;
String target_table_name;
String table_name; String table_name;
String database_name; String database_name;
ASTPtr inner_query; ASTPtr inner_query;
Context & global_context; Context & global_context;
NamesAndTypesListPtr columns; NamesAndTypesListPtr columns;
bool has_inner_table = false;
StorageMaterializedView( StorageMaterializedView(
const String & table_name_, const String & table_name_,

View File

@ -11,8 +11,8 @@ TEST(RangeFiltered, simple)
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
v.push_back(i); v.push_back(i);
auto v30 = createRangeFiltered([] (int i) { return i % 3 == 0;}, v); auto v30 = createRangeFiltered([] (int i) { return i % 3 == 0; }, v);
auto v31 = createRangeFiltered([] (int i) { return i % 3 != 0;}, v); auto v31 = createRangeFiltered([] (int i) { return i % 3 != 0; }, v);
for (const int & i : v30) for (const int & i : v30)
ASSERT_EQ(i % 3, 0); ASSERT_EQ(i % 3, 0);
@ -27,7 +27,6 @@ TEST(RangeFiltered, simple)
auto it2 = std::next(it); auto it2 = std::next(it);
ASSERT_EQ(*it2, 3); ASSERT_EQ(*it2, 3);
auto it3 = it;
it = std::next(it2); it = std::next(it2);
ASSERT_EQ(*it, 6); ASSERT_EQ(*it, 6);
} }

View File

@ -8,11 +8,12 @@ make -j24
sudo make install sudo make install
# Perform analysis # Perform analysis
# cd ClickHouse_clean/build
cd ClickHouse_clean/build
cppcheck -j24 --project=compile_commands.json --enable=all 2> cppcheck-errors.txt cppcheck -j24 --project=compile_commands.json --enable=all 2> cppcheck-errors.txt
# or
# cppcheck -j24 -i contrib -i build --enable=all . 2> cppcheck-errors.txt # or (from directory with sources)
# cppcheck -i contrib -i build --enable=all . 2> cppcheck-errors.txt
# Check is pretty fast. # Check is pretty fast.
# It gives many false positives. # It gives many false positives.

View File

@ -58,7 +58,7 @@ def test(started_cluster):
assert node_2_1.query("SELECT sum(x) FROM replicated").strip() == '' assert node_2_1.query("SELECT sum(x) FROM replicated").strip() == ''
assert node_2_2.query("SELECT sum(x) FROM replicated").strip() == '2' assert node_2_2.query("SELECT sum(x) FROM replicated").strip() == '2'
# With in_order balancing first replicas chosen. # With in_order balancing first replicas are chosen.
assert instance_with_dist_table.query( assert instance_with_dist_table.query(
"SELECT count() FROM distributed SETTINGS load_balancing='in_order'").strip() == '' "SELECT count() FROM distributed SETTINGS load_balancing='in_order'").strip() == ''
@ -89,3 +89,12 @@ SELECT count() FROM distributed SETTINGS
max_replica_delay_for_distributed_queries=1, max_replica_delay_for_distributed_queries=1,
fallback_to_stale_replicas_for_distributed_queries=0 fallback_to_stale_replicas_for_distributed_queries=0
''') ''')
# Now partition off the remote replica of the local shard and test that failover still works.
pm.partition_instances(node_1_1, node_1_2, port=9000)
assert instance_with_dist_table.query('''
SELECT sum(x) FROM distributed SETTINGS
load_balancing='in_order',
max_replica_delay_for_distributed_queries=1
''').strip() == '2'

View File

@ -0,0 +1,96 @@
<test>
<name>Functions for working with date and time</name>
<type>once</type>
<stop_conditions>
<any_of>
<average_speed_not_changing_for_ms>10000</average_speed_not_changing_for_ms>
<total_time_ms>1000</total_time_ms>
</any_of>
</stop_conditions>
<metrics>
<max_rows_per_second />
<max_bytes_per_second />
<avg_rows_per_second />
<avg_bytes_per_second />
</metrics>
<substitutions>
<substitution>
<name>datetime_transform</name>
<values>
<value>toSecond</value>
<value>toMinute</value>
<value>toHour</value>
<value>toDayOfWeek</value>
<value>toDayOfMonth</value>
<value>toMonth</value>
<value>toQuarter</value>
<value>toYear</value>
<value>toStartOfMinute</value>
<value>toStartOfFiveMinute</value>
<value>toStartOfHour</value>
<value>toStartOfDay</value>
<value>toDate</value>
<value>toMonday</value>
<value>toStartOfMonth</value>
<value>toStartOfQuarter</value>
<value>toYear</value>
<value>toTime</value>
<value>toRelativeYearNum</value>
<value>toRelativeMonthNum</value>
<value>toRelativeWeekNum</value>
<value>toRelativeDayNum</value>
<value>toRelativeHourNum</value>
<value>toRelativeMinuteNum</value>
<value>toRelativeSecondNum</value>
<value>toYYYYMM</value>
<value>toYYYYMMDD</value>
<value>toYYYYMMDDhhmmss</value>
</values>
</substitution>
<substitution>
<name>date_transform</name>
<values>
<value>toDayOfWeek</value>
<value>toDayOfMonth</value>
<value>toMonth</value>
<value>toQuarter</value>
<value>toYear</value>
<value>toStartOfDay</value>
<value>toDate</value>
<value>toMonday</value>
<value>toStartOfMonth</value>
<value>toStartOfQuarter</value>
<value>toYear</value>
<value>toRelativeYearNum</value>
<value>toRelativeMonthNum</value>
<value>toRelativeWeekNum</value>
<value>toRelativeDayNum</value>
<value>toYYYYMM</value>
<value>toYYYYMMDD</value>
<value>toYYYYMMDDhhmmss</value>
</values>
</substitution>
<substitution>
<name>time_zone</name>
<values>
<value>UTC</value>
<value>Europe/Moscow</value>
<value>Asia/Kolkata</value>
</values>
</substitution>
</substitutions>
<query>SELECT count() FROM system.numbers WHERE NOT ignore(toDateTime('2017-01-01 00:00:00') + number % 100000000 + rand() % 100000 AS t, {datetime_transform}(t, '{time_zone}'))</query>
<query>SELECT count() FROM system.numbers WHERE NOT ignore(toDate('2017-01-01') + number % 1000 + rand() % 10 AS t, {date_transform}(t))</query>
</test>

View File

@ -0,0 +1,41 @@
<test>
<name>set_lookup_random</name>
<type>once</type>
<stop_conditions>
<all_of>
<total_time_ms>10000</total_time_ms>
</all_of>
<any_of>
<average_speed_not_changing_for_ms>5000</average_speed_not_changing_for_ms>
<total_time_ms>20000</total_time_ms>
</any_of>
</stop_conditions>
<main_metric>
<avg_rows_per_second/>
</main_metric>
<substitutions>
<substitution>
<name>table</name>
<values>
<value>system.numbers</value>
<value>system.numbers_mt</value>
</values>
</substitution>
<substitution>
<name>size</name>
<values>
<value>1</value>
<value>16</value>
<value>1024</value>
<value>16384</value>
<value>1048576</value>
<value>10000000</value>
</values>
</substitution>
</substitutions>
<query>SELECT count() FROM {table} WHERE rand64() IN (SELECT number FROM system.numbers LIMIT {size})</query>
</test>

View File

@ -0,0 +1,25 @@
<test>
<name>set_lookup_hits</name>
<type>once</type>
<stop_conditions>
<all_of>
<total_time_ms>10000</total_time_ms>
</all_of>
<any_of>
<average_speed_not_changing_for_ms>5000</average_speed_not_changing_for_ms>
<total_time_ms>20000</total_time_ms>
</any_of>
</stop_conditions>
<main_metric>
<avg_rows_per_second/>
</main_metric>
<query>SELECT count() FROM hits_100m_single WHERE UserID IN (SELECT UserID FROM hits_100m_single WHERE AdvEngineID != 0)</query>
<query>SELECT count() FROM hits_100m_single WHERE UserID IN (SELECT UserID FROM hits_100m_single)</query>
<query>SELECT count() FROM hits_100m_single WHERE SearchPhrase IN (SELECT SearchPhrase FROM hits_100m_single)</query>
<query>SELECT count() FROM hits_100m_single WHERE URL IN (SELECT URL FROM hits_100m_single WHERE AdvEngineID != 0)</query>
<query>SELECT count() FROM hits_100m_single WHERE URL IN (SELECT URL FROM hits_100m_single WHERE SearchEngineID != 0)</query>
<query>SELECT count() FROM hits_100m_single WHERE RegionID IN (SELECT RegionID FROM hits_100m_single)</query>
</test>

View File

@ -8,21 +8,21 @@
2014-12-01 2014-12-01
2014-12-01 2014-12-01
2014-12-01 2014-12-01
2014-12-01
2014-12-01
2014-12-01
2014-12-01
2014-12-01
2014-07-01 2014-07-01
2014-07-01 2014-07-01
2014-07-01 2014-07-01
2014-10-01 2014-10-01
2014-07-01 2014-07-01
2014-01-01
2014-01-01
2014-01-01
2014-01-01
2014-01-01
1970-01-02 12:00:00 1970-01-02 12:00:00 1970-01-02 12:00:00 1970-01-02 12:00:00
1970-01-02 10:00:00 1970-01-02 11:00:00 1970-01-02 10:00:00 1970-01-02 11:00:00
1970-01-02 09:00:00 1970-01-02 10:00:00 1970-01-02 09:00:00 1970-01-02 10:00:00
1970-01-02 18:00:00 1970-01-02 18:00:00 1970-01-02 18:00:00 1970-01-02 18:00:00
1970-01-02 01:30:00 1970-01-02 01:30:00 1970-01-02 01:00:00 1970-01-02 01:00:00
2014 2014
2014 2014
2014 2014
@ -92,7 +92,6 @@
392251 392251
392251 392251
392251 392251
392251
23535110 23535110
23535110 23535110
23535110 23535110

View File

@ -24,20 +24,20 @@ SELECT toStartOfMonth(toDateTime(1419800400), 'Pacific/Pitcairn');
/* toStartOfQuarter */ /* toStartOfQuarter */
SELECT toStartOfMonth(toDateTime(1419800400), 'Europe/Moscow');
SELECT toStartOfMonth(toDateTime(1419800400), 'Europe/Paris');
SELECT toStartOfMonth(toDateTime(1419800400), 'Europe/London');
SELECT toStartOfMonth(toDateTime(1419800400), 'Asia/Tokyo');
SELECT toStartOfMonth(toDateTime(1419800400), 'Pacific/Pitcairn');
/* toStartOfYear */
SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/Moscow'); SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/Moscow');
SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/Paris'); SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/Paris');
SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/London'); SELECT toStartOfQuarter(toDateTime(1412106600), 'Europe/London');
SELECT toStartOfQuarter(toDateTime(1412106600), 'Asia/Tokyo'); SELECT toStartOfQuarter(toDateTime(1412106600), 'Asia/Tokyo');
SELECT toStartOfQuarter(toDateTime(1412106600), 'Pacific/Pitcairn'); SELECT toStartOfQuarter(toDateTime(1412106600), 'Pacific/Pitcairn');
/* toStartOfYear */
SELECT toStartOfYear(toDateTime(1419800400), 'Europe/Moscow');
SELECT toStartOfYear(toDateTime(1419800400), 'Europe/Paris');
SELECT toStartOfYear(toDateTime(1419800400), 'Europe/London');
SELECT toStartOfYear(toDateTime(1419800400), 'Asia/Tokyo');
SELECT toStartOfYear(toDateTime(1419800400), 'Pacific/Pitcairn');
/* toTime */ /* toTime */
SELECT toString(toTime(toDateTime(1420102800), 'Europe/Moscow'), 'Europe/Moscow'), toString(toTime(toDateTime(1428310800), 'Europe/Moscow'), 'Europe/Moscow'); SELECT toString(toTime(toDateTime(1420102800), 'Europe/Moscow'), 'Europe/Moscow'), toString(toTime(toDateTime(1428310800), 'Europe/Moscow'), 'Europe/Moscow');
@ -156,7 +156,7 @@ SELECT toRelativeHourNum(toDateTime(1412106600), 'Europe/Moscow') - toRelativeHo
SELECT toRelativeHourNum(toDateTime(1412106600), 'Europe/Paris') - toRelativeHourNum(toDateTime(0), 'Europe/Paris'); SELECT toRelativeHourNum(toDateTime(1412106600), 'Europe/Paris') - toRelativeHourNum(toDateTime(0), 'Europe/Paris');
SELECT toRelativeHourNum(toDateTime(1412106600), 'Europe/London') - toRelativeHourNum(toDateTime(0), 'Europe/London'); SELECT toRelativeHourNum(toDateTime(1412106600), 'Europe/London') - toRelativeHourNum(toDateTime(0), 'Europe/London');
SELECT toRelativeHourNum(toDateTime(1412106600), 'Asia/Tokyo') - toRelativeHourNum(toDateTime(0), 'Asia/Tokyo'); SELECT toRelativeHourNum(toDateTime(1412106600), 'Asia/Tokyo') - toRelativeHourNum(toDateTime(0), 'Asia/Tokyo');
SELECT toRelativeHourNum(toDateTime(1412106600), 'Pacific/Pitcairn') - toRelativeHourNum(toDateTime(0), 'Pacific/Pitcairn'); -- known wrong result: SELECT toRelativeHourNum(toDateTime(1412106600), 'Pacific/Pitcairn') - toRelativeHourNum(toDateTime(0), 'Pacific/Pitcairn');
/* toRelativeMinuteNum */ /* toRelativeMinuteNum */

View File

@ -61,104 +61,104 @@ FROM
( (
SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.00 SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.00
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.01 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.01
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.02 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.02
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.03 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.03
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.04 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.04
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.05 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.05
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.06 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.06
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.07 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.07
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.08 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.08
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.09 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.09
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.10 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.10
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.11 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.11
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.12 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.12
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.13 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.13
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.14 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.14
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.15 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.15
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.16 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.16
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.17 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.17
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.18 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.18
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.19 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.19
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.20 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.20
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.21 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.21
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.22 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.22
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.23 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.23
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.24 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.24
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.25 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.25
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.26 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.26
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.27 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.27
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.28 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.28
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.29 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.29
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.30 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.30
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.31 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.31
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.32 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.32
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.33 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.33
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.34 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.34
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.35 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.35
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.36 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.36
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.37 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.37
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.38 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.38
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.39 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.39
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.40 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.40
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.41 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.41
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.42 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.42
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.43 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.43
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.44 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.44
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.45 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.45
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.46 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.46
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.47 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.47
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.48 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.48
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.49 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.49
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.50 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.50
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.51 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.51
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.52 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.52
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.53 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.53
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.54 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.54
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.55 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.55
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.56 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.56
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.57 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.57
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.58 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.58
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.59 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.59
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.60 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.60
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.61 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.61
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.62 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.62
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.63 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.63
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.64 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.64
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.65 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.65
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.66 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.66
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.67 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.67
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.68 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.68
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.69 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.69
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.70 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.70
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.71 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.71
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.72 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.72
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.73 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.73
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.74 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.74
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.75 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.75
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.76 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.76
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.77 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.77
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.78 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.78
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.79 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.79
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.80 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.80
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.81 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.81
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.82 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.82
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.83 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.83
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.84 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.84
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.85 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.85
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.86 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.86
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.87 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.87
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.88 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.88
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.89 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.89
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.90 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.90
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.91 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.91
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.92 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.92
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.93 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.93
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.94 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.94
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.95 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.95
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.96 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.96
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.97 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.97
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.98 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.98
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.99 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.99
) )
GROUP BY x GROUP BY x
HAVING c = 1 HAVING c = 1
@ -182,104 +182,104 @@ FROM
( (
SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.00 SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.00
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.01 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.01
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.02 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.02
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.03 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.03
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.04 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.04
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.05 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.05
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.06 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.06
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.07 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.07
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.08 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.08
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.09 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.09
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.10 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.10
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.11 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.11
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.12 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.12
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.13 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.13
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.14 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.14
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.15 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.15
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.16 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.16
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.17 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.17
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.18 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.18
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.19 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.19
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.20 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.20
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.21 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.21
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.22 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.22
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.23 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.23
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.24 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.24
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.25 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.25
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.26 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.26
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.27 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.27
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.28 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.28
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.29 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.29
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.30 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.30
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.31 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.31
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.32 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.32
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.33 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.33
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.34 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.34
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.35 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.35
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.36 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.36
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.37 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.37
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.38 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.38
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.39 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.39
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.40 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.40
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.41 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.41
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.42 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.42
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.43 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.43
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.44 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.44
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.45 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.45
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.46 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.46
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.47 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.47
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.48 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.48
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.49 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.49
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.50 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.50
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.51 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.51
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.52 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.52
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.53 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.53
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.54 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.54
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.55 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.55
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.56 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.56
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.57 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.57
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.58 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.58
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.59 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.59
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.60 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.60
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.61 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.61
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.62 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.62
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.63 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.63
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.64 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.64
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.65 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.65
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.66 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.66
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.67 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.67
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.68 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.68
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.69 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.69
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.70 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.70
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.71 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.71
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.72 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.72
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.73 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.73
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.74 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.74
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.75 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.75
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.76 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.76
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.77 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.77
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.78 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.78
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.79 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.79
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.80 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.80
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.81 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.81
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.82 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.82
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.83 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.83
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.84 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.84
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.85 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.85
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.86 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.86
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.87 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.87
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.88 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.88
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.89 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.89
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.90 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.90
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.91 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.91
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.92 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.92
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.93 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.93
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.94 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.94
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.95 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.95
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.96 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.96
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.97 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.97
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.98 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.98
UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.99 UNION ALL SELECT * FROM test.sample SAMPLE 0.01 OFFSET 0.99
) )
GROUP BY x GROUP BY x
HAVING c = 1 HAVING c = 1

View File

@ -0,0 +1,4 @@
1
2
1
2

View File

@ -0,0 +1,23 @@
DROP TABLE IF EXISTS test.src;
DROP TABLE IF EXISTS test.dst;
DROP TABLE IF EXISTS test.mv;
CREATE TABLE test.src (x UInt8) ENGINE = Null;
CREATE TABLE test.dst (x UInt8) ENGINE = Memory();
CREATE MATERIALIZED VIEW test.mv TO test.dst AS SELECT * FROM test.src;
INSERT INTO test.src VALUES (1), (2);
-- Detach MV and see if the data is still readable
DETACH TABLE test.mv;
SELECT * FROM test.dst;
-- Reattach MV (shortcut)
ATTACH TABLE test.mv;
-- Drop the MV and see if the data is still readable
DROP TABLE test.mv;
SELECT * FROM test.dst;
DROP TABLE test.src;
DROP TABLE test.dst;

View File

@ -0,0 +1,2 @@
2
3

View File

@ -0,0 +1,2 @@
SELECT getSizeOfEnumType(CAST(1 AS Enum8('a' = 1, 'b' = 2)));
SELECT getSizeOfEnumType(CAST('b' AS Enum16('a' = 1, 'b' = 2, 'x' = 10)));

View File

@ -0,0 +1,3 @@
1990-10-19 00:00:00
1990-10-19 00:00:00
1990-10-19 00:00:00

View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
TZ=Europe/Moscow clickhouse-local --query="SELECT toDateTime('1990-10-19 00:00:00')" 2>/dev/null
TZ=Asia/Colombo clickhouse-local --query="SELECT toDateTime('1990-10-19 00:00:00')" 2>/dev/null
TZ=Asia/Kathmandu clickhouse-local --query="SELECT toDateTime('1990-10-19 00:00:00')" 2>/dev/null

View File

@ -0,0 +1,12 @@
2 2017-10-28 02:00:00
2 2017-10-28 02:00:00
2 2017-10-28 02:00:00
2 2017-10-28 02:00:00
2 2017-10-28 02:00:00
2 2017-10-28 02:00:00
3 2017-10-28 03:00:00
3 2017-10-28 03:00:00
3 2017-10-28 03:00:00
3 2017-10-28 03:00:00
3 2017-10-28 03:00:00
3 2017-10-28 03:00:00

View File

@ -0,0 +1 @@
WITH toDateTime(1509138000) + number * 300 AS t SELECT toHour(t, 'Asia/Kolkata') AS h, toString(toStartOfHour(t, 'Asia/Kolkata'), 'Asia/Kolkata') AS h_start FROM system.numbers LIMIT 12;

View File

@ -0,0 +1,38 @@
2016-11-30 08:18:19
2017-10-31 01:58:29
2017-10-31 08:18:19
2017-11-30 08:18:19
2017-12-31 08:18:19
2018-01-31 08:18:19
2018-02-28 08:18:19
2018-03-31 08:18:19
2018-04-30 08:18:19
2018-05-31 08:18:19
2018-06-30 08:18:19
2018-07-31 08:18:19
2018-08-31 08:18:19
2018-09-30 08:18:19
2018-10-31 08:18:19
2018-11-30 08:18:19
2018-12-31 08:18:19
2019-01-31 08:18:19
2019-02-28 08:18:19
2019-03-31 08:18:19
2019-04-30 08:18:19
2019-05-31 08:18:19
2016-02-29 01:02:03 2016-02-29 01:02:03
2017-02-28 01:02:03 2016-03-29 01:02:03
2018-02-28 01:02:03 2016-04-29 01:02:03
2019-02-28 01:02:03 2016-05-29 01:02:03
2020-02-29 01:02:03 2016-06-29 01:02:03
2021-02-28 01:02:03 2016-07-29 01:02:03
2022-02-28 01:02:03 2016-08-29 01:02:03
2023-02-28 01:02:03 2016-09-29 01:02:03
2024-02-29 01:02:03 2016-10-29 01:02:03
2025-02-28 01:02:03 2016-11-29 01:02:03
2026-02-28 01:02:03 2016-12-29 01:02:03
2027-02-28 01:02:03 2017-01-29 01:02:03
2028-02-29 01:02:03 2017-02-28 01:02:03
2029-02-28 01:02:03 2017-03-29 01:02:03
2030-02-28 01:02:03 2017-04-29 01:02:03
2031-02-28 01:02:03 2017-05-29 01:02:03

View File

@ -0,0 +1,4 @@
SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 DAY + INTERVAL 1 MONTH - INTERVAL 1 YEAR;
SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 HOUR + INTERVAL 1000 MINUTE + INTERVAL 10 SECOND;
SELECT toDateTime('2017-10-30 08:18:19') + INTERVAL 1 DAY + INTERVAL number MONTH FROM system.numbers LIMIT 20;
SELECT toDateTime('2016-02-29 01:02:03') + INTERVAL number YEAR, toDateTime('2016-02-29 01:02:03') + INTERVAL number MONTH FROM system.numbers LIMIT 16;

4
debian/changelog vendored
View File

@ -1,5 +1,5 @@
clickhouse (1.1.54300) unstable; urgency=low clickhouse (1.1.54306) unstable; urgency=low
* Modified source code * Modified source code
-- <robot-metrika-test@yandex-team.ru> Mon, 16 Oct 2017 13:49:50 +0300 -- <robot-metrika-test@yandex-team.ru> Sat, 28 Oct 2017 00:23:24 +0300

View File

@ -107,7 +107,7 @@ At the moment, ``ALTER`` queries for replicated tables are not supported yet.
CREATE VIEW CREATE VIEW
~~~~~~~~~~~ ~~~~~~~~~~~
``CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ...`` ``CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [TO [db.]name] [ENGINE = engine] [POPULATE] AS SELECT ...``
Creates a view. There are two types of views: normal and MATERIALIZED. Creates a view. There are two types of views: normal and MATERIALIZED.
@ -133,7 +133,7 @@ This query is fully equivalent to using the subquery:
Materialized views store data transformed by the corresponding SELECT query. Materialized views store data transformed by the corresponding SELECT query.
When creating a materialized view, you have to specify ENGINE - the table engine for storing data. When creating a materialized view, you have to either specify ENGINE - the table engine for storing data, or target table for materialized results. By default, it uses the same engine as for the table that the SELECT query is made from.
A materialized view is arranged as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view. A materialized view is arranged as follows: when inserting data to the table specified in SELECT, part of the inserted data is converted by this SELECT query, and the result is inserted in the view.
@ -142,6 +142,7 @@ If you specify POPULATE, the existing table data is inserted in the view when cr
The SELECT query can contain DISTINCT, GROUP BY, ORDER BY, LIMIT ... Note that the corresponding conversions are performed independently on each block of inserted data. For example, if GROUP BY is set, data is aggregated during insertion, but only within a single packet of inserted data. The data won't be further aggregated. The exception is when using an ENGINE that independently performs data aggregation, such as SummingMergeTree. The SELECT query can contain DISTINCT, GROUP BY, ORDER BY, LIMIT ... Note that the corresponding conversions are performed independently on each block of inserted data. For example, if GROUP BY is set, data is aggregated during insertion, but only within a single packet of inserted data. The data won't be further aggregated. The exception is when using an ENGINE that independently performs data aggregation, such as SummingMergeTree.
The execution of ALTER queries on materialized views has not been fully developed, so they might be inconvenient. The execution of ALTER queries on materialized views has not been fully developed, so they might be inconvenient.
If the materialized view uses a ``TO [db.]name`` to specify a target table, it is possible to DETACH the view, ALTER the target table, and ATTACH the view again.
Views look the same as normal tables. For example, they are listed in the result of the SHOW TABLES query. Views look the same as normal tables. For example, they are listed in the result of the SHOW TABLES query.
@ -154,6 +155,12 @@ The query is exactly the same as CREATE, except
- The query doesn't create data on the disk, but assumes that data is already in the appropriate places, and just adds information about the table to the server. - The query doesn't create data on the disk, but assumes that data is already in the appropriate places, and just adds information about the table to the server.
After executing an ATTACH query, the server will know about the existence of the table. After executing an ATTACH query, the server will know about the existence of the table.
If the table has been previously detached and it's structure is known, it's possible to use shorthand form and omit structure definition:
.. code-block:: sql
ATTACH TABLE [IF NOT EXISTS] [db.]name
This query is used when starting the server. The server stores table metadata as files with ATTACH queries, which it simply runs at launch (with the exception of system tables, which are explicitly created on the server). This query is used when starting the server. The server stores table metadata as files with ATTACH queries, which it simply runs at launch (with the exception of system tables, which are explicitly created on the server).
DROP DROP

View File

@ -1,21 +1,18 @@
#pragma once #pragma once
#include <common/Types.h> #include <common/Types.h>
#include <ext/singleton.h>
#include <common/likely.h> #include <common/likely.h>
#include <common/strong_typedef.h> #include <common/strong_typedef.h>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <ctime> #include <ctime>
#define DATE_LUT_MIN 0 #define DATE_LUT_MAX (0xFFFFFFFFU - 86400)
#define DATE_LUT_MAX (0x7FFFFFFF - 86400) #define DATE_LUT_MAX_DAY_NUM (0xFFFFFFFFU / 86400)
#define DATE_LUT_MAX_DAY_NUM (0x7FFFFFFF / 86400) /// Table size is bigger than DATE_LUT_MAX_DAY_NUM to fill all indices within UInt16 range: this allows to remove extra check.
#define DATE_LUT_SIZE 0x10000
#define DATE_LUT_MIN_YEAR 1970 #define DATE_LUT_MIN_YEAR 1970
#define DATE_LUT_MAX_YEAR 2037 /// Last supported year #define DATE_LUT_MAX_YEAR 2105 /// Last supported year
#define DATE_LUT_YEARS 68 /// Number of years in lookup table #define DATE_LUT_YEARS (1 + DATE_LUT_MAX_YEAR - DATE_LUT_MIN_YEAR) /// Number of years in lookup table
STRONG_TYPEDEF(UInt16, DayNum_t); STRONG_TYPEDEF(UInt16, DayNum_t);
@ -33,9 +30,9 @@ public:
struct Values struct Values
{ {
/// Least significat 32 bits from time_t at beginning of the day. /// Least significat 32 bits from time_t at beginning of the day.
/// Signedness is important to support 1970-01-01 MSK, where time_t == -10800. /// If the unix timestamp of beginning of the day is negative (example: 1970-01-01 MSK, where time_t == -10800), then value is zero.
/// Change to time_t; change constants above; and recompile the sources if you need to support time after 2038 year. /// Change to time_t; change constants above; and recompile the sources if you need to support time after 2105 year.
Int32 date; UInt32 date;
/// Properties of the day. /// Properties of the day.
UInt16 year; UInt16 year;
@ -43,6 +40,10 @@ public:
UInt8 day_of_month; UInt8 day_of_month;
UInt8 day_of_week; UInt8 day_of_week;
/// Total number of days in current month. Actually we can use separate table that is independent of time zone.
/// But due to alignment, this field is totally zero cost.
UInt8 days_in_month;
/// For days, when offset from UTC was changed due to daylight saving time or permanent change, following values could be non zero. /// For days, when offset from UTC was changed due to daylight saving time or permanent change, following values could be non zero.
UInt16 time_at_offset_change; /// In seconds from beginning of the day. Assuming offset never changed close to the end of day (so, value < 65536). UInt16 time_at_offset_change; /// In seconds from beginning of the day. Assuming offset never changed close to the end of day (so, value < 65536).
Int16 amount_of_offset_change; /// Usually -3600 or 3600, but look at Lord Howe Island. Int16 amount_of_offset_change; /// Usually -3600 or 3600, but look at Lord Howe Island.
@ -51,15 +52,16 @@ public:
private: private:
/// Lookup table is indexed by DayNum. /// Lookup table is indexed by DayNum.
/// Day nums are the same in all time zones. 1970-01-01 is 0 and so on. /// Day nums are the same in all time zones. 1970-01-01 is 0 and so on.
/// Table is relatively large (~30 000 elements), so better not to place object on stack. /// Table is relatively large, so better not to place the object on stack.
/// In comparison to std::vector, plain array is cheaper by one indirection. /// In comparison to std::vector, plain array is cheaper by one indirection.
Values lut[DATE_LUT_MAX_DAY_NUM + 1]; Values lut[DATE_LUT_SIZE];
/// Year number after DATE_LUT_MIN_YEAR -> day num for start of year. /// Year number after DATE_LUT_MIN_YEAR -> day num for start of year.
DayNum_t years_lut[DATE_LUT_YEARS]; DayNum_t years_lut[DATE_LUT_YEARS];
/// UTC offset at beginning of the Unix epoch. /// UTC offset at beginning of the Unix epoch. The same as unix timestamp of 1970-01-01 00:00:00 local time.
time_t offset_at_start_of_epoch; time_t offset_at_start_of_epoch;
bool offset_is_whole_number_of_hours_everytime;
/// Time zone name. /// Time zone name.
std::string time_zone; std::string time_zone;
@ -92,15 +94,10 @@ private:
return lut[findIndex(t)]; return lut[findIndex(t)];
} }
static inline DayNum_t fixDay(DayNum_t day)
{
return day > DATE_LUT_MAX_DAY_NUM ? static_cast<DayNum_t>(0) : day;
}
public: public:
const std::string & getTimeZone() const { return time_zone; } const std::string & getTimeZone() const { return time_zone; }
/// всё ниже thread-safe; корректность входных данных не проверяется /// All functions below are thread-safe; arguments are not checked.
inline time_t toDate(time_t t) const { return find(t).date; } inline time_t toDate(time_t t) const { return find(t).date; }
inline unsigned toMonth(time_t t) const { return find(t).month; } inline unsigned toMonth(time_t t) const { return find(t).month; }
@ -108,47 +105,7 @@ public:
inline unsigned toDayOfWeek(time_t t) const { return find(t).day_of_week; } inline unsigned toDayOfWeek(time_t t) const { return find(t).day_of_week; }
inline unsigned toDayOfMonth(time_t t) const { return find(t).day_of_month; } inline unsigned toDayOfMonth(time_t t) const { return find(t).day_of_month; }
/// номер недели, начиная с какой-то недели в прошлом; неделя начинается с понедельника /// Round down to start of monday.
/// (переводим к понедельнику и делим DayNum на 7; будем исходить из допущения,
/// что в области применения этой функции не было и не будет недель, состоящих не из семи дней)
inline unsigned toRelativeWeekNum(DayNum_t d) const
{
return (d + 8 - lut[d].day_of_week) / 7;
}
inline unsigned toRelativeWeekNum(time_t t) const
{
size_t index = findIndex(t);
return (index + 8 - lut[index].day_of_week) / 7;
}
/// номер месяца, начиная с какого-то месяца в прошлом (год * 12 + номер месяца в году)
inline unsigned toRelativeMonthNum(DayNum_t d) const
{
return lut[d].year * 12 + lut[d].month;
}
inline unsigned toRelativeMonthNum(time_t t) const
{
size_t index = findIndex(t);
return lut[index].year * 12 + lut[index].month;
}
/// делим unix timestamp на 3600;
/// (таким образом, учитываются прошедшие интервалы времени длительностью в час, не зависимо от перевода стрелок;
/// поддерживаются только часовые пояса, в которых перевод стрелок осуществлялся только на целое число часов)
inline time_t toRelativeHourNum(time_t t) const
{
return t / 3600;
}
/// делим unix timestamp на 60
inline time_t toRelativeMinuteNum(time_t t) const
{
return t / 60;
}
/// округление вниз до понедельника
inline time_t toFirstDayOfWeek(time_t t) const inline time_t toFirstDayOfWeek(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
@ -166,7 +123,7 @@ public:
return DayNum_t(index - (lut[index].day_of_week - 1)); return DayNum_t(index - (lut[index].day_of_week - 1));
} }
/// округление вниз до первого числа месяца /// Round down to start of month.
inline time_t toFirstDayOfMonth(time_t t) const inline time_t toFirstDayOfMonth(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
@ -175,7 +132,7 @@ public:
inline DayNum_t toFirstDayNumOfMonth(DayNum_t d) const inline DayNum_t toFirstDayNumOfMonth(DayNum_t d) const
{ {
return DayNum_t(d - (lut[fixDay(d)].day_of_month - 1)); return DayNum_t(d - (lut[d].day_of_month - 1));
} }
inline DayNum_t toFirstDayNumOfMonth(time_t t) const inline DayNum_t toFirstDayNumOfMonth(time_t t) const
@ -184,53 +141,33 @@ public:
return DayNum_t(index - (lut[index].day_of_month - 1)); return DayNum_t(index - (lut[index].day_of_month - 1));
} }
/// округление до первого числа квартала /// Round down to start of quarter.
inline time_t toFirstDayOfQuarter(time_t t) const
{
size_t index = findIndex(t);
switch (lut[index].month % 3)
{
case 0:
index = index - lut[index].day_of_month;
case 2:
index = index - lut[index].day_of_month;
case 1:
index = index - lut[index].day_of_month + 1;
}
return DayNum_t(index);
}
inline DayNum_t toFirstDayNumOfQuarter(DayNum_t d) const inline DayNum_t toFirstDayNumOfQuarter(DayNum_t d) const
{ {
size_t index = fixDay(d); size_t index = d;
switch (lut[index].month % 3) size_t month_inside_quarter = (lut[index].month - 1) % 3;
index = index - lut[index].day_of_month;
while (month_inside_quarter)
{ {
case 0: index = index - lut[index].day_of_month;
index = index - lut[index].day_of_month; --month_inside_quarter;
case 2:
index = index - lut[index].day_of_month;
case 1:
index = index - lut[index].day_of_month + 1;
} }
return DayNum_t(index);
return DayNum_t(index + 1);
} }
inline DayNum_t toFirstDayNumOfQuarter(time_t t) const inline DayNum_t toFirstDayNumOfQuarter(time_t t) const
{ {
size_t index = findIndex(t); return toFirstDayNumOfQuarter(toDayNum(t));
switch (lut[index].month % 3)
{
case 0:
index = index - lut[index].day_of_month;
case 2:
index = index - lut[index].day_of_month;
case 1:
index = index - lut[index].day_of_month + 1;
}
return DayNum_t(index);
} }
/// округление вниз до первого числа года inline time_t toFirstDayOfQuarter(time_t t) const
{
return fromDayNum(toFirstDayNumOfQuarter(t));
}
/// Round down to start of year.
inline time_t toFirstDayOfYear(time_t t) const inline time_t toFirstDayOfYear(time_t t) const
{ {
return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date; return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date;
@ -238,7 +175,7 @@ public:
inline DayNum_t toFirstDayNumOfYear(DayNum_t d) const inline DayNum_t toFirstDayNumOfYear(DayNum_t d) const
{ {
return years_lut[lut[fixDay(d)].year - DATE_LUT_MIN_YEAR]; return years_lut[lut[d].year - DATE_LUT_MIN_YEAR];
} }
inline time_t toFirstDayNumOfYear(time_t t) const inline time_t toFirstDayNumOfYear(time_t t) const
@ -246,7 +183,6 @@ public:
return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date; return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date;
} }
/// первое число следующего месяца
inline time_t toFirstDayOfNextMonth(time_t t) const inline time_t toFirstDayOfNextMonth(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
@ -254,7 +190,6 @@ public:
return lut[index - (lut[index].day_of_month - 1)].date; return lut[index - (lut[index].day_of_month - 1)].date;
} }
/// первое число предыдущего месяца
inline time_t toFirstDayOfPrevMonth(time_t t) const inline time_t toFirstDayOfPrevMonth(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
@ -262,20 +197,25 @@ public:
return lut[index - (lut[index].day_of_month - 1)].date; return lut[index - (lut[index].day_of_month - 1)].date;
} }
/// количество дней в месяце inline UInt8 daysInMonth(DayNum_t d) const
inline size_t daysInMonth(time_t t) const
{ {
size_t today = findIndex(t); return lut[d].days_in_month;
size_t start_of_month = today - (lut[today].day_of_month - 1);
size_t next_month = start_of_month + 31;
size_t start_of_next_month = next_month - (lut[next_month].day_of_month - 1);
return start_of_next_month - start_of_month;
} }
/** Округление до даты; затем сдвиг на указанное количество дней. inline UInt8 daysInMonth(time_t t) const
* Замечание: результат сдвига должен находиться в пределах LUT. {
return find(t).days_in_month;
}
inline UInt8 daysInMonth(UInt16 year, UInt8 month) const
{
auto any_day_of_month = years_lut[year - DATE_LUT_MIN_YEAR] + 31 * (month - 1);
return lut[any_day_of_month].days_in_month;
}
/** Round to start of day, then shift for specified amount of days.
*/ */
inline time_t toDateAndShift(time_t t, int days = 1) const inline time_t toDateAndShift(time_t t, Int32 days) const
{ {
return lut[findIndex(t) + days].date; return lut[findIndex(t) + days].date;
} }
@ -283,17 +223,25 @@ public:
inline time_t toTime(time_t t) const inline time_t toTime(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
if (unlikely(index == 0))
return t + offset_at_start_of_epoch;
time_t res = t - lut[index].date; time_t res = t - lut[index].date;
if (res >= lut[index].time_at_offset_change) if (res >= lut[index].time_at_offset_change)
res += lut[index].amount_of_offset_change; res += lut[index].amount_of_offset_change;
return res - offset_at_start_of_epoch; /// Отсчёт от 1970-01-01 00:00:00 по локальному времени return res - offset_at_start_of_epoch; /// Starting at 1970-01-01 00:00:00 local time.
} }
inline unsigned toHour(time_t t) const inline unsigned toHour(time_t t) const
{ {
size_t index = findIndex(t); size_t index = findIndex(t);
if (unlikely(index == 0))
return (t + offset_at_start_of_epoch) / 3600;
time_t res = t - lut[index].date; time_t res = t - lut[index].date;
if (res >= lut[index].time_at_offset_change) if (res >= lut[index].time_at_offset_change)
@ -302,46 +250,103 @@ public:
return res / 3600; return res / 3600;
} }
inline unsigned toMinute(time_t t) const { return ((t - find(t).date) % 3600) / 60; } /** Only for time zones with/when offset from UTC is multiple of five minutes.
inline unsigned toSecond(time_t t) const { return (t - find(t).date) % 60; } * This is true for all time zones: right now, all time zones have an offset that is multiple of 15 minutes.
*
* "By 1929, most major countries had adopted hourly time zones. Nepal was the last
* country to adopt a standard offset, shifting slightly to UTC+5:45 in 1986."
* - https://en.wikipedia.org/wiki/Time_zone#Offsets_from_UTC
*
* Also please note, that unix timestamp doesn't count "leap seconds":
* each minute, with added or subtracted leap second, spans exactly 60 unix timestamps.
*/
inline unsigned toStartOfMinute(time_t t) const inline unsigned toSecond(time_t t) const { return t % 60; }
inline unsigned toMinute(time_t t) const
{ {
if (offset_is_whole_number_of_hours_everytime)
return (t / 60) % 60;
time_t date = find(t).date; time_t date = find(t).date;
return date + (t - date) / 60 * 60; return (t - date) / 60 % 60;
} }
inline unsigned toStartOfHour(time_t t) const inline time_t toStartOfMinute(time_t t) const { return t / 60 * 60; }
inline time_t toStartOfFiveMinute(time_t t) const { return t / 300 * 300; }
inline time_t toStartOfHour(time_t t) const
{ {
if (offset_is_whole_number_of_hours_everytime)
return t / 3600 * 3600;
time_t date = find(t).date; time_t date = find(t).date;
/// Still can return wrong values for time at 1970-01-01 if the UTC offset was non-whole number of hours.
return date + (t - date) / 3600 * 3600; return date + (t - date) / 3600 * 3600;
} }
/** Только для часовых поясов, отличающихся от UTC на значение, кратное часу и без перевода стрелок не значение не кратное часу */ /** Number of calendar day since the beginning of UNIX epoch (1970-01-01 is zero)
* We use just two bytes for it. It covers the range up to 2105 and slightly more.
inline unsigned toMinuteInaccurate(time_t t) const { return (t / 60) % 60; } *
inline unsigned toSecondInaccurate(time_t t) const { return t % 60; } * This is "calendar" day, it itself is independent of time zone
* (conversion from/to unix timestamp will depend on time zone,
inline unsigned toStartOfMinuteInaccurate(time_t t) const { return t / 60 * 60; } * because the same calendar day starts/ends at different timestamps in different time zones)
inline unsigned toStartOfFiveMinuteInaccurate(time_t t) const { return t / 300 * 300; } */
inline unsigned toStartOfHourInaccurate(time_t t) const { return t / 3600 * 3600; }
/// Номер дня в пределах UNIX эпохи (и немного больше) - позволяет хранить дату в двух байтах
inline DayNum_t toDayNum(time_t t) const { return static_cast<DayNum_t>(findIndex(t)); } inline DayNum_t toDayNum(time_t t) const { return static_cast<DayNum_t>(findIndex(t)); }
inline time_t fromDayNum(DayNum_t d) const { return lut[fixDay(d)].date; } inline time_t fromDayNum(DayNum_t d) const { return lut[d].date; }
inline time_t toDate(DayNum_t d) const { return lut[fixDay(d)].date; } inline time_t toDate(DayNum_t d) const { return lut[d].date; }
inline unsigned toMonth(DayNum_t d) const { return lut[fixDay(d)].month; } inline unsigned toMonth(DayNum_t d) const { return lut[d].month; }
inline unsigned toYear(DayNum_t d) const { return lut[fixDay(d)].year; } inline unsigned toYear(DayNum_t d) const { return lut[d].year; }
inline unsigned toDayOfWeek(DayNum_t d) const { return lut[fixDay(d)].day_of_week; } inline unsigned toDayOfWeek(DayNum_t d) const { return lut[d].day_of_week; }
inline unsigned toDayOfMonth(DayNum_t d) const { return lut[fixDay(d)].day_of_month; } inline unsigned toDayOfMonth(DayNum_t d) const { return lut[d].day_of_month; }
inline const Values & getValues(DayNum_t d) const { return lut[fixDay(d)]; } /// Number of week from some fixed moment in the past. Week begins at monday.
inline const Values & getValues(time_t t) const { return lut[findIndex(t)]; } /// (round down to monday and divide DayNum by 7; we made an assumption,
/// that in domain of the function there was no weeks with any other number of days than 7)
inline unsigned toRelativeWeekNum(DayNum_t d) const
{
/// We add 8 to avoid underflow at beginning of unix epoch.
return (d + 8 - lut[d].day_of_week) / 7;
}
/// получает DayNum_t из года, месяца, дня inline unsigned toRelativeWeekNum(time_t t) const
inline DayNum_t makeDayNum(short year, char month, char day_of_month) const {
size_t index = findIndex(t);
return (index + 8 - lut[index].day_of_week) / 7;
}
/// Number of month from some fixed moment in the past (year * 12 + month)
inline unsigned toRelativeMonthNum(DayNum_t d) const
{
return lut[d].year * 12 + lut[d].month;
}
inline unsigned toRelativeMonthNum(time_t t) const
{
size_t index = findIndex(t);
return lut[index].year * 12 + lut[index].month;
}
/// We calculate all hour-length intervals, unrelated to offset changes.
inline time_t toRelativeHourNum(time_t t) const
{
if (offset_is_whole_number_of_hours_everytime)
return t / 3600;
/// Assume that if offset was fractional, then the fraction is the same as at the beginning of epoch.
/// NOTE This assumption is false for "Pacific/Pitcairn" time zone.
return (t + 86400 - offset_at_start_of_epoch) / 3600;
}
inline time_t toRelativeMinuteNum(time_t t) const
{
return t / 60;
}
/// Create DayNum_t from year, month, day of month.
inline DayNum_t makeDayNum(UInt16 year, UInt8 month, UInt8 day_of_month) const
{ {
if (unlikely(year < DATE_LUT_MIN_YEAR || year > DATE_LUT_MAX_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31)) if (unlikely(year < DATE_LUT_MIN_YEAR || year > DATE_LUT_MAX_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31))
return DayNum_t(0); return DayNum_t(0);
@ -349,14 +354,14 @@ public:
return DayNum_t(any_day_of_month - toDayOfMonth(any_day_of_month) + day_of_month); return DayNum_t(any_day_of_month - toDayOfMonth(any_day_of_month) + day_of_month);
} }
inline time_t makeDate(short year, char month, char day_of_month) const inline time_t makeDate(UInt16 year, UInt8 month, UInt8 day_of_month) const
{ {
return lut[makeDayNum(year, month, day_of_month)].date; return lut[makeDayNum(year, month, day_of_month)].date;
} }
/** Does not accept daylight saving time as argument: in case of ambiguity, it choose greater timestamp. /** Does not accept daylight saving time as argument: in case of ambiguity, it choose greater timestamp.
*/ */
inline time_t makeDateTime(short year, char month, char day_of_month, char hour, char minute, char second) const inline time_t makeDateTime(UInt16 year, UInt8 month, UInt8 day_of_month, UInt8 hour, UInt8 minute, UInt8 second) const
{ {
size_t index = makeDayNum(year, month, day_of_month); size_t index = makeDayNum(year, month, day_of_month);
time_t time_offset = hour * 3600 + minute * 60 + second; time_t time_offset = hour * 3600 + minute * 60 + second;
@ -367,6 +372,9 @@ public:
return lut[index].date + time_offset; return lut[index].date + time_offset;
} }
inline const Values & getValues(DayNum_t d) const { return lut[d]; }
inline const Values & getValues(time_t t) const { return lut[findIndex(t)]; }
inline UInt32 toNumYYYYMM(time_t t) const inline UInt32 toNumYYYYMM(time_t t) const
{ {
const Values & values = find(t); const Values & values = find(t);
@ -375,7 +383,7 @@ public:
inline UInt32 toNumYYYYMM(DayNum_t d) const inline UInt32 toNumYYYYMM(DayNum_t d) const
{ {
const Values & values = lut[fixDay(d)]; const Values & values = lut[d];
return values.year * 100 + values.month; return values.year * 100 + values.month;
} }
@ -387,7 +395,7 @@ public:
inline UInt32 toNumYYYYMMDD(DayNum_t d) const inline UInt32 toNumYYYYMMDD(DayNum_t d) const
{ {
const Values & values = lut[fixDay(d)]; const Values & values = lut[d];
return values.year * 10000 + values.month * 100 + values.day_of_month; return values.year * 10000 + values.month * 100 + values.day_of_month;
} }
@ -406,8 +414,8 @@ public:
{ {
const Values & values = find(t); const Values & values = find(t);
return return
toSecondInaccurate(t) toSecond(t)
+ toMinuteInaccurate(t) * 100 + toMinute(t) * 100
+ toHour(t) * 10000 + toHour(t) * 10000
+ UInt64(values.day_of_month) * 1000000 + UInt64(values.day_of_month) * 1000000
+ UInt64(values.month) * 100000000 + UInt64(values.month) * 100000000
@ -425,6 +433,113 @@ public:
num % 100); num % 100);
} }
/// Adding calendar intervals.
/// Implementation specific behaviour when delta is too big.
inline time_t addDays(time_t t, Int64 delta) const
{
size_t index = findIndex(t);
time_t time_offset = toHour(t) * 3600 + toMinute(t) * 60 + toSecond(t);
index += delta;
if (time_offset >= lut[index].time_at_offset_change)
time_offset -= lut[index].amount_of_offset_change;
return lut[index].date + time_offset;
}
inline time_t addWeeks(time_t t, Int64 delta) const
{
return addDays(t, delta * 7);
}
inline UInt8 saturateDayOfMonth(UInt16 year, UInt8 month, UInt8 day_of_month) const
{
if (likely(day_of_month <= 28))
return day_of_month;
UInt8 days_in_month = daysInMonth(year, month);
if (day_of_month > days_in_month)
day_of_month = days_in_month;
return day_of_month;
}
/// If resulting month has less deys than source month, then saturation can happen.
/// Example: 31 Aug + 1 month = 30 Sep.
inline time_t addMonths(time_t t, Int64 delta) const
{
size_t index = findIndex(t);
const Values & values = lut[index];
time_t time_offset = toHour(t) * 3600 + toMinute(t) * 60 + toSecond(t);
auto month = values.month + delta;
auto year = values.year + (month - 1) / 12;
month = ((month - 1) % 12) + 1;
auto day_of_month = saturateDayOfMonth(year, month, values.day_of_month);
DayNum_t result_day = makeDayNum(year, month, day_of_month);
if (time_offset >= lut[result_day].time_at_offset_change)
time_offset -= lut[result_day].amount_of_offset_change;
return lut[result_day].date + time_offset;
}
inline DayNum_t addMonths(DayNum_t d, Int64 delta) const
{
const Values & values = lut[d];
auto month = values.month + delta;
auto year = values.year + (month - 1) / 12;
month = ((month - 1) % 12) + 1;
auto day_of_month = saturateDayOfMonth(year, month, values.day_of_month);
return makeDayNum(year, month, day_of_month);
}
/// Saturation can occur if 29 Feb is mapped to non-leap year.
inline time_t addYears(time_t t, Int64 delta) const
{
size_t index = findIndex(t);
const Values & values = lut[index];
time_t time_offset = toHour(t) * 3600 + toMinute(t) * 60 + toSecond(t);
auto year = values.year + delta;
auto month = values.month;
auto day_of_month = values.day_of_month;
/// Saturation to 28 Feb can happen.
if (unlikely(day_of_month == 29 && month == 2))
day_of_month = saturateDayOfMonth(year, month, day_of_month);
DayNum_t result_day = makeDayNum(year, month, day_of_month);
if (time_offset >= lut[result_day].time_at_offset_change)
time_offset -= lut[result_day].amount_of_offset_change;
return lut[result_day].date + time_offset;
}
inline DayNum_t addYears(DayNum_t d, Int64 delta) const
{
const Values & values = lut[d];
auto year = values.year + delta;
auto month = values.month;
auto day_of_month = values.day_of_month;
/// Saturation to 28 Feb can happen.
if (unlikely(day_of_month == 29 && month == 2))
day_of_month = saturateDayOfMonth(year, month, day_of_month);
return makeDayNum(year, month, day_of_month);
}
inline std::string timeToString(time_t t) const inline std::string timeToString(time_t t) const
{ {
@ -442,8 +557,8 @@ public:
s[9] += values.day_of_month % 10; s[9] += values.day_of_month % 10;
auto hour = toHour(t); auto hour = toHour(t);
auto minute = toMinuteInaccurate(t); auto minute = toMinute(t);
auto second = toSecondInaccurate(t); auto second = toSecond(t);
s[11] += hour / 10; s[11] += hour / 10;
s[12] += hour % 10; s[12] += hour % 10;
@ -475,7 +590,7 @@ public:
inline std::string dateToString(DayNum_t d) const inline std::string dateToString(DayNum_t d) const
{ {
const Values & values = lut[fixDay(d)]; const Values & values = lut[d];
std::string s {"0000-00-00"}; std::string s {"0000-00-00"};
@ -490,4 +605,6 @@ public:
return s; return s;
} }
inline bool isOffsetWholeNumberOfHoursEveryTime() const { return offset_is_whole_number_of_hours_everytime; }
}; };

View File

@ -48,8 +48,8 @@ private:
m_month = values.month; m_month = values.month;
m_day = values.day_of_month; m_day = values.day_of_month;
m_hour = date_lut.toHour(time); m_hour = date_lut.toHour(time);
m_minute = date_lut.toMinuteInaccurate(time); m_minute = date_lut.toMinute(time);
m_second = date_lut.toSecondInaccurate(time); m_second = date_lut.toSecond(time);
} }
void init(const char * s, size_t length) void init(const char * s, size_t length)

View File

@ -6,28 +6,30 @@
template <typename F, typename C> template <typename F, typename C>
struct RangeFiltered struct RangeFiltered
{ {
using RawIterator = typename C:: iterator; /// Template parameter C may be const. Then const_iterator is used.
using RawIterator = decltype(std::declval<C>().begin());
class Iterator; class Iterator;
/// Will iterate over elements for which filter(*it) == true /// Will iterate over elements for which filter(*it) == true
RangeFiltered(F && filter, const C & container) template <typename F_, typename C_> /// Another template for universal references to work.
: filter(std::move(filter)), container(container) {} RangeFiltered(F_ && filter, C_ && container)
: filter(std::move(filter)), container(container) {}
Iterator begin() const Iterator begin() const
{ {
return {*this, std::begin(container)}; return Iterator{*this, std::begin(container)};
} }
Iterator end() const Iterator end() const
{ {
return {*this, std::end(container)}; return Iterator{*this, std::end(container)};
} }
/// Convert ordinary iterator to filtered one /// Convert ordinary iterator to filtered one
/// Real position will be in range [ordinary_iterator; end()], so it is suitable to use with lower[upper]_bound() /// Real position will be in range [ordinary_iterator; end()], so it is suitable to use with lower[upper]_bound()
inline Iterator convert(RawIterator ordinary_iterator) const inline Iterator convert(RawIterator ordinary_iterator) const
{ {
return {*this, ordinary_iterator}; return Iterator{*this, ordinary_iterator};
} }
@ -114,12 +116,12 @@ struct RangeFiltered
protected: protected:
F filter; F filter;
const C & container; C & container;
}; };
template <typename F, typename C> template <typename F, typename C>
inline RangeFiltered<std::decay_t<F>, std::decay_t<C>> createRangeFiltered(F && filter, C && container) inline RangeFiltered<std::decay_t<F>, std::remove_reference_t<C>> createRangeFiltered(F && filter, C && container)
{ {
return {std::forward<F>(filter), std::forward<C>(container)}; return {std::forward<F>(filter), std::forward<C>(container)};
}; };

View File

@ -13,7 +13,27 @@ using UInt32 = Poco::UInt32;
using UInt64 = Poco::UInt64; using UInt64 = Poco::UInt64;
/// Обход проблемы с тем, что KDevelop не видит time_t и size_t (для подсветки синтаксиса). /** This is not the best way to overcome an issue of different definitions
* of uint64_t and size_t on Linux and Mac OS X (both 64 bit).
*
* Note that on both platforms, long and long long are 64 bit types.
* But they are always different types (with the same physical representation).
*/
namespace std
{
inline UInt64 max(unsigned long x, unsigned long long y) { return x > y ? x : y; }
inline UInt64 max(unsigned long long x, unsigned long y) { return x > y ? x : y; }
inline UInt64 min(unsigned long x, unsigned long long y) { return x < y ? x : y; }
inline UInt64 min(unsigned long long x, unsigned long y) { return x < y ? x : y; }
inline Int64 max(long x, long long y) { return x > y ? x : y; }
inline Int64 max(long long x, long y) { return x > y ? x : y; }
inline Int64 min(long x, long long y) { return x < y ? x : y; }
inline Int64 min(long long x, long y) { return x < y ? x : y; }
}
/// Workaround for the issue, that KDevelop doesn't see time_t and size_t types (for syntax highlight).
#ifdef IN_KDEVELOP_PARSER #ifdef IN_KDEVELOP_PARSER
using time_t = Int64; using time_t = Int64;
using size_t = UInt64; using size_t = UInt64;

View File

@ -9,6 +9,8 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#define DATE_LUT_MIN 0
namespace namespace
{ {
@ -45,6 +47,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
cctz::time_zone::absolute_lookup start_of_epoch_lookup = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(start_of_day)); cctz::time_zone::absolute_lookup start_of_epoch_lookup = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(start_of_day));
offset_at_start_of_epoch = start_of_epoch_lookup.offset; offset_at_start_of_epoch = start_of_epoch_lookup.offset;
offset_is_whole_number_of_hours_everytime = true;
cctz::civil_day date{1970, 1, 1}; cctz::civil_day date{1970, 1, 1};
@ -61,9 +64,20 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
values.day_of_week = getDayOfWeek(date); values.day_of_week = getDayOfWeek(date);
values.date = start_of_day; values.date = start_of_day;
if (values.day_of_month == 1)
{
cctz::civil_month month(date);
values.days_in_month = cctz::civil_day(month + 1) - cctz::civil_day(month);
}
else
values.days_in_month = i != 0 ? lut[i - 1].days_in_month : 31;
values.time_at_offset_change = 0; values.time_at_offset_change = 0;
values.amount_of_offset_change = 0; values.amount_of_offset_change = 0;
if (start_of_day % 3600)
offset_is_whole_number_of_hours_everytime = false;
/// If UTC offset was changed in previous day. /// If UTC offset was changed in previous day.
if (i != 0) if (i != 0)
{ {
@ -102,7 +116,14 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
} }
while (start_of_day <= DATE_LUT_MAX && i <= DATE_LUT_MAX_DAY_NUM); while (start_of_day <= DATE_LUT_MAX && i <= DATE_LUT_MAX_DAY_NUM);
/// Заполняем lookup таблицу для годов /// Fill excessive part of lookup table. This is needed only to simplify handling of overflow cases.
while (i < DATE_LUT_SIZE)
{
lut[i] = lut[0];
++i;
}
/// Fill lookup table for years.
::memset(years_lut, 0, DATE_LUT_YEARS * sizeof(years_lut[0])); ::memset(years_lut, 0, DATE_LUT_YEARS * sizeof(years_lut[0]));
for (size_t day = 0; day < i && lut[day].year <= DATE_LUT_MAX_YEAR; ++day) for (size_t day = 0; day < i && lut[day].year <= DATE_LUT_MAX_YEAR; ++day)
{ {

View File

@ -14,9 +14,8 @@ target_link_libraries (date_lut2 common ${PLATFORM_LIBS})
target_link_libraries (date_lut3 common ${PLATFORM_LIBS}) target_link_libraries (date_lut3 common ${PLATFORM_LIBS})
target_link_libraries (date_lut4 common ${PLATFORM_LIBS}) target_link_libraries (date_lut4 common ${PLATFORM_LIBS})
target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS}) target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS})
target_link_libraries (multi_version common ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${RT_LIBRARIES}) target_link_libraries (multi_version common ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${RT_LIBRARIES})
add_executable (unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp) add_executable (unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp)
target_link_libraries (unit_tests_libcommon gtest_main) target_link_libraries (unit_tests_libcommon gtest_main common ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${RT_LIBRARIES})
target_link_libraries (unit_tests_libcommon ${Boost_SYSTEM_LIBRARY} ${RT_LIBRARIES} common)
add_check(unit_tests_libcommon) add_check(unit_tests_libcommon)

View File

@ -3,7 +3,7 @@
set -e set -e
BRANCH=trunk BRANCH=trunk
#BRANCH=tags/RELEASE_400/final #BRANCH=tags/RELEASE_500/final
THREADS=$(grep -c ^processor /proc/cpuinfo) THREADS=$(grep -c ^processor /proc/cpuinfo)