Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions iceberg/iceberg-handler/src/test/queries/positive/variant_cast.q
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
set hive.explain.user=false;

drop table if exists variant_cast;

CREATE EXTERNAL TABLE variant_cast (
id INT,
v VARIANT
) STORED BY ICEBERG
TBLPROPERTIES (
'format-version'='3'
);

-- typed variant construction: values JSON cannot express keep their real type
INSERT INTO variant_cast VALUES
(1, CAST(true AS VARIANT)),
(2, CAST(42 AS VARIANT)),
(3, CAST(1.5BD AS VARIANT)),
(4, CAST(unhex('DEADBEEF') AS VARIANT)),
(5, CAST(DATE '2026-07-28' AS VARIANT)),
(6, CAST(TIMESTAMP '2026-07-28 10:00:00' AS VARIANT)),
(7, CAST('plain' AS VARIANT)),
(8, CAST(array(1, 2, 3) AS VARIANT)),
(9, CAST(NULL AS VARIANT));

SELECT id, v FROM variant_cast ORDER BY id;

-- binary node is rendered as base64, matching Impala/Trino
SELECT variant_get(v, '$', 'string') FROM variant_cast WHERE id = 4;

-- cast over a column expression, not a constant
drop table if exists variant_src;

CREATE TABLE variant_src (id INT, s STRING);

INSERT INTO variant_src VALUES (11, 'from_col');

EXPLAIN INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src;

INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src;

SELECT id, v FROM variant_cast WHERE id > 10;

-- identity cast over a reader-produced variant column
SELECT id, CAST(v AS VARIANT) FROM variant_cast WHERE id > 10;

drop table variant_cast;
drop table variant_src;
203 changes: 203 additions & 0 deletions iceberg/iceberg-handler/src/test/results/positive/variant_cast.q.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
PREHOOK: query: drop table if exists variant_cast
PREHOOK: type: DROPTABLE
PREHOOK: Output: database:default
POSTHOOK: query: drop table if exists variant_cast
POSTHOOK: type: DROPTABLE
POSTHOOK: Output: database:default
PREHOOK: query: CREATE EXTERNAL TABLE variant_cast (
id INT,
v VARIANT
) STORED BY ICEBERG
TBLPROPERTIES (
'format-version'='3'
)
PREHOOK: type: CREATETABLE
PREHOOK: Output: database:default
PREHOOK: Output: default@variant_cast
POSTHOOK: query: CREATE EXTERNAL TABLE variant_cast (
id INT,
v VARIANT
) STORED BY ICEBERG
TBLPROPERTIES (
'format-version'='3'
)
POSTHOOK: type: CREATETABLE
POSTHOOK: Output: database:default
POSTHOOK: Output: default@variant_cast
PREHOOK: query: INSERT INTO variant_cast VALUES
(1, CAST(true AS VARIANT)),
(2, CAST(42 AS VARIANT)),
(3, CAST(1.5BD AS VARIANT)),
(4, CAST(unhex('DEADBEEF') AS VARIANT)),
(5, CAST(DATE '2026-07-28' AS VARIANT)),
(6, CAST(TIMESTAMP '2026-07-28 10:00:00' AS VARIANT)),
(7, CAST('plain' AS VARIANT)),
(8, CAST(array(1, 2, 3) AS VARIANT)),
(9, CAST(NULL AS VARIANT))
PREHOOK: type: QUERY
PREHOOK: Input: _dummy_database@_dummy_table
PREHOOK: Output: default@variant_cast
POSTHOOK: query: INSERT INTO variant_cast VALUES
(1, CAST(true AS VARIANT)),
(2, CAST(42 AS VARIANT)),
(3, CAST(1.5BD AS VARIANT)),
(4, CAST(unhex('DEADBEEF') AS VARIANT)),
(5, CAST(DATE '2026-07-28' AS VARIANT)),
(6, CAST(TIMESTAMP '2026-07-28 10:00:00' AS VARIANT)),
(7, CAST('plain' AS VARIANT)),
(8, CAST(array(1, 2, 3) AS VARIANT)),
(9, CAST(NULL AS VARIANT))
POSTHOOK: type: QUERY
POSTHOOK: Input: _dummy_database@_dummy_table
POSTHOOK: Output: default@variant_cast
PREHOOK: query: SELECT id, v FROM variant_cast ORDER BY id
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_cast
PREHOOK: Output: hdfs://### HDFS PATH ###
POSTHOOK: query: SELECT id, v FROM variant_cast ORDER BY id
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_cast
POSTHOOK: Output: hdfs://### HDFS PATH ###
1 true
2 42
3 1.5
4 "3q2+7w=="
5 "2026-07-28"
6 "2026-07-28 10:00:00"
7 "plain"
8 [1,2,3]
9 NULL
PREHOOK: query: SELECT variant_get(v, '$', 'string') FROM variant_cast WHERE id = 4
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_cast
PREHOOK: Output: hdfs://### HDFS PATH ###
POSTHOOK: query: SELECT variant_get(v, '$', 'string') FROM variant_cast WHERE id = 4
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_cast
POSTHOOK: Output: hdfs://### HDFS PATH ###
3q2+7w==
PREHOOK: query: drop table if exists variant_src
PREHOOK: type: DROPTABLE
PREHOOK: Output: database:default
POSTHOOK: query: drop table if exists variant_src
POSTHOOK: type: DROPTABLE
POSTHOOK: Output: database:default
PREHOOK: query: CREATE TABLE variant_src (id INT, s STRING)
PREHOOK: type: CREATETABLE
PREHOOK: Output: database:default
PREHOOK: Output: default@variant_src
POSTHOOK: query: CREATE TABLE variant_src (id INT, s STRING)
POSTHOOK: type: CREATETABLE
POSTHOOK: Output: database:default
POSTHOOK: Output: default@variant_src
PREHOOK: query: INSERT INTO variant_src VALUES (11, 'from_col')
PREHOOK: type: QUERY
PREHOOK: Input: _dummy_database@_dummy_table
PREHOOK: Output: default@variant_src
POSTHOOK: query: INSERT INTO variant_src VALUES (11, 'from_col')
POSTHOOK: type: QUERY
POSTHOOK: Input: _dummy_database@_dummy_table
POSTHOOK: Output: default@variant_src
POSTHOOK: Lineage: variant_src.id SCRIPT []
POSTHOOK: Lineage: variant_src.s SCRIPT []
PREHOOK: query: EXPLAIN INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_src
PREHOOK: Output: default@variant_cast
POSTHOOK: query: EXPLAIN INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_src
POSTHOOK: Output: default@variant_cast
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-2 depends on stages: Stage-1
Stage-0 depends on stages: Stage-2
Stage-3 depends on stages: Stage-0

STAGE PLANS:
Stage: Stage-1
Tez
#### A masked pattern was here ####
Vertices:
Map 1
Map Operator Tree:
TableScan
alias: variant_src
Statistics: Num rows: 1 Data size: 96 Basic stats: COMPLETE Column stats: COMPLETE
Select Operator
expressions: id (type: int), CAST( s AS VARIANT) (type: struct<metadata:binary,value:binary>)
outputColumnNames: _col0, _col1
Statistics: Num rows: 1 Data size: 340 Basic stats: COMPLETE Column stats: COMPLETE
File Output Operator
compressed: false
Statistics: Num rows: 1 Data size: 340 Basic stats: COMPLETE Column stats: COMPLETE
table:
input format: org.apache.iceberg.mr.hive.HiveIcebergInputFormat
output format: org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
name: default.variant_cast
Execution mode: vectorized

Stage: Stage-2
Dependency Collection

Stage: Stage-0
Move Operator
tables:
replace: false
table:
input format: org.apache.iceberg.mr.hive.HiveIcebergInputFormat
output format: org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
name: default.variant_cast

Stage: Stage-3
Stats Work
Basic Stats Work:

PREHOOK: query: INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_src
PREHOOK: Output: default@variant_cast
POSTHOOK: query: INSERT INTO variant_cast SELECT id, CAST(s AS VARIANT) FROM variant_src
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_src
POSTHOOK: Output: default@variant_cast
PREHOOK: query: SELECT id, v FROM variant_cast WHERE id > 10
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_cast
PREHOOK: Output: hdfs://### HDFS PATH ###
POSTHOOK: query: SELECT id, v FROM variant_cast WHERE id > 10
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_cast
POSTHOOK: Output: hdfs://### HDFS PATH ###
11 "from_col"
PREHOOK: query: SELECT id, CAST(v AS VARIANT) FROM variant_cast WHERE id > 10
PREHOOK: type: QUERY
PREHOOK: Input: default@variant_cast
PREHOOK: Output: hdfs://### HDFS PATH ###
POSTHOOK: query: SELECT id, CAST(v AS VARIANT) FROM variant_cast WHERE id > 10
POSTHOOK: type: QUERY
POSTHOOK: Input: default@variant_cast
POSTHOOK: Output: hdfs://### HDFS PATH ###
11 "from_col"
PREHOOK: query: drop table variant_cast
PREHOOK: type: DROPTABLE
PREHOOK: Input: default@variant_cast
PREHOOK: Output: database:default
PREHOOK: Output: default@variant_cast
POSTHOOK: query: drop table variant_cast
POSTHOOK: type: DROPTABLE
POSTHOOK: Input: default@variant_cast
POSTHOOK: Output: database:default
POSTHOOK: Output: default@variant_cast
PREHOOK: query: drop table variant_src
PREHOOK: type: DROPTABLE
PREHOOK: Input: default@variant_src
PREHOOK: Output: database:default
PREHOOK: Output: default@variant_src
POSTHOOK: query: drop table variant_src
POSTHOOK: type: DROPTABLE
POSTHOOK: Input: default@variant_src
POSTHOOK: Output: database:default
POSTHOOK: Output: default@variant_src
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ public final class FunctionRegistry {
system.registerFunction("ST_Z", ST_Z.class);

// Iceberg UDFs
system.registerGenericUDF(serdeConstants.VARIANT_TYPE_NAME, GenericUDFToVariant.class);
system.registerGenericUDF("parse_json", GenericUDFParseJson.class);
system.registerGenericUDF("to_json", GenericUDFToJson.class);
system.registerGenericUDF("variant_get", GenericUDFVariantGet.class);
Expand Down Expand Up @@ -1637,7 +1638,7 @@ public static boolean isOpCast(GenericUDF genericUDF) {
udfClass == GenericUDFToVarchar.class || udfClass == GenericUDFToChar.class ||
udfClass == GenericUDFTimestamp.class || udfClass == GenericUDFToBinary.class ||
udfClass == GenericUDFToDate.class || udfClass == GenericUDFToDecimal.class ||
udfClass == GenericUDFToTimestampLocalTZ.class;
udfClass == GenericUDFToTimestampLocalTZ.class || udfClass == GenericUDFToVariant.class;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public class TypeCheckProcFactory<T> {
serdeConstants.INTERVAL_DAY_TIME_TYPE_NAME);
CONVERSION_FUNCTION_TEXT_MAP.put(HiveParser.TOK_DECIMAL,
serdeConstants.DECIMAL_TYPE_NAME);
CONVERSION_FUNCTION_TEXT_MAP.put(HiveParser.TOK_VARIANT,
serdeConstants.VARIANT_TYPE_NAME);
CONVERSION_FUNCTION_TEXT_MAP.put(HiveParser.TOK_MAP, "toMap");
CONVERSION_FUNCTION_TEXT_MAP.put(HiveParser.TOK_LIST, "toArray");
CONVERSION_FUNCTION_TEXT_MAP.put(HiveParser.TOK_STRUCT, "toStruct");
Expand Down
Loading
Loading