355 lines
7.4 KiB
SQL
355 lines
7.4 KiB
SQL
# 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}}
|
|
|