This commit is contained in:
lgbo-ustc 2023-04-19 19:22:36 +08:00
parent 8e16db7060
commit 10daacb18f
7 changed files with 39 additions and 100 deletions

View File

@ -9,7 +9,7 @@ Selects the first encountered value, similar to `any`, but could accept NULL.
## examples ## examples
```sq; ```sql
insert into test_data (a,b) values (1,null), (2,3), (4, 5), (6,null) insert into test_data (a,b) values (1,null), (2,3), (4, 5), (6,null)
``` ```

View File

@ -10,7 +10,7 @@ Selects the last encountered value, similar to `anyLast`, but could accept NULL.
## examples ## examples
```sq; ```sql
insert into test_data (a,b) values (1,null), (2,3), (4, 5), (6,null) insert into test_data (a,b) values (1,null), (2,3), (4, 5), (6,null)
``` ```

View File

@ -14,11 +14,12 @@ AggregateFunctionPtr createAggregateFunctionAny(const std::string & name, const
return AggregateFunctionPtr(createAggregateFunctionSingleValue<AggregateFunctionsSingleValue, AggregateFunctionAnyData>(name, argument_types, parameters, settings)); return AggregateFunctionPtr(createAggregateFunctionSingleValue<AggregateFunctionsSingleValue, AggregateFunctionAnyData>(name, argument_types, parameters, settings));
} }
template <bool RespectNulls = false, bool NullIsGreater = false> template <bool RespectNulls = false>
AggregateFunctionPtr createAggregateFunctionNullableAny(const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings) AggregateFunctionPtr createAggregateFunctionNullableAny(
const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings)
{ {
return AggregateFunctionPtr( return AggregateFunctionPtr(
createAggregateFunctionSingleNullableValue<AggregateFunctionsSingleValue, AggregateFunctionAnyData, RespectNulls, NullIsGreater>( createAggregateFunctionSingleNullableValue<AggregateFunctionsSingleValue, AggregateFunctionAnyData, RespectNulls>(
name, argument_types, parameters, settings)); name, argument_types, parameters, settings));
} }
@ -27,14 +28,13 @@ AggregateFunctionPtr createAggregateFunctionAnyLast(const std::string & name, co
return AggregateFunctionPtr(createAggregateFunctionSingleValue<AggregateFunctionsSingleValue, AggregateFunctionAnyLastData>(name, argument_types, parameters, settings)); return AggregateFunctionPtr(createAggregateFunctionSingleValue<AggregateFunctionsSingleValue, AggregateFunctionAnyLastData>(name, argument_types, parameters, settings));
} }
template <bool RespectNulls = false, bool NullIsGreater = false> template <bool RespectNulls = false>
AggregateFunctionPtr createAggregateFunctionNullableAnyLast(const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings) AggregateFunctionPtr createAggregateFunctionNullableAnyLast(const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings)
{ {
return AggregateFunctionPtr(createAggregateFunctionSingleNullableValue< return AggregateFunctionPtr(createAggregateFunctionSingleNullableValue<
AggregateFunctionsSingleValue, AggregateFunctionsSingleValue,
AggregateFunctionAnyLastData, AggregateFunctionAnyLastData,
RespectNulls, RespectNulls>(name, argument_types, parameters, settings));
NullIsGreater>(name, argument_types, parameters, settings));
} }
AggregateFunctionPtr createAggregateFunctionAnyHeavy(const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings) AggregateFunctionPtr createAggregateFunctionAnyHeavy(const std::string & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings)
@ -59,18 +59,12 @@ void registerAggregateFunctionsAny(AggregateFunctionFactory & factory)
factory.registerFunction("first_value_respect_nulls", factory.registerFunction("first_value_respect_nulls",
{ createAggregateFunctionNullableAny<true>, properties }, { createAggregateFunctionNullableAny<true>, properties },
AggregateFunctionFactory::CaseInsensitive); AggregateFunctionFactory::CaseInsensitive);
factory.registerFunction("first_value_ignore_nulls",
{ createAggregateFunctionNullableAny<false>, properties },
AggregateFunctionFactory::CaseInsensitive);
factory.registerFunction("last_value", factory.registerFunction("last_value",
{ createAggregateFunctionAnyLast, properties }, { createAggregateFunctionAnyLast, properties },
AggregateFunctionFactory::CaseInsensitive); AggregateFunctionFactory::CaseInsensitive);
factory.registerFunction("last_value_respect_nulls", factory.registerFunction("last_value_respect_nulls",
{ createAggregateFunctionNullableAnyLast<true>, properties }, { createAggregateFunctionNullableAnyLast<true>, properties },
AggregateFunctionFactory::CaseInsensitive); AggregateFunctionFactory::CaseInsensitive);
factory.registerFunction("last_value_ignore_nulls",
{ createAggregateFunctionNullableAnyLast<false>, properties },
AggregateFunctionFactory::CaseInsensitive);
} }
} }

View File

@ -106,7 +106,7 @@ AggregateFunctionPtr AggregateFunctionFactory::get(
// nullability themselves. Another special case is functions from Nothing // nullability themselves. Another special case is functions from Nothing
// that are rewritten to AggregateFunctionNothing, in this case // that are rewritten to AggregateFunctionNothing, in this case
// nested_function is nullptr. // nested_function is nullptr.
if ((!nested_function || !nested_function->isOnlyWindowFunction())) if (!nested_function || !nested_function->isOnlyWindowFunction())
return combinator->transformAggregateFunction(nested_function, out_properties, types_without_low_cardinality, parameters); return combinator->transformAggregateFunction(nested_function, out_properties, types_without_low_cardinality, parameters);
} }

View File

@ -766,7 +766,7 @@ static_assert(
/// For any other value types. /// For any other value types.
template <bool IS_NULLABLE = false, bool IS_NULL_GREATER = false> template <bool IS_NULLABLE = false>
struct SingleValueDataGeneric struct SingleValueDataGeneric
{ {
private: private:
@ -778,7 +778,6 @@ private:
public: public:
static constexpr bool is_nullable = IS_NULLABLE; static constexpr bool is_nullable = IS_NULLABLE;
static constexpr bool is_any = false; static constexpr bool is_any = false;
static constexpr bool is_null_greater = IS_NULL_GREATER;
bool has() const bool has() const
{ {
@ -881,26 +880,13 @@ public:
{ {
Field new_value; Field new_value;
column.get(row_num, new_value); column.get(row_num, new_value);
if constexpr (!is_null_greater) if (!value.isNull() && (new_value.isNull() || new_value < value))
{ {
if (!value.isNull() && (new_value.isNull() || new_value < value)) value = new_value;
{ return true;
value = new_value;
return true;
}
else
return false;
} }
else else
{
if ((value.isNull() && !new_value.isNull()) || (!new_value.isNull() && new_value < value))
{
value = new_value;
return true;
}
return false; return false;
}
} }
else else
{ {
@ -928,24 +914,12 @@ public:
change(to, arena); change(to, arena);
return true; return true;
} }
if constexpr (!is_null_greater) if (to.value.isNull() || (!value.isNull() && to.value < value))
{ {
if (to.value.isNull() || (!value.isNull() && to.value < value)) value = to.value;
{ return true;
value = to.value;
return true;
}
return false;
}
else
{
if ((value.isNull() && !to.value.isNull()) || (!to.value.isNull() || to.value < value))
{
value = to.value;
return true;
}
return false;
} }
return false;
} }
else else
{ {
@ -972,24 +946,12 @@ public:
{ {
Field new_value; Field new_value;
column.get(row_num, new_value); column.get(row_num, new_value);
if constexpr (is_null_greater) if (!value.isNull() && (new_value.isNull() || value < new_value))
{ {
if (!value.isNull() && (new_value.isNull() || value < new_value)) value = new_value;
{ return true;
value = new_value;
return true;
}
return false;
}
else
{
if ((value.isNull() && !new_value.isNull()) || (!new_value.isNull() && value < new_value))
{
value = new_value;
return true;
}
return false;
} }
return false;
} }
else else
{ {
@ -1012,25 +974,12 @@ public:
return false; return false;
if constexpr (is_nullable) if constexpr (is_nullable)
{ {
if constexpr (is_null_greater) if (!value.isNull() && (to.value.isNull() || value < to.value))
{ {
if (!value.isNull() && (to.value.isNull() || value < to.value)) value = to.value;
{ return true;
value = to.value;
return true;
}
return false;
}
else
{
if ((value.isNull() && !to.value.isNull()) || (!to.value.isNull() && value < to.value))
{
value = to.value;
return true;
}
return false;
} }
return false;
} }
else else
{ {

View File

@ -11,10 +11,6 @@
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
}
struct Settings; struct Settings;
/// min, max, any, anyLast, anyHeavy, etc... /// min, max, any, anyLast, anyHeavy, etc...
@ -51,29 +47,23 @@ static IAggregateFunction * createAggregateFunctionSingleValue(const String & na
return new AggregateFunctionTemplate<Data<SingleValueDataGeneric<>>>(argument_type); return new AggregateFunctionTemplate<Data<SingleValueDataGeneric<>>>(argument_type);
} }
template <template <typename> class AggregateFunctionTemplate, template <typename> class Data, bool RespectNulls = false, bool NullIsGreater = false> template <template <typename> class AggregateFunctionTemplate, template <typename> class Data, bool RespectNulls = false>
static IAggregateFunction * createAggregateFunctionSingleNullableValue(const String & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings) static IAggregateFunction * createAggregateFunctionSingleNullableValue(const String & name, const DataTypes & argument_types, const Array & parameters, const Settings * settings)
{ {
assertNoParameters(name, parameters); assertNoParameters(name, parameters);
assertUnary(name, argument_types); assertUnary(name, argument_types);
if (parameters.size() > 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "name's parameter size must not be larger then 2");
const DataTypePtr & argument_type = argument_types[0]; const DataTypePtr & argument_type = argument_types[0];
WhichDataType which(argument_type); WhichDataType which(argument_type);
// if the resule value could be null(excluding the case that no row is matched), // If the result value could be null (excluding the case that no row is matched),
// use SingleValueDataGeneric. // use SingleValueDataGeneric.
if constexpr (!RespectNulls) if constexpr (!RespectNulls)
{ {
return createAggregateFunctionSingleValue<AggregateFunctionTemplate, Data>(name, argument_types, Array(), settings); return createAggregateFunctionSingleValue<AggregateFunctionTemplate, Data>(name, argument_types, Array(), settings);
} }
else if constexpr (NullIsGreater)
{
return new AggregateFunctionTemplate<Data<SingleValueDataGeneric<true, true>>>(argument_type);
}
else else
{ {
return new AggregateFunctionTemplate<Data<SingleValueDataGeneric<true, false>>>(argument_type); return new AggregateFunctionTemplate<Data<SingleValueDataGeneric<true>>>(argument_type);
} }
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -1104,7 +1104,7 @@ public:
return false; return false;
} }
NullsAction nulls_action = NullsAction::DEFAULT; NullsAction nulls_action = NullsAction::EMPTY;
if (respect_nulls.ignore(pos, expected)) if (respect_nulls.ignore(pos, expected))
{ {
nulls_action = NullsAction::RESPECT_NULLS; nulls_action = NullsAction::RESPECT_NULLS;
@ -1150,19 +1150,25 @@ private:
enum NullsAction enum NullsAction
{ {
DEFAULT = 0, EMPTY = 0,
RESPECT_NULLS = 1, RESPECT_NULLS = 1,
IGNORE_NULLS = 2, IGNORE_NULLS = 2,
}; };
static String transformFunctionNameForRepectNulls(const String & original_function_name, NullsAction nulls_action) static String transformFunctionNameForRepectNulls(const String & original_function_name, NullsAction nulls_action)
{ {
static std::unordered_map<String, std::vector<String>> renamed_functions_with_nulls = { static std::unordered_map<String, std::vector<String>> renamed_functions_with_nulls = {
{"first_value", {"first_value_ignore_nulls", "first_value_respect_nulls", "first_value_ignore_nulls"}}, {"first_value", {"first_value", "first_value_respect_nulls", "first_value"}},
{"last_value", {"last_value_ignore_nulls", "last_value_respect_nulls", "last_value_ignore_nulls"}}, {"last_value", {"last_value", "last_value_respect_nulls", "last_value"}},
}; };
auto it = renamed_functions_with_nulls.find(original_function_name); auto it = renamed_functions_with_nulls.find(original_function_name);
if (it == renamed_functions_with_nulls.end()) if (it == renamed_functions_with_nulls.end())
return original_function_name; {
if (nulls_action == NullsAction::EMPTY)
return original_function_name;
else
throw Exception(
ErrorCodes::SYNTAX_ERROR, "Function {} does not support RESPECT NULLS or IGNORE NULLS", original_function_name);
}
return it->second[nulls_action]; return it->second[nulls_action];
} }
}; };