mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-19 16:20:50 +00:00
Merge b724f49deb
into 3eb5bc1a0f
This commit is contained in:
commit
65c21e9d9e
@ -24,7 +24,7 @@ void expandDataByMask(PaddedPODArray<T> & data, const PaddedPODArray<UInt8> & ma
|
||||
|
||||
ssize_t from = data.size() - 1;
|
||||
ssize_t index = mask.size() - 1;
|
||||
data.resize(mask.size());
|
||||
data.resize_exact(mask.size());
|
||||
while (index >= 0)
|
||||
{
|
||||
if (!!mask[index] ^ inverted)
|
||||
|
@ -893,6 +893,7 @@ class IColumn;
|
||||
M(Int64, ignore_cold_parts_seconds, 0, "Only available in ClickHouse Cloud. Exclude new data parts from SELECT queries until they're either pre-warmed (see cache_populated_by_fetch) or this many seconds old. Only for Replicated-/SharedMergeTree.", 0) \
|
||||
M(Int64, prefer_warmed_unmerged_parts_seconds, 0, "Only available in ClickHouse Cloud. If a merged part is less than this many seconds old and is not pre-warmed (see cache_populated_by_fetch), but all its source parts are available and pre-warmed, SELECT queries will read from those parts instead. Only for ReplicatedMergeTree. Note that this only checks whether CacheWarmer processed the part; if the part was fetched into cache by something else, it'll still be considered cold until CacheWarmer gets to it; if it was warmed, then evicted from cache, it'll still be considered warm.", 0) \
|
||||
M(Bool, iceberg_engine_ignore_schema_evolution, false, "Ignore schema evolution in Iceberg table engine and read all data using latest schema saved on table creation. Note that it can lead to incorrect result", 0) \
|
||||
M(Bool, short_circuit_default_implementation_for_nulls, true, "Setting for short-circuit default implementations for null in function with useDefaultImplementationForNulls() = true. If true, function will not actually evaluate for rows in which there are at least one argument with null value.", 0) \
|
||||
M(Bool, allow_deprecated_error_prone_window_functions, false, "Allow usage of deprecated error prone window functions (neighbor, runningAccumulate, runningDifferenceStartingWithFirstValue, runningDifference)", 0) \
|
||||
M(Bool, allow_deprecated_snowflake_conversion_functions, false, "Enables deprecated functions snowflakeToDateTime[64] and dateTime[64]ToSnowflake.", 0) \
|
||||
M(Bool, optimize_distinct_in_order, true, "Enable DISTINCT optimization if some columns in DISTINCT form a prefix of sorting. For example, prefix of sorting key in merge tree or ORDER BY statement", 0) \
|
||||
|
@ -77,6 +77,7 @@ static std::initializer_list<std::pair<ClickHouseVersion, SettingsChangesHistory
|
||||
{"join_output_by_rowlist_perkey_rows_threshold", 0, 5, "The lower limit of per-key average rows in the right table to determine whether to output by row list in hash join."},
|
||||
{"create_if_not_exists", false, false, "New setting."},
|
||||
{"allow_materialized_view_with_bad_select", true, true, "Support (but not enable yet) stricter validation in CREATE MATERIALIZED VIEW"},
|
||||
{"allow_short_circuit_default_implementation_for_nulls", true, true, "Setting for short-circuit default implementations for null in function with useDefaultImplementationForNulls() = true. If true, function will not actually evaluate for rows in which there are at least one argument with null value."},
|
||||
{"output_format_always_quote_identifiers", false, false, "New setting."},
|
||||
{"output_format_identifier_quoting_style", "Backticks", "Backticks", "New setting."},
|
||||
{"parallel_replicas_mark_segment_size", 128, 0, "Value for this setting now determined automatically"},
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <Common/assert_cast.h>
|
||||
|
||||
|
||||
@ -13,11 +13,11 @@ namespace DB
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int SIZES_OF_ARRAYS_DONT_MATCH;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int SIZES_OF_ARRAYS_DONT_MATCH;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
}
|
||||
|
||||
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
||||
@ -27,8 +27,7 @@ const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * co
|
||||
|
||||
const ColumnConst * res = assert_cast<const ColumnConst *>(column);
|
||||
|
||||
if (checkColumn<ColumnString>(&res->getDataColumn())
|
||||
|| checkColumn<ColumnFixedString>(&res->getDataColumn()))
|
||||
if (checkColumn<ColumnString>(&res->getDataColumn()) || checkColumn<ColumnFixedString>(&res->getDataColumn()))
|
||||
return res;
|
||||
|
||||
return {};
|
||||
@ -78,7 +77,7 @@ ColumnWithTypeAndName columnGetNested(const ColumnWithTypeAndName & col)
|
||||
{
|
||||
nullable_res = makeNullable(col.column);
|
||||
}
|
||||
return ColumnWithTypeAndName{ nullable_res, nested_type, col.name };
|
||||
return ColumnWithTypeAndName{nullable_res, nested_type, col.name};
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} for DataTypeNullable", col.dumpStructure());
|
||||
@ -102,18 +101,22 @@ String withOrdinalEnding(size_t i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return "1st";
|
||||
case 1: return "2nd";
|
||||
case 2: return "3rd";
|
||||
default: return std::to_string(i) + "th";
|
||||
case 0:
|
||||
return "1st";
|
||||
case 1:
|
||||
return "2nd";
|
||||
case 2:
|
||||
return "3rd";
|
||||
default:
|
||||
return std::to_string(i) + "th";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void validateArgumentsImpl(const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
size_t argument_offset,
|
||||
const FunctionArgumentDescriptors & descriptors)
|
||||
void validateArgumentsImpl(
|
||||
const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
size_t argument_offset,
|
||||
const FunctionArgumentDescriptors & descriptors)
|
||||
{
|
||||
for (size_t i = 0; i < descriptors.size(); ++i)
|
||||
{
|
||||
@ -124,13 +127,14 @@ void validateArgumentsImpl(const IFunction & func,
|
||||
const auto & arg = arguments[i + argument_offset];
|
||||
const auto & descriptor = descriptors[i];
|
||||
if (int error_code = descriptor.isValid(arg.type, arg.column); error_code != 0)
|
||||
throw Exception(error_code,
|
||||
"A value of illegal type was provided as {} argument '{}' to function '{}'. Expected: {}, got: {}",
|
||||
withOrdinalEnding(argument_offset + i),
|
||||
descriptor.name,
|
||||
func.getName(),
|
||||
descriptor.type_name,
|
||||
arg.type ? arg.type->getName() : "<?>");
|
||||
throw Exception(
|
||||
error_code,
|
||||
"A value of illegal type was provided as {} argument '{}' to function '{}'. Expected: {}, got: {}",
|
||||
withOrdinalEnding(argument_offset + i),
|
||||
descriptor.name,
|
||||
func.getName(),
|
||||
descriptor.type_name,
|
||||
arg.type ? arg.type->getName() : "<?>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,26 +154,35 @@ int FunctionArgumentDescriptor::isValid(const DataTypePtr & data_type, const Col
|
||||
return 0;
|
||||
}
|
||||
|
||||
void validateFunctionArguments(const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
const FunctionArgumentDescriptors & mandatory_args,
|
||||
const FunctionArgumentDescriptors & optional_args)
|
||||
void validateFunctionArguments(
|
||||
const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
const FunctionArgumentDescriptors & mandatory_args,
|
||||
const FunctionArgumentDescriptors & optional_args)
|
||||
{
|
||||
if (arguments.size() < mandatory_args.size() || arguments.size() > mandatory_args.size() + optional_args.size())
|
||||
{
|
||||
auto argument_singular_or_plural = [](const auto & args) -> std::string_view { return args.size() == 1 ? "argument" : "arguments"; };
|
||||
auto argument_singular_or_plural
|
||||
= [](const auto & args) -> std::string_view { return args.size() == 1 ? "argument" : "arguments"; };
|
||||
|
||||
String expected_args_string;
|
||||
if (!mandatory_args.empty() && !optional_args.empty())
|
||||
expected_args_string = fmt::format("{} mandatory {} and {} optional {}", mandatory_args.size(), argument_singular_or_plural(mandatory_args), optional_args.size(), argument_singular_or_plural(optional_args));
|
||||
expected_args_string = fmt::format(
|
||||
"{} mandatory {} and {} optional {}",
|
||||
mandatory_args.size(),
|
||||
argument_singular_or_plural(mandatory_args),
|
||||
optional_args.size(),
|
||||
argument_singular_or_plural(optional_args));
|
||||
else if (!mandatory_args.empty() && optional_args.empty())
|
||||
expected_args_string = fmt::format("{} {}", mandatory_args.size(), argument_singular_or_plural(mandatory_args)); /// intentionally not "_mandatory_ arguments"
|
||||
expected_args_string = fmt::format(
|
||||
"{} {}", mandatory_args.size(), argument_singular_or_plural(mandatory_args)); /// intentionally not "_mandatory_ arguments"
|
||||
else if (mandatory_args.empty() && !optional_args.empty())
|
||||
expected_args_string = fmt::format("{} optional {}", optional_args.size(), argument_singular_or_plural(optional_args));
|
||||
else
|
||||
expected_args_string = "0 arguments";
|
||||
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
throw Exception(
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"An incorrect number of arguments was specified for function '{}'. Expected {}, got {}",
|
||||
func.getName(),
|
||||
expected_args_string,
|
||||
@ -205,7 +218,8 @@ checkAndGetNestedArrayOffset(const IColumn ** columns, size_t num_arguments)
|
||||
return {nested_columns, offsets->data()};
|
||||
}
|
||||
|
||||
ColumnPtr wrapInNullable(const ColumnPtr & src, const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count)
|
||||
ColumnPtr
|
||||
wrapInNullable(const ColumnPtr & src, const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count)
|
||||
{
|
||||
ColumnPtr result_null_map_column;
|
||||
|
||||
@ -263,6 +277,39 @@ ColumnPtr wrapInNullable(const ColumnPtr & src, const ColumnsWithTypeAndName & a
|
||||
return ColumnNullable::create(src_not_nullable->convertToFullColumnIfConst(), result_null_map_column);
|
||||
}
|
||||
|
||||
ColumnPtr wrapInNullable(const ColumnPtr & src, const ColumnPtr & null_map)
|
||||
{
|
||||
if (src->onlyNull())
|
||||
return src;
|
||||
|
||||
ColumnPtr result_null_map_column;
|
||||
ColumnPtr src_not_nullable = src;
|
||||
if (const auto * nullable = checkAndGetColumn<ColumnNullable>(src.get()))
|
||||
{
|
||||
src_not_nullable = nullable->getNestedColumnPtr();
|
||||
result_null_map_column = nullable->getNullMapColumnPtr();
|
||||
|
||||
MutableColumnPtr mutable_result_null_map_column = IColumn::mutate(std::move(result_null_map_column));
|
||||
NullMap & result_null_map = assert_cast<ColumnUInt8 &>(*mutable_result_null_map_column).getData();
|
||||
const NullMap & null_map_data = assert_cast<const ColumnUInt8 &>(*null_map).getData();
|
||||
for (size_t i = 0; i < result_null_map.size(); ++i)
|
||||
result_null_map[i] |= null_map_data[i];
|
||||
|
||||
result_null_map_column = std::move(mutable_result_null_map_column);
|
||||
return ColumnNullable::create(src_not_nullable->convertToFullColumnIfConst(), result_null_map_column);
|
||||
}
|
||||
else if (const auto * const_src = checkAndGetColumn<ColumnConst>(src.get()))
|
||||
{
|
||||
const NullMap & null_map_data = assert_cast<const ColumnUInt8 &>(*null_map).getData();
|
||||
ColumnPtr result_null_map = ColumnUInt8::create(1, null_map_data[0] || const_src->isNullAt(0));
|
||||
const auto * nullable_data = checkAndGetColumn<ColumnNullable>(&const_src->getDataColumn());
|
||||
auto data_not_nullable = nullable_data ? nullable_data->getNestedColumnPtr() : const_src->getDataColumnPtr();
|
||||
return ColumnConst::create(ColumnNullable::create(data_not_nullable, result_null_map), const_src->size());
|
||||
}
|
||||
else
|
||||
return ColumnNullable::create(src->convertToFullColumnIfConst(), null_map);
|
||||
}
|
||||
|
||||
NullPresence getNullPresense(const ColumnsWithTypeAndName & args)
|
||||
{
|
||||
NullPresence res;
|
||||
|
@ -169,6 +169,11 @@ checkAndGetNestedArrayOffset(const IColumn ** columns, size_t num_arguments);
|
||||
/// Or ColumnConst(ColumnNullable) if the result is always NULL or if the result is constant and always not NULL.
|
||||
ColumnPtr wrapInNullable(const ColumnPtr & src, const ColumnsWithTypeAndName & args, const DataTypePtr & result_type, size_t input_rows_count);
|
||||
|
||||
/** Return ColumnNullable of src, with input null map
|
||||
* Or ColumnConst(ColumnNullable) if the result is always NULL or if the result is constant and always not NULL.
|
||||
*/
|
||||
ColumnPtr wrapInNullable(const ColumnPtr & src, const ColumnPtr & null_map);
|
||||
|
||||
struct NullPresence
|
||||
{
|
||||
bool has_nullable = false;
|
||||
|
@ -1,23 +1,28 @@
|
||||
#include <Functions/IFunctionAdaptors.h>
|
||||
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Core/Block.h>
|
||||
#include <Core/TypeId.h>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <Columns/ColumnConst.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <Columns/ColumnSparse.h>
|
||||
#include <Columns/ColumnNothing.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnSparse.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <Columns/MaskOperations.h>
|
||||
#include <Core/Block.h>
|
||||
#include <Core/Settings.h>
|
||||
#include <Core/TypeId.h>
|
||||
#include <DataTypes/DataTypeLowCardinality.h>
|
||||
#include <DataTypes/DataTypeNothing.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/Native.h>
|
||||
#include <DataTypes/DataTypeLowCardinality.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Common/CurrentThread.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@ -31,9 +36,9 @@ namespace DB
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -65,9 +70,7 @@ ColumnPtr replaceLowCardinalityColumnsByNestedAndGetDictionaryIndexes(
|
||||
const auto * low_cardinality_type = checkAndGetDataType<DataTypeLowCardinality>(column.type.get());
|
||||
|
||||
if (!low_cardinality_type)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
||||
"Incompatible type for LowCardinality column: {}",
|
||||
column.type->getName());
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Incompatible type for LowCardinality column: {}", column.type->getName());
|
||||
|
||||
if (can_be_executed_on_default_arguments)
|
||||
{
|
||||
@ -120,10 +123,7 @@ ColumnPtr IExecutableFunction::defaultImplementationForConstantArguments(
|
||||
/// Check that these arguments are really constant.
|
||||
for (auto arg_num : arguments_to_remain_constants)
|
||||
if (arg_num < args.size() && !isColumnConst(*args[arg_num].column))
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN,
|
||||
"Argument at index {} for function {} must be constant",
|
||||
arg_num,
|
||||
getName());
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Argument at index {} for function {} must be constant", arg_num, getName());
|
||||
|
||||
if (args.empty() || !useDefaultImplementationForConstants() || !allArgumentsAreConstants(args))
|
||||
return nullptr;
|
||||
@ -137,14 +137,16 @@ ColumnPtr IExecutableFunction::defaultImplementationForConstantArguments(
|
||||
{
|
||||
const ColumnWithTypeAndName & column = args[arg_num];
|
||||
|
||||
if (arguments_to_remain_constants.end() != std::find(arguments_to_remain_constants.begin(), arguments_to_remain_constants.end(), arg_num))
|
||||
if (arguments_to_remain_constants.end()
|
||||
!= std::find(arguments_to_remain_constants.begin(), arguments_to_remain_constants.end(), arg_num))
|
||||
{
|
||||
temporary_columns.emplace_back(ColumnWithTypeAndName{column.column->cloneResized(1), column.type, column.name});
|
||||
}
|
||||
else
|
||||
{
|
||||
have_converted_columns = true;
|
||||
temporary_columns.emplace_back(ColumnWithTypeAndName{ assert_cast<const ColumnConst *>(column.column.get())->getDataColumnPtr(), column.type, column.name });
|
||||
temporary_columns.emplace_back(
|
||||
ColumnWithTypeAndName{assert_cast<const ColumnConst *>(column.column.get())->getDataColumnPtr(), column.type, column.name});
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +154,8 @@ ColumnPtr IExecutableFunction::defaultImplementationForConstantArguments(
|
||||
* not in "arguments_to_remain_constants" set. Otherwise we get infinite recursion.
|
||||
*/
|
||||
if (!have_converted_columns)
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
throw Exception(
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"Number of arguments for function {} doesn't match: the function requires more arguments",
|
||||
getName());
|
||||
|
||||
@ -175,7 +178,7 @@ ColumnPtr IExecutableFunction::defaultImplementationForNulls(
|
||||
|
||||
NullPresence null_presence = getNullPresense(args);
|
||||
|
||||
if (null_presence.has_null_constant)
|
||||
if (null_presence.has_null_constant || null_presence.has_nullable)
|
||||
{
|
||||
// Default implementation for nulls returns null result for null arguments,
|
||||
// so the result type must be nullable.
|
||||
@ -186,17 +189,87 @@ ColumnPtr IExecutableFunction::defaultImplementationForNulls(
|
||||
"is expected to return Nullable result, got {}",
|
||||
getName(),
|
||||
result_type->getName());
|
||||
|
||||
return result_type->createColumnConstWithDefaultValue(input_rows_count);
|
||||
}
|
||||
|
||||
if (null_presence.has_null_constant)
|
||||
return result_type->createColumnConstWithDefaultValue(input_rows_count);
|
||||
|
||||
if (null_presence.has_nullable)
|
||||
{
|
||||
ColumnsWithTypeAndName temporary_columns = createBlockWithNestedColumns(args);
|
||||
auto temporary_result_type = removeNullable(result_type);
|
||||
/// Usually happens during analyzing. We should return non-const column to avoid wrong constant folding.
|
||||
if (input_rows_count == 0)
|
||||
return result_type->createColumn();
|
||||
|
||||
auto res = executeWithoutLowCardinalityColumns(temporary_columns, temporary_result_type, input_rows_count, dry_run);
|
||||
return wrapInNullable(res, args, result_type, input_rows_count);
|
||||
IColumn::Filter mask(input_rows_count, 1);
|
||||
MaskInfo mask_info = {.has_ones = true, .has_zeros = false};
|
||||
for (const auto & arg : args)
|
||||
{
|
||||
if (arg.type->isNullable())
|
||||
{
|
||||
if (isColumnConst(*arg.column))
|
||||
{
|
||||
if (arg.column->isNullAt(0))
|
||||
{
|
||||
mask_info.has_ones = false;
|
||||
mask_info.has_zeros = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto & null_map = assert_cast<const ColumnNullable &>(*arg.column).getNullMapColumnPtr();
|
||||
mask_info = extractInvertedMask(mask, null_map);
|
||||
}
|
||||
}
|
||||
|
||||
/// Exit loop early if each row contains null value
|
||||
if (!mask_info.has_ones)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mask_info.has_ones)
|
||||
{
|
||||
/// Don't need to evaluate function if each row contains at least one null value.
|
||||
return result_type->createColumnConstWithDefaultValue(input_rows_count);
|
||||
}
|
||||
else if (!mask_info.has_zeros || !short_circuit_default_implementation_for_nulls)
|
||||
{
|
||||
/// Each row should be evaluated if there are no nulls or short circuiting is disabled.
|
||||
ColumnsWithTypeAndName temporary_columns = createBlockWithNestedColumns(args);
|
||||
auto temporary_result_type = removeNullable(result_type);
|
||||
|
||||
auto res = executeWithoutLowCardinalityColumns(temporary_columns, temporary_result_type, input_rows_count, dry_run);
|
||||
|
||||
/// Invert mask as null map
|
||||
inverseMask(mask, mask_info);
|
||||
auto null_map = ColumnUInt8::create();
|
||||
null_map->getData() = std::move(mask);
|
||||
|
||||
auto new_res = wrapInNullable(res, std::move(null_map));
|
||||
return new_res;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If short circuit is enabled, we only execute the function on rows with all arguments not null
|
||||
ColumnsWithTypeAndName temporary_columns = createBlockWithNestedColumns(args);
|
||||
auto temporary_result_type = removeNullable(result_type);
|
||||
|
||||
/// Filter every column by mask
|
||||
size_t size_hint = countBytesInFilter(mask.data(), 0, mask.size());
|
||||
for (auto & col : temporary_columns)
|
||||
col.column = col.column->filter(mask, size_hint);
|
||||
|
||||
auto res = executeWithoutLowCardinalityColumns(temporary_columns, temporary_result_type, size_hint, dry_run);
|
||||
auto mutable_res = IColumn::mutate(std::move(res));
|
||||
mutable_res->expand(mask, false);
|
||||
|
||||
/// Invert mask as null map
|
||||
inverseMask(mask, mask_info);
|
||||
auto null_map = ColumnUInt8::create();
|
||||
null_map->getData() = std::move(mask);
|
||||
|
||||
auto new_res = wrapInNullable(std::move(mutable_res), std::move(null_map));
|
||||
return new_res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -258,7 +331,18 @@ static void convertSparseColumnsToFull(ColumnsWithTypeAndName & args)
|
||||
column.column = recursiveRemoveSparse(column.column);
|
||||
}
|
||||
|
||||
ColumnPtr IExecutableFunction::executeWithoutSparseColumns(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
||||
IExecutableFunction::IExecutableFunction()
|
||||
{
|
||||
if (CurrentThread::isInitialized())
|
||||
{
|
||||
auto query_context = CurrentThread::get().getQueryContext();
|
||||
if (query_context && query_context->getSettingsRef().short_circuit_default_implementation_for_nulls)
|
||||
short_circuit_default_implementation_for_nulls = true;
|
||||
}
|
||||
}
|
||||
|
||||
ColumnPtr IExecutableFunction::executeWithoutSparseColumns(
|
||||
const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
||||
{
|
||||
ColumnPtr result;
|
||||
if (useDefaultImplementationForLowCardinalityColumns())
|
||||
@ -271,19 +355,16 @@ ColumnPtr IExecutableFunction::executeWithoutSparseColumns(const ColumnsWithType
|
||||
|
||||
const auto & dictionary_type = res_low_cardinality_type->getDictionaryType();
|
||||
ColumnPtr indexes = replaceLowCardinalityColumnsByNestedAndGetDictionaryIndexes(
|
||||
columns_without_low_cardinality, can_be_executed_on_default_arguments, input_rows_count);
|
||||
columns_without_low_cardinality, can_be_executed_on_default_arguments, input_rows_count);
|
||||
|
||||
size_t new_input_rows_count = columns_without_low_cardinality.empty()
|
||||
? input_rows_count
|
||||
: columns_without_low_cardinality.front().column->size();
|
||||
size_t new_input_rows_count
|
||||
= columns_without_low_cardinality.empty() ? input_rows_count : columns_without_low_cardinality.front().column->size();
|
||||
checkFunctionArgumentSizes(columns_without_low_cardinality, new_input_rows_count);
|
||||
|
||||
auto res = executeWithoutLowCardinalityColumns(columns_without_low_cardinality, dictionary_type, new_input_rows_count, dry_run);
|
||||
bool res_is_constant = isColumnConst(*res);
|
||||
|
||||
auto keys = res_is_constant
|
||||
? res->cloneResized(1)->convertToFullColumnIfConst()
|
||||
: res;
|
||||
auto keys = res_is_constant ? res->cloneResized(1)->convertToFullColumnIfConst() : res;
|
||||
|
||||
auto res_mut_dictionary = DataTypeLowCardinality::createColumnUnique(*res_low_cardinality_type->getDictionaryType());
|
||||
ColumnPtr res_indexes = res_mut_dictionary->uniqueInsertRangeFrom(*keys, 0, keys->size());
|
||||
@ -309,7 +390,8 @@ ColumnPtr IExecutableFunction::executeWithoutSparseColumns(const ColumnsWithType
|
||||
return result;
|
||||
}
|
||||
|
||||
ColumnPtr IExecutableFunction::execute(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
||||
ColumnPtr IExecutableFunction::execute(
|
||||
const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const
|
||||
{
|
||||
checkFunctionArgumentSizes(arguments, input_rows_count);
|
||||
|
||||
@ -370,7 +452,7 @@ ColumnPtr IExecutableFunction::execute(const ColumnsWithTypeAndName & arguments,
|
||||
if (!result_type->canBeInsideSparseColumns() || !res->isDefaultAt(0) || res->getNumberOfDefaultRows() != 1)
|
||||
{
|
||||
const auto & offsets_data = assert_cast<const ColumnVector<UInt64> &>(*sparse_offsets).getData();
|
||||
return res->createWithOffsets(offsets_data, *createColumnConst(res, 0), input_rows_count, /*shift=*/ 1);
|
||||
return res->createWithOffsets(offsets_data, *createColumnConst(res, 0), input_rows_count, /*shift=*/1);
|
||||
}
|
||||
|
||||
return ColumnSparse::create(res, sparse_offsets, input_rows_count);
|
||||
@ -397,7 +479,8 @@ void IFunctionOverloadResolver::checkNumberOfArguments(size_t number_of_argument
|
||||
size_t expected_number_of_arguments = getNumberOfArguments();
|
||||
|
||||
if (number_of_arguments != expected_number_of_arguments)
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
throw Exception(
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"Number of arguments for function {} doesn't match: passed {}, should be {}",
|
||||
getName(),
|
||||
number_of_arguments,
|
||||
@ -436,9 +519,8 @@ DataTypePtr IFunctionOverloadResolver::getReturnType(const ColumnsWithTypeAndNam
|
||||
|
||||
auto type_without_low_cardinality = getReturnTypeWithoutLowCardinality(args_without_low_cardinality);
|
||||
|
||||
if (canBeExecutedOnLowCardinalityDictionary() && has_low_cardinality
|
||||
&& num_full_low_cardinality_columns <= 1 && num_full_ordinary_columns == 0
|
||||
&& type_without_low_cardinality->canBeInsideLowCardinality())
|
||||
if (canBeExecutedOnLowCardinalityDictionary() && has_low_cardinality && num_full_low_cardinality_columns <= 1
|
||||
&& num_full_ordinary_columns == 0 && type_without_low_cardinality->canBeInsideLowCardinality())
|
||||
return std::make_shared<DataTypeLowCardinality>(type_without_low_cardinality);
|
||||
else
|
||||
return type_without_low_cardinality;
|
||||
@ -545,7 +627,7 @@ llvm::Value * IFunction::compile(llvm::IRBuilderBase & builder, const ValuesWith
|
||||
ValuesWithType unwrapped_arguments;
|
||||
unwrapped_arguments.reserve(arguments.size());
|
||||
|
||||
std::vector<llvm::Value*> is_null_values;
|
||||
std::vector<llvm::Value *> is_null_values;
|
||||
|
||||
for (size_t i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
|
@ -45,6 +45,7 @@ using OptionalFieldInterval = std::optional<FieldInterval>;
|
||||
class IExecutableFunction
|
||||
{
|
||||
public:
|
||||
IExecutableFunction();
|
||||
|
||||
virtual ~IExecutableFunction() = default;
|
||||
|
||||
@ -120,6 +121,8 @@ private:
|
||||
|
||||
ColumnPtr executeWithoutSparseColumns(
|
||||
const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, bool dry_run) const;
|
||||
|
||||
bool short_circuit_default_implementation_for_nulls = false;
|
||||
};
|
||||
|
||||
using ExecutableFunctionPtr = std::shared_ptr<IExecutableFunction>;
|
||||
|
Loading…
Reference in New Issue
Block a user