1#pragma once
2
3#include <Common/typeid_cast.h>
4#include <Common/assert_cast.h>
5#include <DataTypes/IDataType.h>
6#include <Columns/IColumn.h>
7#include <Columns/ColumnArray.h>
8#include <Columns/ColumnConst.h>
9#include <Core/Block.h>
10#include <Core/ColumnNumbers.h>
11#include <Core/callOnTypeIndex.h>
12
13
14namespace DB
15{
16
17class IFunction;
18
19/// Methods, that helps dispatching over real column types.
20
21template <typename Type>
22const Type * checkAndGetDataType(const IDataType * data_type)
23{
24 return typeid_cast<const Type *>(data_type);
25}
26
27template <typename Type>
28const ColumnConst * checkAndGetColumnConst(const IColumn * column)
29{
30 if (!column || !isColumnConst(*column))
31 return {};
32
33 const ColumnConst * res = assert_cast<const ColumnConst *>(column);
34
35 if (!checkColumn<Type>(&res->getDataColumn()))
36 return {};
37
38 return res;
39}
40
41template <typename Type>
42const Type * checkAndGetColumnConstData(const IColumn * column)
43{
44 const ColumnConst * res = checkAndGetColumnConst<Type>(column);
45
46 if (!res)
47 return {};
48
49 return static_cast<const Type *>(&res->getDataColumn());
50}
51
52template <typename Type>
53bool checkColumnConst(const IColumn * column)
54{
55 return checkAndGetColumnConst<Type>(column);
56}
57
58/// Returns non-nullptr if column is ColumnConst with ColumnString or ColumnFixedString inside.
59const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column);
60
61
62/// Transform anything to Field.
63template <typename T>
64inline std::enable_if_t<!IsDecimalNumber<T>, Field> toField(const T & x)
65{
66 return Field(NearestFieldType<T>(x));
67}
68
69template <typename T>
70inline std::enable_if_t<IsDecimalNumber<T>, Field> toField(const T & x, UInt32 scale)
71{
72 return Field(NearestFieldType<T>(x, scale));
73}
74
75
76Columns convertConstTupleToConstantElements(const ColumnConst & column);
77
78
79/// Returns the copy of a given block in which each column specified in
80/// the "arguments" parameter is replaced with its respective nested
81/// column if it is nullable.
82Block createBlockWithNestedColumns(const Block & block, const ColumnNumbers & args);
83
84/// Similar function as above. Additionally transform the result type if needed.
85Block createBlockWithNestedColumns(const Block & block, const ColumnNumbers & args, size_t result);
86
87/// Checks argument type at specified index with predicate.
88/// throws if there is no argument at specified index or if predicate returns false.
89void validateArgumentType(const IFunction & func, const DataTypes & arguments,
90 size_t argument_index, bool (* validator_func)(const IDataType &),
91 const char * expected_type_description);
92
93/** Simple validator that is used in conjunction with validateFunctionArgumentTypes() to check if function arguments are as expected
94 *
95 * Also it is used to generate function description when arguments do not match expected ones.
96 * Any field can be null:
97 * `argument_name` - if not null, reported via type check errors.
98 * `expected_type_description` - if not null, reported via type check errors.
99 * `type_validator_func` - if not null, used to validate data type of function argument.
100 * `column_validator_func` - if not null, used to validate column of function argument.
101 */
102struct FunctionArgumentDescriptor
103{
104 const char * argument_name;
105
106 bool (* type_validator_func)(const IDataType &);
107 bool (* column_validator_func)(const IColumn &);
108
109 const char * expected_type_description;
110
111 /** Validate argument type and column.
112 *
113 * Returns non-zero error code if:
114 * Validator != nullptr && (Value == nullptr || Validator(*Value) == false)
115 * For:
116 * Validator is either `type_validator_func` or `column_validator_func`
117 * Value is either `data_type` or `column` respectively.
118 * ILLEGAL_TYPE_OF_ARGUMENT if type validation fails
119 *
120 */
121 int isValid(const DataTypePtr & data_type, const ColumnPtr & column) const;
122};
123
124using FunctionArgumentDescriptors = std::vector<FunctionArgumentDescriptor>;
125
126/** Validate that function arguments match specification.
127 *
128 * Designed to simplify argument validation for functions with variable arguments
129 * (e.g. depending on result type or other trait).
130 * First, checks that number of arguments is as expected (including optional arguments).
131 * Second, checks that mandatory args present and have valid type.
132 * Third, checks optional arguents types, skipping ones that are missing.
133 *
134 * Please note that if you have several optional arguments, like f([a, b, c]),
135 * only these calls are considered valid:
136 * f(a)
137 * f(a, b)
138 * f(a, b, c)
139 *
140 * But NOT these: f(a, c), f(b, c)
141 * In other words you can't omit middle optional arguments (just like in regular C++).
142 *
143 * If any mandatory arg is missing, throw an exception, with explicit description of expected arguments.
144 */
145void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments,
146 const FunctionArgumentDescriptors & mandatory_args,
147 const FunctionArgumentDescriptors & optional_args = {});
148
149/// Checks if a list of array columns have equal offsets. Return a pair of nested columns and offsets if true, otherwise throw.
150std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *>
151checkAndGetNestedArrayOffset(const IColumn ** columns, size_t num_arguments);
152
153}
154