Skip to content

Commit 3557232

Browse files
authored
Merge pull request #48207 from bigo-sg/map_from_maps
2 parents 0524439 + 3bd29f0 commit 3557232

File tree

4 files changed

+48
-26
lines changed

4 files changed

+48
-26
lines changed

docs/en/sql-reference/functions/tuple-map-functions.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ Result:
6868

6969
## mapFromArrays
7070

71-
Merges an [Array](../../sql-reference/data-types/array.md) of keys and an [Array](../../sql-reference/data-types/array.md) of values into a [Map(key, value)](../../sql-reference/data-types/map.md).
71+
Merges an [Array](../../sql-reference/data-types/array.md) of keys and an [Array](../../sql-reference/data-types/array.md) of values into a [Map(key, value)](../../sql-reference/data-types/map.md). Notice that the second argument could also be a [Map](../../sql-reference/data-types/map.md), thus it is casted to an Array when executing.
7272

73-
The function is a more convenient alternative to `CAST((key_array, value_array), 'Map(key_type, value_type)')`. For example, instead of writing `CAST((['aa', 'bb'], [4, 5]), 'Map(String, UInt32)')`, you can write `mapFromArrays(['aa', 'bb'], [4, 5])`.
73+
The function is a more convenient alternative to `CAST((key_array, value_array_or_map), 'Map(key_type, value_type)')`. For example, instead of writing `CAST((['aa', 'bb'], [4, 5]), 'Map(String, UInt32)')`, you can write `mapFromArrays(['aa', 'bb'], [4, 5])`.
7474

7575
**Syntax**
7676

@@ -82,25 +82,29 @@ Alias: `MAP_FROM_ARRAYS(keys, values)`
8282

8383
**Arguments**
8484
- `keys` — Given key array to create a map from. The nested type of array must be: [String](../../sql-reference/data-types/string.md), [Integer](../../sql-reference/data-types/int-uint.md), [LowCardinality](../../sql-reference/data-types/lowcardinality.md), [FixedString](../../sql-reference/data-types/fixedstring.md), [UUID](../../sql-reference/data-types/uuid.md), [Date](../../sql-reference/data-types/date.md), [DateTime](../../sql-reference/data-types/datetime.md), [Date32](../../sql-reference/data-types/date32.md), [Enum](../../sql-reference/data-types/enum.md)
85-
- `values` - Given value array to create a map from.
85+
- `values` - Given value array or map to create a map from.
8686

8787
**Returned value**
8888

89-
- A map whose keys and values are constructed from the key and value arrays
89+
- A map whose keys and values are constructed from the key array and value array/map.
9090

9191
**Example**
9292

9393
Query:
9494

9595
```sql
9696
select mapFromArrays(['a', 'b', 'c'], [1, 2, 3])
97-
```
98-
99-
```text
97+
10098
┌─mapFromArrays(['a', 'b', 'c'], [1, 2, 3])─┐
10199
│ {'a':1,'b':2,'c':3} │
102100
└───────────────────────────────────────────┘
103-
```
101+
102+
SELECT mapFromArrays([1, 2, 3], map('a', 1, 'b', 2, 'c', 3))
103+
104+
┌─mapFromArrays([1, 2, 3], map('a', 1, 'b', 2, 'c', 3))─┐
105+
│ {1:('a',1),2:('b',2),3:('c',3)} │
106+
└───────────────────────────────────────────────────────┘
107+
```
104108

105109
## mapAdd
106110

src/Functions/map.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,31 @@ class FunctionMapFromArrays : public IFunction
174174
getName(),
175175
arguments.size());
176176

177-
const auto * keys_type = checkAndGetDataType<DataTypeArray>(arguments[0].get());
178-
if (!keys_type)
177+
/// The first argument should always be Array.
178+
/// Because key type can not be nested type of Map, which is Tuple
179+
DataTypePtr key_type;
180+
if (const auto * keys_type = checkAndGetDataType<DataTypeArray>(arguments[0].get()))
181+
key_type = keys_type->getNestedType();
182+
else
179183
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "First argument for function {} must be an Array", getName());
180184

181-
const auto * values_type = checkAndGetDataType<DataTypeArray>(arguments[1].get());
182-
if (!values_type)
183-
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Second argument for function {} must be an Array", getName());
185+
DataTypePtr value_type;
186+
if (const auto * value_array_type = checkAndGetDataType<DataTypeArray>(arguments[1].get()))
187+
value_type = value_array_type->getNestedType();
188+
else if (const auto * value_map_type = checkAndGetDataType<DataTypeMap>(arguments[1].get()))
189+
value_type = std::make_shared<DataTypeTuple>(value_map_type->getKeyValueTypes());
190+
else
191+
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Second argument for function {} must be Array or Map", getName());
184192

185-
DataTypes key_value_types{keys_type->getNestedType(), values_type->getNestedType()};
193+
DataTypes key_value_types{key_type, value_type};
186194
return std::make_shared<DataTypeMap>(key_value_types);
187195
}
188196

189197
ColumnPtr executeImpl(
190198
const ColumnsWithTypeAndName & arguments, const DataTypePtr & /* result_type */, size_t /* input_rows_count */) const override
191199
{
192-
ColumnPtr holder_keys;
193200
bool is_keys_const = isColumnConst(*arguments[0].column);
201+
ColumnPtr holder_keys;
194202
const ColumnArray * col_keys;
195203
if (is_keys_const)
196204
{
@@ -202,24 +210,26 @@ class FunctionMapFromArrays : public IFunction
202210
col_keys = checkAndGetColumn<ColumnArray>(arguments[0].column.get());
203211
}
204212

205-
ColumnPtr holder_values;
213+
if (!col_keys)
214+
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "The first argument of function {} must be Array", getName());
215+
206216
bool is_values_const = isColumnConst(*arguments[1].column);
207-
const ColumnArray * col_values;
217+
ColumnPtr holder_values;
208218
if (is_values_const)
209-
{
210219
holder_values = arguments[1].column->convertToFullColumnIfConst();
211-
col_values = checkAndGetColumn<ColumnArray>(holder_values.get());
212-
}
213220
else
214-
{
215-
col_values = checkAndGetColumn<ColumnArray>(arguments[1].column.get());
216-
}
221+
holder_values = arguments[1].column;
217222

218-
if (!col_keys || !col_values)
219-
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Arguments of function {} must be array", getName());
223+
const ColumnArray * col_values;
224+
if (const auto * col_values_array = checkAndGetColumn<ColumnArray>(holder_values.get()))
225+
col_values = col_values_array;
226+
else if (const auto * col_values_map = checkAndGetColumn<ColumnMap>(holder_values.get()))
227+
col_values = &col_values_map->getNestedColumn();
228+
else
229+
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "The second arguments of function {} must be Array or Map", getName());
220230

221231
if (!col_keys->hasEqualOffsets(*col_values))
222-
throw Exception(ErrorCodes::SIZES_OF_ARRAYS_DONT_MATCH, "Array arguments for function {} must have equal sizes", getName());
232+
throw Exception(ErrorCodes::SIZES_OF_ARRAYS_DONT_MATCH, "Two arguments for function {} must have equal sizes", getName());
223233

224234
const auto & data_keys = col_keys->getDataPtr();
225235
const auto & data_values = col_values->getDataPtr();

tests/queries/0_stateless/01651_map_functions.reference

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@
3333
{'aa':4,'bb':5}
3434
{'aa':4,'bb':5}
3535
{'aa':4,'bb':5}
36+
{'aa':('a',4),'bb':('b',5)}
37+
{'aa':('a',4),'bb':('b',5)}
38+
{'aa':('a',4),'bb':('b',5)}

tests/queries/0_stateless/01651_map_functions.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,8 @@ select mapFromArrays(['aa', 'bb'], 5); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT
3939
select mapFromArrays(['aa', 'bb'], [4, 5], [6, 7]); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
4040
select mapFromArrays(['aa', 'bb'], [4, 5, 6]); -- { serverError SIZES_OF_ARRAYS_DONT_MATCH }
4141
select mapFromArrays([[1,2], [3,4]], [4, 5, 6]); -- { serverError BAD_ARGUMENTS }
42+
43+
select mapFromArrays(['aa', 'bb'], map('a', 4, 'b', 5));
44+
select mapFromArrays(['aa', 'bb'], materialize(map('a', 4, 'b', 5))) from numbers(2);
45+
select mapFromArrays(map('a', 4, 'b', 4), ['aa', 'bb']) from numbers(2); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
46+
select mapFromArrays(['aa', 'bb'], map('a', 4)); -- { serverError SIZES_OF_ARRAYS_DONT_MATCH }

0 commit comments

Comments
 (0)