| 950 | } |
| 951 | |
| 952 | ColumnPtr FunctionArrayElement::executeMap( |
| 953 | const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count, ColumnPtr index_null_map_col) const |
| 954 | { |
| 955 | const auto * col_map = checkAndGetColumn<ColumnMap>(arguments[0].column.get()); |
| 956 | const auto * col_const_map = checkAndGetColumnConst<ColumnMap>(arguments[0].column.get()); |
| 957 | const DataTypeMap * map_type = checkAndGetDataType<DataTypeMap>(arguments[0].type.get()); |
| 958 | if ((!col_map && !col_const_map) || !map_type) |
| 959 | return nullptr; |
| 960 | |
| 961 | if (col_const_map) |
| 962 | col_map = typeid_cast<const ColumnMap *>(&col_const_map->getDataColumn()); |
| 963 | |
| 964 | const auto & nested_column = col_map->getNestedColumn(); |
| 965 | const auto & keys_data = col_map->getNestedData().getColumn(0); |
| 966 | const auto & values_data = col_map->getNestedData().getColumn(1); |
| 967 | const auto & offsets = nested_column.getOffsets(); |
| 968 | |
| 969 | /// At first step calculate indices in array of values for requested keys. |
| 970 | auto indices_column = DataTypeNumber<UInt64>().createColumn(); |
| 971 | indices_column->reserve(input_rows_count); |
| 972 | auto & indices_data = assert_cast<ColumnVector<UInt64> &>(*indices_column).getData(); |
| 973 | |
| 974 | bool executed = false; |
| 975 | if (!isColumnConst(*arguments[1].column)) |
| 976 | { |
| 977 | executed = matchKeyToIndexNumber(keys_data, offsets, !!col_const_map, *arguments[1].column, indices_data) |
| 978 | || matchKeyToIndexString(keys_data, offsets, !!col_const_map, *arguments[1].column, indices_data); |
| 979 | } |
| 980 | else |
| 981 | { |
| 982 | Field index = (*arguments[1].column)[0]; |
| 983 | |
| 984 | /// try convert const index to right type |
| 985 | auto index_lit = std::make_shared<ASTLiteral>(index); |
| 986 | Field key_field = tryConvertToMapKeyField(map_type->getKeyType(), index_lit->getColumnName()); |
| 987 | if (!key_field.isNull()) |
| 988 | index = key_field; |
| 989 | |
| 990 | executed = matchKeyToIndexNumberConst(keys_data, offsets, index, indices_data) |
| 991 | || matchKeyToIndexStringConst(keys_data, offsets, index, indices_data); |
| 992 | } |
| 993 | |
| 994 | if (!executed) |
| 995 | throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, |
| 996 | "Illegal types of arguments: {}, {} for function {}", |
| 997 | arguments[0].type->getName(), arguments[1].type->getName(), getName()); |
| 998 | |
| 999 | ColumnPtr values_array_nested = values_data.getPtr(); |
| 1000 | DataTypePtr result_value_type = map_type->getValueType(); |
| 1001 | |
| 1002 | // TODO(shiyuze): Map can be nested in Map but cannot wrapped in Nullable |
| 1003 | if (is_mysql_dialect && result_type->isNullable()) |
| 1004 | { |
| 1005 | /// In MYSQL dialect type, non-exists indices will return Null, so we need to wrap |
| 1006 | /// new arguments in nullable |
| 1007 | values_array_nested = makeNullable(values_array_nested); |
| 1008 | result_value_type = makeNullable(result_value_type); |
| 1009 | } |
nothing calls this directly
no test coverage detected