should be it
This commit is contained in:
354
external/duckdb/test/sql/cast/struct_to_map.test
vendored
Normal file
354
external/duckdb/test/sql/cast/struct_to_map.test
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
# name: test/sql/cast/struct_to_map.test
|
||||
# group: [cast]
|
||||
|
||||
# enable query verification
|
||||
statement ok
|
||||
PRAGMA enable_verification
|
||||
|
||||
# Basic functionality tests
|
||||
|
||||
# Simple cast - VARCHAR keys to VARCHAR values
|
||||
query I
|
||||
SELECT {"name": 'Alice', "city": 'NYC'}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{name=Alice, city=NYC}
|
||||
|
||||
# Simple cast - VARCHAR keys to INT values
|
||||
query I
|
||||
SELECT {"age": 25, "score": 100}::MAP(VARCHAR, INT);
|
||||
----
|
||||
{age=25, score=100}
|
||||
|
||||
# Multiple rows with same field structure
|
||||
query I
|
||||
SELECT col::MAP(VARCHAR, INT)
|
||||
FROM VALUES ({"duck": 1}),({"duck": 2}),({"duck": 3}),({"duck": 4}),({"duck": 5})
|
||||
AS tab(col);
|
||||
----
|
||||
{duck=1}
|
||||
{duck=2}
|
||||
{duck=3}
|
||||
{duck=4}
|
||||
{duck=5}
|
||||
|
||||
# Multiple fields in a single struct
|
||||
query I
|
||||
SELECT {"name": 'Alice', "age": 25, "score": 95}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{name=Alice, age=25, score=95}
|
||||
|
||||
# Key type casting tests
|
||||
|
||||
# Cast VARCHAR keys to INT keys (keeps null values)
|
||||
query I
|
||||
SELECT col::MAP(INT, INT)
|
||||
FROM VALUES ({"1": 1}),({"2": 2}),({"3": 3}),({"4": 4}),({"5": 5})
|
||||
AS tab(col);
|
||||
----
|
||||
{1=1, 2=NULL, 3=NULL, 4=NULL, 5=NULL}
|
||||
{1=NULL, 2=2, 3=NULL, 4=NULL, 5=NULL}
|
||||
{1=NULL, 2=NULL, 3=3, 4=NULL, 5=NULL}
|
||||
{1=NULL, 2=NULL, 3=NULL, 4=4, 5=NULL}
|
||||
{1=NULL, 2=NULL, 3=NULL, 4=NULL, 5=5}
|
||||
|
||||
# Cast VARCHAR keys to BIGINT keys
|
||||
query I
|
||||
SELECT {"123456789": 42}::MAP(BIGINT, INT);
|
||||
----
|
||||
{123456789=42}
|
||||
|
||||
# Cast VARCHAR keys to DOUBLE keys
|
||||
query I
|
||||
SELECT {"3.14": 100}::MAP(DOUBLE, INT);
|
||||
----
|
||||
{3.14=100}
|
||||
|
||||
# Value type casting tests
|
||||
|
||||
# Cast INT values to VARCHAR
|
||||
query I
|
||||
SELECT {"age": 25, "score": 100}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{age=25, score=100}
|
||||
|
||||
# Cast different numeric types to BIGINT
|
||||
query I
|
||||
SELECT {"small": 1, "big": 999999999}::MAP(VARCHAR, BIGINT);
|
||||
----
|
||||
{small=1, big=999999999}
|
||||
|
||||
# Cast to DOUBLE values
|
||||
query I
|
||||
SELECT {"pi": 3, "e": 2}::MAP(VARCHAR, DOUBLE);
|
||||
----
|
||||
{pi=3.0, e=2.0}
|
||||
|
||||
# Mixed type casting - both keys and values
|
||||
query I
|
||||
SELECT {"1": 100, "2": 200}::MAP(INT, BIGINT);
|
||||
----
|
||||
{1=100, 2=200}
|
||||
|
||||
# NULL handling tests
|
||||
|
||||
# NULL struct becomes NULL map
|
||||
query I
|
||||
SELECT (NULL::STRUCT(name VARCHAR, age INT))::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
NULL
|
||||
|
||||
# NULL field values are preserved
|
||||
query I
|
||||
SELECT {"name": 'Alice', "age": NULL}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{name=Alice, age=NULL}
|
||||
|
||||
# Multiple NULL values
|
||||
query I
|
||||
SELECT {"a": NULL, "b": NULL, "c": 'value'}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{a=NULL, b=NULL, c=value}
|
||||
|
||||
# Constant vector tests
|
||||
|
||||
# Single constant struct
|
||||
query I
|
||||
SELECT x::MAP(VARCHAR, INT) FROM (SELECT {"constant": 42} as x FROM range(5));
|
||||
----
|
||||
{constant=42}
|
||||
{constant=42}
|
||||
{constant=42}
|
||||
{constant=42}
|
||||
{constant=42}
|
||||
|
||||
# Complex nested type tests
|
||||
|
||||
# STRUCT values to STRUCT values
|
||||
query I
|
||||
SELECT {"person": {"name": 'Alice', "age": 25}}::MAP(VARCHAR, STRUCT(name VARCHAR, age INT));
|
||||
----
|
||||
{person={'name': Alice, 'age': 25}}
|
||||
|
||||
# LIST values to LIST values
|
||||
query I
|
||||
SELECT {"numbers": [1,2,3], "letters": ['a','b']}::MAP(VARCHAR, VARCHAR[]);
|
||||
----
|
||||
{numbers=[1, 2, 3], letters=[a, b]}
|
||||
|
||||
# Nested MAP values
|
||||
query I
|
||||
SELECT {meta: MAP{'key': 'value'}}::MAP(VARCHAR, MAP(VARCHAR, VARCHAR));
|
||||
----
|
||||
{meta={key=value}}
|
||||
|
||||
# Complex nested structure
|
||||
query I
|
||||
SELECT col::MAP(VARCHAR, MAP(VARCHAR, INT))
|
||||
FROM VALUES ({ data: MAP{'count': 10, 'total': 100} })
|
||||
AS tab(col);
|
||||
----
|
||||
{data={count=10, total=100}}
|
||||
|
||||
# Edge cases
|
||||
|
||||
# Constant vector select
|
||||
query I
|
||||
SELECT {"value": 42}::MAP(VARCHAR, INT)
|
||||
FROM range(1, 1001)
|
||||
LIMIT 5;
|
||||
----
|
||||
{value=42}
|
||||
{value=42}
|
||||
{value=42}
|
||||
{value=42}
|
||||
{value=42}
|
||||
|
||||
# Make sure nothing breaks if we change the vector type
|
||||
statement ok
|
||||
pragma debug_verify_vector='dictionary_expression'
|
||||
|
||||
query I
|
||||
SELECT TRY_CAST(col AS MAP(VARCHAR, integer))
|
||||
FROM (
|
||||
SELECT CASE WHEN (i % 5 == 0) THEN NULL else {'a': i::varchar} END as col
|
||||
FROM range(1, 1001) t(i)
|
||||
)
|
||||
LIMIT 5;
|
||||
----
|
||||
{a=1}
|
||||
{a=2}
|
||||
{a=3}
|
||||
{a=4}
|
||||
NULL
|
||||
|
||||
statement ok
|
||||
pragma debug_verify_vector='none'
|
||||
|
||||
# Single field struct
|
||||
query I
|
||||
SELECT {"single": 'value'}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{single=value}
|
||||
|
||||
# Large number of fields
|
||||
query I
|
||||
SELECT {
|
||||
"f1": 1, "f2": 2, "f3": 3, "f4": 4, "f5": 5,
|
||||
"f6": 6, "f7": 7, "f8": 8, "f9": 9, "f10": 10
|
||||
}::MAP(VARCHAR, INT);
|
||||
----
|
||||
{f1=1, f2=2, f3=3, f4=4, f5=5, f6=6, f7=7, f8=8, f9=9, f10=10}
|
||||
|
||||
# Error cases
|
||||
|
||||
# Cannot cast unnamed struct to MAP
|
||||
statement error
|
||||
SELECT (1, 2, 3)::MAP(INT, INT);
|
||||
----
|
||||
Cannot cast unnamed STRUCTs to MAP
|
||||
|
||||
# Key casting can fail
|
||||
statement error
|
||||
SELECT col::MAP(INT, INT)
|
||||
FROM VALUES ({"duck": 1}),({"goose": 2})
|
||||
AS tab(col);
|
||||
----
|
||||
Conversion Error: Could not convert string 'duck' to INT32
|
||||
|
||||
# Value casting can fail
|
||||
statement error
|
||||
SELECT {"number": 'not_a_number'}::MAP(VARCHAR, INT);
|
||||
----
|
||||
Conversion Error: Could not convert string 'not_a_number' to INT32
|
||||
|
||||
# Special character handling in keys
|
||||
|
||||
# Keys with spaces
|
||||
query I
|
||||
SELECT {"first name": 'Alice', "last name": 'Smith'}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{first name=Alice, last name=Smith}
|
||||
|
||||
# Keys with special characters
|
||||
query I
|
||||
SELECT {"key-with-dashes": 1, "key_with_underscores": 2, "key.with.dots": 3}::MAP(VARCHAR, INT);
|
||||
----
|
||||
{key-with-dashes=1, key_with_underscores=2, key.with.dots=3}
|
||||
|
||||
# Unicode keys
|
||||
query I
|
||||
SELECT {"测试": 'test', "🦆": 'duck'}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{测试=test, 🦆=duck}
|
||||
|
||||
# Case sensitivity preservation
|
||||
query I
|
||||
SELECT {"CamelCase": 1, "lowercase": 2, "UPPERCASE": 3}::MAP(VARCHAR, INT);
|
||||
----
|
||||
{CamelCase=1, lowercase=2, UPPERCASE=3}
|
||||
|
||||
# Performance and batching tests
|
||||
|
||||
# Large batch of rows
|
||||
query I
|
||||
SELECT col::MAP(VARCHAR, INT)
|
||||
FROM (
|
||||
SELECT {"value": i} as col
|
||||
FROM range(1, 1001) t(i)
|
||||
)
|
||||
LIMIT 5;
|
||||
----
|
||||
{value=1}
|
||||
{value=2}
|
||||
{value=3}
|
||||
{value=4}
|
||||
{value=5}
|
||||
|
||||
# Mixed field counts across rows
|
||||
query I
|
||||
SELECT col::MAP(VARCHAR, VARCHAR)
|
||||
FROM VALUES
|
||||
({"a": '1'}),
|
||||
({"A": '1', "b": '2'}),
|
||||
({"a": '1', "B": '2', "c": '3'}),
|
||||
({"x": 'single'}),
|
||||
({"many": '1', "fields": '2', "here": '3', "total": '4', "five": '5'})
|
||||
AS tab(col);
|
||||
----
|
||||
{a=1, b=NULL, c=NULL, x=NULL, many=NULL, fields=NULL, here=NULL, total=NULL, five=NULL}
|
||||
{a=1, b=2, c=NULL, x=NULL, many=NULL, fields=NULL, here=NULL, total=NULL, five=NULL}
|
||||
{a=1, b=2, c=3, x=NULL, many=NULL, fields=NULL, here=NULL, total=NULL, five=NULL}
|
||||
{a=NULL, b=NULL, c=NULL, x=single, many=NULL, fields=NULL, here=NULL, total=NULL, five=NULL}
|
||||
{a=NULL, b=NULL, c=NULL, x=NULL, many=1, fields=2, here=3, total=4, five=5}
|
||||
|
||||
# Type compatibility tests
|
||||
|
||||
# All numeric types as values
|
||||
query I
|
||||
SELECT {
|
||||
"tinyint": 1::TINYINT,
|
||||
"smallint": 2::SMALLINT,
|
||||
"int": 3::INT,
|
||||
"bigint": 4::BIGINT
|
||||
}::MAP(VARCHAR, BIGINT);
|
||||
----
|
||||
{tinyint=1, smallint=2, int=3, bigint=4}
|
||||
|
||||
# String types as values
|
||||
query I
|
||||
SELECT {
|
||||
"varchar": 'hello'::VARCHAR,
|
||||
"text": 'world'::TEXT
|
||||
}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{varchar=hello, text=world}
|
||||
|
||||
# Date/time types as values
|
||||
query I
|
||||
SELECT {
|
||||
"date": '2023-01-01'::DATE,
|
||||
"time": '12:00:00'::TIME
|
||||
}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{date=2023-01-01, time='12:00:00'}
|
||||
|
||||
# Boolean values
|
||||
query I
|
||||
SELECT {"true_val": true, "false_val": false}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{true_val=true, false_val=false}
|
||||
|
||||
# Decimal values
|
||||
query I
|
||||
SELECT {"price": 19.99::DECIMAL(10,2)}::MAP(VARCHAR, VARCHAR);
|
||||
----
|
||||
{price=19.99}
|
||||
|
||||
# Interoperability tests
|
||||
|
||||
# Use in WHERE clause
|
||||
query I
|
||||
SELECT *
|
||||
FROM VALUES ({"status": 'active'}), ({"status": 'inactive'})
|
||||
AS tab(col)
|
||||
WHERE (col::MAP(VARCHAR, VARCHAR))['status'] = 'active';
|
||||
----
|
||||
{'status': active}
|
||||
|
||||
# Use in aggregations
|
||||
query I
|
||||
SELECT COUNT(*)
|
||||
FROM VALUES ({"type": 'A'}), ({"type": 'B'}), ({"type": 'A'})
|
||||
AS tab(col)
|
||||
WHERE (col::MAP(VARCHAR, VARCHAR))['type'] = 'A';
|
||||
----
|
||||
2
|
||||
|
||||
# Complex nested example from original test
|
||||
query I
|
||||
SELECT col::MAP(VARCHAR, MAP(VARCHAR, INT))
|
||||
FROM VALUES ({ nested: MAP { 'inner_key': 707 } })
|
||||
AS tab(col);
|
||||
----
|
||||
{nested={inner_key=707}}
|
||||
|
||||
Reference in New Issue
Block a user