| 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 |  | 
|---|
| 14 | namespace DB | 
|---|
| 15 | { | 
|---|
| 16 |  | 
|---|
| 17 | class IFunction; | 
|---|
| 18 |  | 
|---|
| 19 | /// Methods, that helps dispatching over real column types. | 
|---|
| 20 |  | 
|---|
| 21 | template <typename Type> | 
|---|
| 22 | const Type * checkAndGetDataType(const IDataType * data_type) | 
|---|
| 23 | { | 
|---|
| 24 | return typeid_cast<const Type *>(data_type); | 
|---|
| 25 | } | 
|---|
| 26 |  | 
|---|
| 27 | template <typename Type> | 
|---|
| 28 | const 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 |  | 
|---|
| 41 | template <typename Type> | 
|---|
| 42 | const 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 |  | 
|---|
| 52 | template <typename Type> | 
|---|
| 53 | bool 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. | 
|---|
| 59 | const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column); | 
|---|
| 60 |  | 
|---|
| 61 |  | 
|---|
| 62 | /// Transform anything to Field. | 
|---|
| 63 | template <typename T> | 
|---|
| 64 | inline std::enable_if_t<!IsDecimalNumber<T>, Field> toField(const T & x) | 
|---|
| 65 | { | 
|---|
| 66 | return Field(NearestFieldType<T>(x)); | 
|---|
| 67 | } | 
|---|
| 68 |  | 
|---|
| 69 | template <typename T> | 
|---|
| 70 | inline std::enable_if_t<IsDecimalNumber<T>, Field> toField(const T & x, UInt32 scale) | 
|---|
| 71 | { | 
|---|
| 72 | return Field(NearestFieldType<T>(x, scale)); | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 |  | 
|---|
| 76 | Columns 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. | 
|---|
| 82 | Block createBlockWithNestedColumns(const Block & block, const ColumnNumbers & args); | 
|---|
| 83 |  | 
|---|
| 84 | /// Similar function as above. Additionally transform the result type if needed. | 
|---|
| 85 | Block 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. | 
|---|
| 89 | void 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 | */ | 
|---|
| 102 | struct 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 |  | 
|---|
| 124 | using 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 | */ | 
|---|
| 145 | void 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. | 
|---|
| 150 | std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *> | 
|---|
| 151 | checkAndGetNestedArrayOffset(const IColumn ** columns, size_t num_arguments); | 
|---|
| 152 |  | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|