From 2e46aa34802257b61c0f1e3bd9053fadb93953d2 Mon Sep 17 00:00:00 2001 From: JingsongLi Date: Wed, 14 Oct 2026 11:13:56 +0800 Subject: [PATCH 1/4] [python] Align REST numeric authorization casts with Java --- .../pypaimon/casting/decimal_cast.py | 19 +- .../pypaimon/casting/numeric_cast.py | 152 +++++ .../pypaimon/casting/numeric_utils.py | 18 + .../pypaimon/casting/schema_evolution.py | 50 +- .../pypaimon/common/predicate_json_parser.py | 37 +- .../tests/authorization_numeric_cast_test.py | 569 ++++++++++++++++++ .../tests/native_numeric_cast_test.py | 131 ++++ .../native_schema_evolution_cast_test.py | 34 ++ 8 files changed, 965 insertions(+), 45 deletions(-) create mode 100644 paimon-python/pypaimon/casting/numeric_cast.py create mode 100644 paimon-python/pypaimon/tests/authorization_numeric_cast_test.py create mode 100644 paimon-python/pypaimon/tests/native_numeric_cast_test.py diff --git a/paimon-python/pypaimon/casting/decimal_cast.py b/paimon-python/pypaimon/casting/decimal_cast.py index eb7170dbea2d..9f8c7b97aeb6 100644 --- a/paimon-python/pypaimon/casting/decimal_cast.py +++ b/paimon-python/pypaimon/casting/decimal_cast.py @@ -22,7 +22,7 @@ import pyarrow as pa -from pypaimon.casting.numeric_utils import java_double_decimal_text +from pypaimon.casting.numeric_utils import java_double_decimal_text, java_decimal_digit _DECIMAL_TEXT = re.compile(r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?\Z') @@ -37,8 +37,9 @@ def cast_decimal(array, target): fails the conversion instead of silently becoming NULL. """ floating = pa.types.is_floating(array.type) - text = pa.types.is_string(array.type) - if not pa.types.is_decimal(target) or not (floating or text or pa.types.is_decimal(array.type)): + text = pa.types.is_string(array.type) or pa.types.is_large_string(array.type) + integral = pa.types.is_signed_integer(array.type) + if not pa.types.is_decimal(target) or not (floating or text or integral or pa.types.is_decimal(array.type)): return None values = [] # The caller's rounding traps and exponent limits must not affect reads. @@ -55,11 +56,21 @@ def cast_decimal(array, target): value = java_double_decimal_text(value) if floating or text: if _DECIMAL_TEXT.fullmatch(value) is None: - raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) + # BigDecimal accepts BMP decimal digits, unlike the + # ASCII-only BinaryStringUtils integer text parser. + normalized = [] + for character in value: + digit = java_decimal_digit(character) + normalized.append(str(digit) if digit is not None else character) + value = ''.join(normalized) + if _DECIMAL_TEXT.fullmatch(value) is None: + raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) try: value = Decimal(value) except InvalidOperation as error: raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) from error + if integral: + value = Decimal(value) # BigDecimal validates the adjusted input scale, then setScale and # BigInteger.TEN.pow check their supported range before precision. # Zero bypasses the power check, but still needs a valid input scale. diff --git a/paimon-python/pypaimon/casting/numeric_cast.py b/paimon-python/pypaimon/casting/numeric_cast.py new file mode 100644 index 000000000000..62e27fec58c0 --- /dev/null +++ b/paimon-python/pypaimon/casting/numeric_cast.py @@ -0,0 +1,152 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Existing Java numeric and Boolean CAST rules shared by readers and auth.""" + +import math +import re + +import pyarrow as pa + +from pypaimon.casting.decimal_cast import cast_decimal + + +def _narrow_integer(value, bits): + half = 1 << (bits - 1) + return (value + half) % (half * 2) - half + + +def _numeric_to_integer(array, target_type): + bits = target_type.bit_width + floating = pa.types.is_floating(array.type) + intermediate_bits = 64 if bits == 64 else 32 + lower = -(1 << (intermediate_bits - 1)) + upper = (1 << (intermediate_bits - 1)) - 1 + values = [] + for value in array.to_pylist(): + if value is None: + values.append(None) + continue + # Number.byteValue/shortValue first convert floats to int; Java's + # float-to-int/long conversion saturates before the final narrowing. + if floating: + # Java's floating-point narrowing maps NaN to zero. + if math.isnan(value): + value = 0 + else: + value = lower if value <= lower else upper if value >= upper else int(value) + else: + # BigDecimal.longValue truncates towards zero and retains low bits. + value = int(value) + values.append(_narrow_integer(value, bits)) + return pa.array(values, type=target_type) + + +def _parse_integer(text, bits): + if not text: + raise ValueError('Empty integer value') + negative = text[0] == '-' + index = int(text[0] in ('+', '-')) + if index == len(text): + raise ValueError('Invalid integer value: %s' % text) + limit = 1 << (bits - 1) + if not negative: + limit -= 1 + value = 0 + while index < len(text) and text[index] != '.': + digit = text[index] + if digit < '0' or digit > '9': + raise ValueError('Invalid integer value: %s' % text) + value = value * 10 + ord(digit) - ord('0') + if value > limit: + raise ValueError('Integer value overflow: %s' % text) + index += 1 + if index < len(text) and any(digit < '0' or digit > '9' for digit in text[index + 1:]): + raise ValueError('Invalid integer value: %s' % text) + return -value if negative else value + + +def _parse_boolean(text): + lowered = text.lower() + if lowered in ('t', 'true', 'y', 'yes', '1'): + return True + if lowered in ('f', 'false', 'n', 'no', '0'): + return False + raise ValueError("Cannot parse '%s' as BOOLEAN" % text) + + +def cast_numeric(array, target, target_paimon_type=None): + """Return None outside the existing numeric/Boolean CAST subset. + + Invalid text is an error, decimal precision overflow is NULL, and numeric + narrowing follows Number/BigDecimal conversion rather than Arrow storage. + The caller retains the original Java executor when rebinding field refs. + """ + source = array.type + text = pa.types.is_string(source) or pa.types.is_large_string(source) + integer = pa.types.is_signed_integer(source) + numeric = integer or pa.types.is_floating(source) or pa.types.is_decimal(source) + numeric_target = pa.types.is_signed_integer(target) or pa.types.is_floating(target) or pa.types.is_decimal(target) + if pa.types.is_boolean(target) and text: + return pa.array([None if value is None else _parse_boolean(value) for value in array.to_pylist()], + type=target) + if pa.types.is_boolean(target) and numeric: + if not integer: + raise ValueError('Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast') + return pa.array([None if value is None else value != 0 for value in array.to_pylist()], type=target) + if pa.types.is_signed_integer(target) and text: + return pa.array([None if value is None else _parse_integer(value, target.bit_width) + for value in array.to_pylist()], type=target) + if pa.types.is_decimal(source) and (pa.types.is_string(target) or pa.types.is_large_string(target)): + values = [None if value is None else format(value, 'f') for value in array.to_pylist()] + # Arrow carries no declared CHAR/VARCHAR length. Authorization callers + # apply widths themselves; old-file reads pass the logical target here. + width = re.fullmatch(r'(CHAR|VARCHAR)(?:\(\s*([0-9]+)\s*\))?(?:\s+(?:NOT\s+)?NULL)?', + str(target_paimon_type).strip().upper()) + if width is not None: + kind, length = width.group(1), int(width.group(2) or 1) + values = [None if value is None else (value[:length].ljust(length) if kind == 'CHAR' else value[:length]) + for value in values] + return pa.array(values, type=target) + if pa.types.is_decimal(target) and (numeric or text): + return cast_decimal(array, target) + if pa.types.is_boolean(source) and pa.types.is_decimal(target): + # PyPaimon does not support this pair; keep the existing capability + # boundary instead of introducing another Java CAST category here. + return None + if numeric_target and (numeric or pa.types.is_boolean(source)): + if pa.types.is_signed_integer(target) and numeric: + return _numeric_to_integer(array, target) + if pa.types.is_decimal(source): + # DecimalToNumericPrimitive first obtains a double, then casts to + # FLOAT if requested; direct decimal-to-float can double-round differently. + def decimal_double(value): + if value is None: + return None + if source.precision > 18: + return float(value) + digits = value.as_tuple() + unscaled = 0 + for digit in digits.digits: + unscaled = unscaled * 10 + digit + if digits.sign: + unscaled = -unscaled + return float(unscaled) / (10 ** source.scale) + + return pa.array([decimal_double(value) for value in array.to_pylist()], type=target) + return array.cast(target, safe=False) + return None diff --git a/paimon-python/pypaimon/casting/numeric_utils.py b/paimon-python/pypaimon/casting/numeric_utils.py index a44ec07cfacd..6a04517f2366 100644 --- a/paimon-python/pypaimon/casting/numeric_utils.py +++ b/paimon-python/pypaimon/casting/numeric_utils.py @@ -22,6 +22,24 @@ from decimal import Decimal +# Java Character.digit scans UTF-16 chars, so supplementary digits do not +# participate. +_DECIMAL_ZEROES = ( + 0x0030, 0x0660, 0x06f0, 0x07c0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0be6, 0x0c66, + 0x0ce6, 0x0d66, 0x0de6, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x1090, 0x17e0, 0x1810, 0x1946, + 0x19d0, 0x1a80, 0x1a90, 0x1b50, 0x1bb0, 0x1c40, 0x1c50, 0xa620, 0xa8d0, 0xa900, 0xa9d0, + 0xa9f0, 0xaa50, 0xabf0, 0xff10, +) + + +def java_decimal_digit(character): + code = ord(character) + for zero in _DECIMAL_ZEROES: + if zero <= code < zero + 10: + return code - zero + return None + + def java_floating_string(value, single_precision=False) -> str: # Java's JDK 19+ contract selects a shortest round-tripping form with at # least two significant digits before applying its notation thresholds. diff --git a/paimon-python/pypaimon/casting/schema_evolution.py b/paimon-python/pypaimon/casting/schema_evolution.py index 1116aeaacd51..8b57e7988321 100644 --- a/paimon-python/pypaimon/casting/schema_evolution.py +++ b/paimon-python/pypaimon/casting/schema_evolution.py @@ -17,47 +17,14 @@ """Java cast rules shared by old-file readers.""" -import math - import pyarrow as pa -from pypaimon.casting.decimal_cast import cast_decimal +from pypaimon.casting.numeric_cast import _narrow_integer, cast_numeric from pypaimon.casting.temporal_cast import cast_temporal from pypaimon.casting.temporal_string import temporal_to_string from pypaimon.table.row.generic_row import _parse_type_precision_scale -def _narrow_integer(value, bits): - half = 1 << (bits - 1) - return (value + half) % (half * 2) - half - - -def _numeric_to_integer(array, target_type): - bits = target_type.bit_width - floating = pa.types.is_floating(array.type) - intermediate_bits = 64 if bits == 64 else 32 - lower = -(1 << (intermediate_bits - 1)) - upper = (1 << (intermediate_bits - 1)) - 1 - values = [] - for value in array.to_pylist(): - if value is None: - values.append(None) - continue - # Number.byteValue/shortValue first convert floats to int; Java's - # float-to-int/long conversion saturates before the final narrowing. - if floating: - # Java's floating-point narrowing maps NaN to zero. - if math.isnan(value): - value = 0 - else: - value = lower if value <= lower else upper if value >= upper else int(value) - else: - # BigDecimal.longValue truncates towards zero and retains low bits. - value = int(value) - values.append(_narrow_integer(value, bits)) - return pa.array(values, type=target_type) - - def _truncate_timestamp(array, target_type, source_paimon_type, target_paimon_type): if (not pa.types.is_timestamp(array.type) or not pa.types.is_timestamp(target_type) or array.type.tz != target_type.tz @@ -138,15 +105,18 @@ def cast_array_for_schema_evolution(array, target_type, source_paimon_type=None, return timestamp if array.type == target_type: return array - decimals = cast_decimal(array, target_type) - if decimals is not None: - return decimals + if pa.types.is_signed_integer(array.type) and pa.types.is_decimal(target_type): + required = {8: 3, 16: 5, 32: 10, 64: 19}[array.type.bit_width] + target_type.scale + if target_type.precision < required: + # Preserve PyPaimon's existing ALTER TABLE capability boundary. + # Authorization CASTs separately use Java's per-value NULL overflow. + return array.cast(target_type, safe=False) + numeric = cast_numeric(array, target_type, target_paimon_type) + if numeric is not None: + return numeric if pa.types.is_timestamp(array.type) and target_type == pa.int64(): return _timestamp_to_bigint(array) if (array.type in (pa.int32(), pa.int64()) and pa.types.is_timestamp(target_type) and target_type.tz is None): return _integer_to_timestamp(array, target_type) - if (pa.types.is_signed_integer(target_type) - and (pa.types.is_floating(array.type) or pa.types.is_decimal(array.type))): - return _numeric_to_integer(array, target_type) return array.cast(target_type, safe=False) diff --git a/paimon-python/pypaimon/common/predicate_json_parser.py b/paimon-python/pypaimon/common/predicate_json_parser.py index 5ab57be62098..cf2df23bd212 100644 --- a/paimon-python/pypaimon/common/predicate_json_parser.py +++ b/paimon-python/pypaimon/common/predicate_json_parser.py @@ -23,6 +23,8 @@ import pyarrow as pa import pyarrow.compute as pc +from pypaimon.casting.numeric_cast import cast_numeric, _numeric_to_integer + # utf8_slice_codeunits needs an explicit integer stop on pyarrow 6 _MAX_STOP = 2 ** 31 - 1 @@ -167,7 +169,9 @@ def _apply_predicate_transform(transform: dict, batch: pa.RecordBatch, target_type = _paimon_type_to_arrow(target) stored = _paimon_type_to_arrow(transform['fieldRef']['type']) col = _cast_input_for_java_executor(col, stored, target_type) - result = pc.cast(col, target_type, safe=False) + result = cast_numeric(col, target_type) + if result is None: + result = pc.cast(col, target_type, safe=False) # Java CastTransform enforces widths; Arrow uses unbounded arrays. if width is not None: pad = kind in ('CHAR', 'BINARY') @@ -255,6 +259,37 @@ def _cast_input_for_java_executor(col, stored, target): return pa.nulls(len(col), type=target) numeric = pa.types.is_integer(stored) or pa.types.is_floating(stored) or pa.types.is_decimal(stored) + if numeric and pa.types.is_boolean(target): + if not pa.types.is_signed_integer(stored): + raise ValueError('Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast') + if pa.types.is_date(col.type): + col = col.cast(pa.date32(), safe=False).cast(pa.int32()) + elif pa.types.is_time(col.type): + col = col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) + if not (pa.types.is_signed_integer(col.type) or pa.types.is_floating(col.type)): + if col.null_count != len(col): + raise ValueError('CAST source no longer has the Number class its Java executor expects') + return pa.nulls(len(col), type=target) + # NumericToBoolean retains Number.longValue, even for a rebound float. + return _numeric_to_integer(col, pa.int64()) + numeric_target = pa.types.is_signed_integer(target) or pa.types.is_floating(target) or pa.types.is_decimal(target) + if numeric and numeric_target: + decimal = pa.types.is_decimal(stored) + primitive = (pa.types.is_signed_integer(col.type) or pa.types.is_floating(col.type) or + pa.types.is_date(col.type) or pa.types.is_time(col.type)) + if (decimal and not pa.types.is_decimal(col.type)) or (not decimal and not primitive): + if col.null_count != len(col): + raise ValueError('CAST source no longer has the Number/Decimal class its Java executor expects') + return pa.nulls(len(col), type=target) + if pa.types.is_date(col.type): + col = col.cast(pa.date32(), safe=False).cast(pa.int32()) + elif pa.types.is_time(col.type): + col = col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) + if pa.types.is_decimal(target) and not decimal: + # NumericPrimitiveToDecimal retains longValue or doubleValue based + # on the stored source family, even when the actual field changes. + col = (_numeric_to_integer(col, pa.int64()) if pa.types.is_signed_integer(stored) + else col.cast(pa.float64(), safe=False)) if numeric and pa.types.is_string(target) and col.type != stored: # NumericToString accepts Object. DATE and TIME getters return Integer, # so this executor prints epoch days / milliseconds, not calendar text. diff --git a/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py b/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py new file mode 100644 index 000000000000..6ee506bd02e3 --- /dev/null +++ b/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py @@ -0,0 +1,569 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Java numeric REST CAST semantics for authorization and masking.""" + +import json +from decimal import Decimal + +import pyarrow as pa +import pytest + +from pypaimon.common.predicate_json_parser import ( + _apply_predicate_transform, _paimon_type_to_arrow, parse_predicate_to_batch_filter, +) + + +def _cast(source_type, target_type, array): + return _apply_predicate_transform({ + 'name': 'CAST', 'fieldRef': {'name': 'source', 'type': source_type}, 'type': target_type, + }, pa.RecordBatch.from_pydict({'source': array})) + + +def test_floating_narrowing_saturates_before_byte_conversion(): + source = pa.array([128.9, -129.9, 1e30, -1e30, None], type=pa.float64()) + assert _cast('DOUBLE', 'TINYINT', source).to_pylist() == [-128, 127, -1, 0, None] + + +def test_numeric_decimal_rounds_half_up_and_returns_null_on_precision_overflow(): + source = pa.array([1.005, -1.005, 2.675, 999.995, None], type=pa.float64()) + assert _cast('DOUBLE', 'DECIMAL(5,2)', source).to_pylist() == [ + Decimal('1.01'), Decimal('-1.01'), Decimal('2.68'), None, None] + + +# Generated with Java CastExecutors / PredicateRemapper on Paimon master +# 8de6fdbda9. Includes the decimal compact/wide and original-executor paths; +# the Double-to-Decimal text was additionally verified on Java 8. +JAVA_CASES = [ + json.loads( + '{"name":"BIGINT_to_TINYINT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[922337' + '2036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[42949672' + '97],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT' + '"},"type":"TINYINT"},"expected":{"name":"BIGINT_to_TINYINT","results":[0,-1,-128,-1,0,127,-1,0,-1,0,0,0,1,' + '1,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_SMALLINT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[92233' + '72036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967' + '297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGIN' + 'T"},"type":"SMALLINT"},"expected":{"name":"BIGINT_to_SMALLINT","results":[0,-1,128,255,256,-129,-257,-3276' + '8,-1,0,0,0,1,1,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_INT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9223372036' + '854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967297],' + '[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"' + 'type":"INT"},"expected":{"name":"BIGINT_to_INT","results":[0,-1,128,255,256,-129,-257,32768,65535,65536,-2' + '147483648,0,1,536870913,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_FLOAT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[92233720' + '36854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967297' + '],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"}' + ',"type":"FLOAT"},"expected":{"name":"BIGINT_to_FLOAT","results":[-9.223372036854776e+18,9.223372036854776e' + '+18,128.0,255.0,256.0,-129.0,-257.0,32768.0,65535.0,65536.0,2147483648.0,4294967296.0,4294967296.0,9007200' + '328482816.0,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_DOUBLE","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9223372' + '036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429496729' + '7],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"' + '},"type":"DOUBLE"},"expected":{"name":"BIGINT_to_DOUBLE","results":[-9.223372036854776e+18,9.2233720368547' + '76e+18,128.0,255.0,256.0,-129.0,-257.0,32768.0,65535.0,65536.0,2147483648.0,4294967296.0,4294967297.0,9007' + '199791611904.0,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_DECIMAL(5,0)","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9' + '223372036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429' + '4967297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"B' + 'IGINT"},"type":"DECIMAL(5,0)"},"expected":{"name":"BIGINT_to_DECIMAL(5,0)","results":[null,null,"128","255' + '","256","-129","-257","32768","65535","65536",null,null,null,null,null]}}' + ), + json.loads( + '{"name":"BIGINT_to_DECIMAL(4,2)","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9' + '223372036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429' + '4967297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"B' + 'IGINT"},"type":"DECIMAL(4,2)"},"expected":{"name":"BIGINT_to_DECIMAL(4,2)","results":[null,null,null,null,' + 'null,null,null,null,null,null,null,null,null,null,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_TINYINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-1' + '29.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fi' + 'eldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"TINYINT"},"expected":{"name":"FLOAT_to_TINYINT","re' + 'sults":[1,-1,127,-128,127,-1,-1,-1,-1,0,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_SMALLINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-' + '129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","f' + 'ieldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"SMALLINT"},"expected":{"name":"FLOAT_to_SMALLINT",' + '"results":[1,-1,127,128,-129,-1,-1,-1,-1,0,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_INT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-129.9' + '],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"FLOAT"},"type":"INT"},"expected":{"name":"FLOAT_to_INT","results":[1,-1' + ',127,128,-129,2147483647,2147483647,2147483647,2147483647,-2147483648,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_BIGINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-12' + '9.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"BIGINT"},"expected":{"name":"FLOAT_to_BIGINT","resul' + 'ts":[1,-1,127,128,-129,2147483648,2147483648,4294967296,9223372036854775807,-9223372036854775808,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_DECIMAL(4,2)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],[-' + '2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":99' + ',"name":"v","type":"FLOAT"},"type":"DECIMAL(4,2)"},"expected":{"name":"FLOAT_to_DECIMAL(4,2)","results":["' + '1.00","-1.00","2.67","-2.67","99.99",null,null,null,null,null]}}' + ), + json.loads( + '{"name":"FLOAT_to_DECIMAL(38,0)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],[' + '-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":9' + '9,"name":"v","type":"FLOAT"},"type":"DECIMAL(38,0)"},"expected":{"name":"FLOAT_to_DECIMAL(38,0)","results"' + ':["1","-1","3","-3","100","100","100000002004087730000","99999997781963080000000","10000000150474662000000' + '00000000",null]}}' + ), + json.loads( + '{"name":"FLOAT_to_DECIMAL(38,18)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],' + '[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":' + '99,"name":"v","type":"FLOAT"},"type":"DECIMAL(38,18)"},"expected":{"name":"FLOAT_to_DECIMAL(38,18)","resul' + 'ts":["1.004999995231628400","-1.004999995231628400","2.674999952316284000","-2.674999952316284000","99.994' + '003295898440000","99.995002746582030000",null,null,null,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_TINYINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[' + '-129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","' + 'fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"TINYINT"},"expected":{"name":"DOUBLE_to_TINYINT"' + ',"results":[1,-1,127,-128,127,-1,-1,-1,-1,0,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_SMALLINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],' + '[-129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST",' + '"fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"SMALLINT"},"expected":{"name":"DOUBLE_to_SMALLI' + 'NT","results":[1,-1,127,128,-129,-1,-1,-1,-1,0,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_INT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-129' + '.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"INT"},"expected":{"name":"DOUBLE_to_INT","results":[' + '1,-1,127,128,-129,2147483647,2147483647,2147483647,2147483647,-2147483648,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_BIGINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-' + '129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","f' + 'ieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"BIGINT"},"expected":{"name":"DOUBLE_to_BIGINT","r' + 'esults":[1,-1,127,128,-129,2147483647,2147483648,4294967297,9223372036854775807,-9223372036854775808,null]' + '}}' + ), + json.loads( + '{"name":"DOUBLE_to_DECIMAL(4,2)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675],' + '[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":' + '99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(4,2)"},"expected":{"name":"DOUBLE_to_DECIMAL(4,2)","results' + '":["1.01","-1.01","2.68","-2.68","99.99",null,null,null,null,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_DECIMAL(38,0)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675]' + ',[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index"' + ':99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(38,0)"},"expected":{"name":"DOUBLE_to_DECIMAL(38,0)","resu' + 'lts":["1","-1","3","-3","100","100","100000000000000000000","99999999999999990000000","1000000000000000000' + '000000000000",null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_DECIMAL(38,18)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675' + '],[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index' + '":99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(38,18)"},"expected":{"name":"DOUBLE_to_DECIMAL(38,18)","r' + 'esults":["1.005000000000000000","-1.005000000000000000","2.675000000000000000","-2.675000000000000000","99' + '.994000000000000000","99.995000000000000000",null,null,null,null]}}' + ), + json.loads( + '{"name":"INT_to_DOUBLE","fields":[{"name":"v","type":"INT"}],"rows":[[-2147483648],[2147483647],[1],[null]' + '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"DOUBLE"},"expected":{' + '"name":"INT_to_DOUBLE","results":[-2147483648.0,2147483647.0,1.0,null]}}' + ), + json.loads( + '{"name":"INT_to_FLOAT","fields":[{"name":"v","type":"INT"}],"rows":[[-2147483648],[2147483647],[16777217],' + '[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"FLOAT"},"expect' + 'ed":{"name":"INT_to_FLOAT","results":[-2147483648.0,2147483648.0,16777216.0,null]}}' + ), + json.loads( + '{"name":"BOOLEAN_to_TINYINT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"tran' + 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"TINYINT"},"expected":{"n' + 'ame":"BOOLEAN_to_TINYINT","results":[1,0,null]}}' + ), + json.loads( + '{"name":"BOOLEAN_to_INT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"INT"},"expected":{"name":"BO' + 'OLEAN_to_INT","results":[1,0,null]}}' + ), + json.loads( + '{"name":"BOOLEAN_to_BIGINT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"trans' + 'form":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"BIGINT"},"expected":{"nam' + 'e":"BOOLEAN_to_BIGINT","results":[1,0,null]}}' + ), + json.loads( + '{"name":"BOOLEAN_to_FLOAT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"transf' + 'orm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"FLOAT"},"expected":{"name"' + ':"BOOLEAN_to_FLOAT","results":[1.0,0.0,null]}}' + ), + json.loads( + '{"name":"BOOLEAN_to_DOUBLE","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"trans' + 'form":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"DOUBLE"},"expected":{"nam' + 'e":"BOOLEAN_to_DOUBLE","results":[1.0,0.0,null]}}' + ), + json.loads( + '{"name":"STRING_to_TINYINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],' + '["1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],[' + '"128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-92233720368' + '54775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[nu' + 'll]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TINYINT"},"expe' + 'cted":{"name":"STRING_to_TINYINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatExcep' + 'tion"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberFo' + 'rmatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormat' + 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExce' + 'ption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' + 'n"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},' + '{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' + 'ror":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error"' + ':"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_SMALLINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"]' + ',["1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],' + '["128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-9223372036' + '854775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[n' + 'ull]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"SMALLINT"},"ex' + 'pected":{"name":"STRING_to_SMALLINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatEx' + 'ception"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"Numbe' + 'rFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFor' + 'matException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatE' + 'xception"},{"error":"NumberFormatException"},128,-129,{"error":"NumberFormatException"},{"error":"NumberFo' + 'rmatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormat' + 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExce' + 'ption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_INT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],["1.' + '"],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],["128' + '"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-922337203685477' + '5809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[null]]' + ',"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"INT"},"expected":{"' + 'name":"STRING_to_INT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"err' + 'or":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' + 'n"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},' + '{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' + 'ror":"NumberFormatException"},128,-129,32768,-32769,{"error":"NumberFormatException"},{"error":"NumberForm' + 'atException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},2147483647,-2147483648,{' + '"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_BIGINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],[' + '"1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],["' + '128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-922337203685' + '4775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[nul' + 'l]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"BIGINT"},"expect' + 'ed":{"name":"STRING_to_BIGINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' + 'n"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberForma' + 'tException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExc' + 'eption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExcepti' + 'on"},{"error":"NumberFormatException"},128,-129,32768,-32769,2147483648,-2147483649,{"error":"NumberFormat' + 'Exception"},{"error":"NumberFormatException"},2147483647,-2147483648,9223372036854775807,-9223372036854775' + '808,null]}}' + ), + json.loads( + '{"name":"STRING_to_BOOLEAN","fields":[{"name":"v","type":"STRING"}],"rows":[["t"],["TRUE"],["TrUe"],["y"],' + '["YeS"],["1"],["f"],["FALSE"],["FaLsE"],["n"],["No"],["0"],[" true"],["true "],["\\ttrue"],["on"],["off"],' + '["2"],[""],["1.0"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"' + 'type":"BOOLEAN"},"expected":{"name":"STRING_to_BOOLEAN","results":[true,true,true,true,true,true,false,fal' + 'se,false,false,false,false,{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeExce' + 'ption"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"R' + 'untimeException"},{"error":"RuntimeException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_DECIMAL(4,2)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["99' + '.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005 "' + '],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","t' + 'ype":"STRING"},"type":"DECIMAL(4,2)"},"expected":{"name":"STRING_to_DECIMAL(4,2)","results":["1.01","-1.01' + '","99.99",null,null,null,null,"0.00","0.50","1.00","1.01",{"error":"NumberFormatException"},{"error":"Numb' + 'erFormatException"},{"error":"NumberFormatException"},"12.34","12.34",{"error":"NumberFormatException"},{"' + 'error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_DECIMAL(38,0)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["9' + '9.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005 ' + '"],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","' + 'type":"STRING"},"type":"DECIMAL(38,0)"},"expected":{"name":"STRING_to_DECIMAL(38,0)","results":["1","-1","' + '100","100","9999","1000","1000","0","1","1","1",{"error":"NumberFormatException"},{"error":"NumberFormatEx' + 'ception"},{"error":"NumberFormatException"},"12","12",{"error":"NumberFormatException"},{"error":"NumberFo' + 'rmatException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_DECIMAL(38,18)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["' + '99.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005' + ' "],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v",' + '"type":"STRING"},"type":"DECIMAL(38,18)"},"expected":{"name":"STRING_to_DECIMAL(38,18)","results":["1.0050' + '00000000000000","-1.005000000000000000","99.994000000000000000","99.995000000000000000","9999.000000000000' + '000000","1000.000000000000000000","1000.000000000000000000","0.001000000000000000","0.500000000000000000",' + '"1.000000000000000000","1.005000000000000000",{"error":"NumberFormatException"},{"error":"NumberFormatExce' + 'ption"},{"error":"NumberFormatException"},"12.340000000000000000","12.340000000000000000",{"error":"Number' + 'FormatException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_TINYINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.9' + '99"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["18446744073709' + '551617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"i' + 'ndex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"TINYINT"},"expected":{"name":"DECIMAL(38,3)_to_TINYINT' + '","results":[1,-1,127,-128,0,0,0,1,-1,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_SMALLINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.' + '999"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["1844674407370' + '9551617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"' + 'index":99,"name":"v","type":"DECIMAL(38,3)"},"type":"SMALLINT"},"expected":{"name":"DECIMAL(38,3)_to_SMALL' + 'INT","results":[1,-1,127,128,-32768,0,0,1,-1,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_INT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.999"]' + ',["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095516' + '17.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"index' + '":99,"name":"v","type":"DECIMAL(38,3)"},"type":"INT"},"expected":{"name":"DECIMAL(38,3)_to_INT","results":' + '[1,-1,127,128,32768,-2147483648,0,1,-1,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_BIGINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.99' + '9"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095' + '51617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"in' + 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"BIGINT"},"expected":{"name":"DECIMAL(38,3)_to_BIGINT","' + 'results":[1,-1,127,128,32768,2147483648,-9223372036854775808,1,3136633892082024447,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_FLOAT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.999' + '"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["1844674407370955' + '1617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"ind' + 'ex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(38,3)_to_FLOAT","res' + 'ults":[1.9989999532699585,-1.9989999532699585,127.9990005493164,128.99899291992188,32769.0,2147483648.0,9.' + '223372036854776e+18,1.8446744073709552e+19,1.0000000409184788e+35,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_DOUBLE","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.99' + '9"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095' + '51617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"in' + 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(38,3)_to_DOUBLE","' + 'results":[1.999,-1.999,127.999,128.999,32768.999,2147483648.999,9.223372036854776e+18,1.8446744073709552e+' + '19,1e+35,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_DECIMAL(4,2)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"],[' + '"-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"in' + 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(4,2)"},"expected":{"name":"DECIMAL(38,3)_to_DEC' + 'IMAL(4,2)","results":["1.01","-1.01","99.99",null,null,null,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_DECIMAL(3,0)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"],[' + '"-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"in' + 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(3,0)"},"expected":{"name":"DECIMAL(38,3)_to_DEC' + 'IMAL(3,0)","results":["1","-1","100","100","999",null,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,3)_to_DECIMAL(38,10)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"]' + ',["-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"' + 'index":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(38,10)"},"expected":{"name":"DECIMAL(38,3)_to' + '_DECIMAL(38,10)","results":["1.0050000000","-1.0050000000","99.9940000000","99.9950000000","999.4990000000' + '","999.5000000000",null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,10)_to_STRING","fields":[{"name":"v","type":"DECIMAL(38,10)"}],"rows":[["0.0000000123"' + '],["-0.0000000123"],["0.0000000000"],["10000000000000000000000.0000000000"],[null]],"transform":{"name":"C' + 'AST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(38,10)"},"type":"STRING"},"expected":{"name":"DECIM' + 'AL(38,10)_to_STRING","results":["0.0000000123","-0.0000000123","0.0000000000","10000000000000000000000.000' + '0000000",null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,10)_to_VARCHAR(3)","fields":[{"name":"v","type":"DECIMAL(38,10)"}],"rows":[["0.0000000' + '123"],["-0.0000000123"],["0.0000000000"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' + '"v","type":"DECIMAL(38,10)"},"type":"VARCHAR(3)"},"expected":{"name":"DECIMAL(38,10)_to_VARCHAR(3)","resul' + 'ts":["0.0","-0.","0.0",null]}}' + ), + json.loads( + '{"name":"BIGINT_to_TINYINT_stored_INT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[4294967297],[null]' + '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"TINYINT"},"expected":' + '{"name":"BIGINT_to_TINYINT_stored_INT","results":[1,null]}}' + ), + json.loads( + '{"name":"DOUBLE_to_DECIMAL(4,2)_stored_INT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[null]],' + '"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"DECIMAL(4,2)"},"expecte' + 'd":{"name":"DOUBLE_to_DECIMAL(4,2)_stored_INT","results":["1.00",null]}}' + ), + json.loads( + '{"name":"BIGINT_to_DECIMAL(38,0)_stored_DOUBLE","fields":[{"name":"v","type":"BIGINT"}],"rows":[[900719925' + '4740993],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"DEC' + 'IMAL(38,0)"},"expected":{"name":"BIGINT_to_DECIMAL(38,0)_stored_DOUBLE","results":["9007199254740992",null' + ']}}' + ), + json.loads( + '{"name":"DECIMAL(12,3)_to_INT_stored_INT","fields":[{"name":"v","type":"DECIMAL(12,3)"}],"rows":[["1.999"]' + ',[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"INT"},"expecte' + 'd":{"name":"DECIMAL(12,3)_to_INT_stored_INT","results":[{"error":"ClassCastException"},null]}}' + ), + json.loads( + '{"name":"INT_to_INT_stored_DECIMAL(12,3)","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transf' + 'orm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(12,3)"},"type":"INT"},"expected":{"n' + 'ame":"INT_to_INT_stored_DECIMAL(12,3)","results":[{"error":"ClassCastException"},null]}}' + ), + json.loads( + '{"name":"INT_to_INT_stored_BOOLEAN","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transform":{' + '"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"INT"},"expected":{"name":"INT_to' + '_INT_stored_BOOLEAN","results":[{"error":"ClassCastException"},null]}}' + ), + json.loads( + '{"name":"INT_to_INT_stored_STRING","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transform":{"' + 'name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"INT"},"expected":{"name":"INT_to_I' + 'NT_stored_STRING","results":[{"error":"ClassCastException"},null]}}' + ), + json.loads( + '{"name":"STRING_to_INT_stored_INT","fields":[{"name":"v","type":"STRING"}],"rows":[["1"],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"INT"},"expected":{"name":"STRING' + '_to_INT_stored_INT","results":[{"error":"ClassCastException"},null]}}' + ), + json.loads( + '{"name":"DECIMAL(18,4)_to_DECIMAL(4,2)_stored_DECIMAL(12,3)","fields":[{"name":"v","type":"DECIMAL(18,4)"}' + '],"rows":[["1.0050"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(' + '12,3)"},"type":"DECIMAL(4,2)"},"expected":{"name":"DECIMAL(18,4)_to_DECIMAL(4,2)_stored_DECIMAL(12,3)","re' + 'sults":["1.01",null]}}' + ), + json.loads( + '{"name":"short_circuit_string_int_AND","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],' + '"rows":[[0,"bad"],[1,"1.9"],[2,null]],"predicate":{"kind":"COMPOUND","function":"AND","children":[{"kind":' + '"LEAF","transform":{"name":"FIELD_REF","fieldRef":{"index":0,"name":"id","type":"INT"}},"function":"EQUAL"' + ',"literals":[1]},{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING' + '"},"type":"INT"},"function":"EQUAL","literals":[1]}]},"expected":{"name":"short_circuit_string_int_AND","r' + 'esults":[false,true,false]}}' + ), + json.loads( + '{"name":"short_circuit_string_int_OR","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],"' + 'rows":[[0,"bad"],[1,"1.9"],[2,null]],"predicate":{"kind":"COMPOUND","function":"OR","children":[{"kind":"L' + 'EAF","transform":{"name":"FIELD_REF","fieldRef":{"index":0,"name":"id","type":"INT"}},"function":"EQUAL","' + 'literals":[1]},{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING"}' + ',"type":"INT"},"function":"EQUAL","literals":[1]}]},"expected":{"name":"short_circuit_string_int_OR","resu' + 'lts":[{"error":"NumberFormatException"},true,false]}}' + ), + json.loads( + '{"name":"separate_string_int_filters","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],"' + 'rows":[[0,"bad"],[1,"1.9"],[2,null]],"filters":[{"kind":"LEAF","transform":{"name":"FIELD_REF","fieldRef":' + '{"index":0,"name":"id","type":"INT"}},"function":"EQUAL","literals":[1]},{"kind":"LEAF","transform":{"name' + '":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING"},"type":"INT"},"function":"EQUAL","literals":[1]' + '}],"expected":{"name":"separate_string_int_filters","results":[false,true,false]}}' + ), + json.loads( + '{"name":"bad_cast_before_function_TRUE","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[n' + 'ull]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRIN' + 'G"},"type":"INT"},"function":"TRUE","literals":[]},"expected":{"name":"bad_cast_before_function_TRUE","res' + 'ults":[{"error":"NumberFormatException"},true,true]}}' + ), + json.loads( + '{"name":"bad_cast_before_function_FALSE","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[' + 'null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRI' + 'NG"},"type":"INT"},"function":"FALSE","literals":[]},"expected":{"name":"bad_cast_before_function_FALSE","' + 'results":[{"error":"NumberFormatException"},false,false]}}' + ), + json.loads( + '{"name":"bad_cast_before_function_EQUAL","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[' + 'null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRI' + 'NG"},"type":"INT"},"function":"EQUAL","literals":[null]},"expected":{"name":"bad_cast_before_function_EQUA' + 'L","results":[{"error":"NumberFormatException"},false,false]}}' + ), + json.loads( + '{"name":"decimal_overflow_IS_NULL","fields":[{"name":"v","type":"STRING"}],"rows":[["99.994"],["99.995"],[' + '"bad"],[null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' + 'e":"STRING"},"type":"DECIMAL(4,2)"},"function":"IS_NULL","literals":[]},"expected":{"name":"decimal_overfl' + 'ow_IS_NULL","results":[false,true,{"error":"NumberFormatException"},true]}}' + ), + json.loads( + '{"name":"decimal_overflow_IS_NOT_NULL","fields":[{"name":"v","type":"STRING"}],"rows":[["99.994"],["99.995' + '"],["bad"],[null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v",' + '"type":"STRING"},"type":"DECIMAL(4,2)"},"function":"IS_NOT_NULL","literals":[]},"expected":{"name":"decima' + 'l_overflow_IS_NOT_NULL","results":[true,false,{"error":"NumberFormatException"},false]}}' + ), + json.loads( + '{"name":"DECIMAL(18,1)_compact_double_DOUBLE","fields":[{"name":"v","type":"DECIMAL(18,1)"}],"rows":[["900' + '719925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef' + '":{"index":99,"name":"v","type":"DECIMAL(18,1)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(18,1)_compac' + 't_double_DOUBLE","results":[900719925474099.2,900719925474099.6,-900719925474099.2,null]}}' + ), + json.loads( + '{"name":"DECIMAL(18,1)_compact_double_FLOAT","fields":[{"name":"v","type":"DECIMAL(18,1)"}],"rows":[["9007' + '19925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"DECIMAL(18,1)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(18,1)_compact_' + 'double_FLOAT","results":[900719938895872.0,900719938895872.0,-900719938895872.0,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,1)_compact_double_DOUBLE","fields":[{"name":"v","type":"DECIMAL(38,1)"}],"rows":[["900' + '719925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef' + '":{"index":99,"name":"v","type":"DECIMAL(38,1)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(38,1)_compac' + 't_double_DOUBLE","results":[900719925474099.2,900719925474099.5,-900719925474099.2,null]}}' + ), + json.loads( + '{"name":"DECIMAL(38,1)_compact_double_FLOAT","fields":[{"name":"v","type":"DECIMAL(38,1)"}],"rows":[["9007' + '19925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"DECIMAL(38,1)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(38,1)_compact_' + 'double_FLOAT","results":[900719938895872.0,900719938895872.0,-900719938895872.0,null]}}' + ), +] + + +def source_array(values, type_): + if pa.types.is_decimal(type_): + values = [None if v is None else Decimal(v) for v in values] + return pa.array(values, type=type_) + + +@pytest.mark.parametrize('case', JAVA_CASES, ids=lambda case: case['name']) +def test_existing_numeric_casts_match_java_golden(case): + schema = pa.schema([(f['name'], _paimon_type_to_arrow(f['type'])) for f in case['fields']]) + cols = [source_array([row[i] for row in case['rows']], field.type) for i, field in enumerate(schema)] + batch = pa.RecordBatch.from_arrays(cols, schema=schema) + if 'transform' in case: + def execute(rows): + return _apply_predicate_transform(case['transform'], rows) + else: + rule = case.get('predicate') or {'kind': 'COMPOUND', 'function': 'AND', 'children': case['filters']} + execute = parse_predicate_to_batch_filter(json.dumps(rule)) + if 'parseError' in case['expected']: + with pytest.raises((ValueError, TypeError, pa.ArrowInvalid)): + execute(batch.slice(0, 0)) + return + execute(batch.slice(0, 0)) + for i, expected in enumerate(case['expected']['results']): + if isinstance(expected, dict) and 'error' in expected: + with pytest.raises((ValueError, TypeError, pa.ArrowInvalid)): + execute(batch.slice(i, 1)) + else: + value = execute(batch.slice(i, 1)).to_pylist()[0] + if isinstance(value, Decimal): + value = format(value, 'f') + assert value == expected, (case['name'], i) + + +def test_boolean_to_decimal_remains_outside_existing_python_support(): + with pytest.raises(pa.ArrowNotImplementedError): + _cast('BOOLEAN', 'DECIMAL(4,2)', pa.array([True, False, None])) + + +def test_rebound_integer_to_boolean_keeps_number_long_value(): + array = pa.array([0.5, 1.9, -0.5, -1.9, 1e30, None], type=pa.float64()) + assert _cast('INT', 'BOOLEAN', array).to_pylist() == [False, True, False, True, True, None] + with pytest.raises(ValueError): + _cast('DOUBLE', 'BOOLEAN', array) diff --git a/paimon-python/pypaimon/tests/native_numeric_cast_test.py b/paimon-python/pypaimon/tests/native_numeric_cast_test.py new file mode 100644 index 000000000000..36929b9355ca --- /dev/null +++ b/paimon-python/pypaimon/tests/native_numeric_cast_test.py @@ -0,0 +1,131 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Numeric REST CASTs through strict Native reads of all existing table modes.""" + +import json + +import pyarrow as pa +import pytest + +from pypaimon import Schema +from pypaimon.api.api_response import AuthTableQueryResponse +from pypaimon.common.predicate_builder import PredicateBuilder +from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow +from pypaimon.read.native_plan import native_runtime_available +from pypaimon.schema.schema_change import SchemaChange +from pypaimon.tests import native_query_auth_test +from pypaimon.tests.authorization_numeric_cast_test import JAVA_CASES, source_array + +rest_catalog = native_query_auth_test.rest_catalog +_read = native_query_auth_test._read +pytestmark = [pytest.mark.native_plan, pytest.mark.skipif( + not native_runtime_available(), reason='Rust reader required')] + + +def _native_cases(): + cases = [] + for case in JAVA_CASES: + if 'transform' not in case or 'parseError' in case['expected']: + continue + if case['fields'][0]['type'] != case['transform']['fieldRef']['type']: + continue + pairs = [(row, value) for row, value in zip(case['rows'], case['expected']['results']) + if not isinstance(value, dict)] + if pairs: + cases.append(dict(case, rows=[p[0] for p in pairs], values=[p[1] for p in pairs])) + return cases + + +@pytest.fixture(params=[ + ('append', {}), ('primary-key', {'bucket': '1'}), + ('data-evolution', {'row-tracking.enabled': 'true', 'data-evolution.enabled': 'true'}), +], ids=lambda mode: mode[0]) +def table_mode(request): + return request.param + + +def _create_table(rest_catalog, table_mode, schema, data): + catalog, server = rest_catalog + mode, options = table_mode + catalog.create_table('default.numeric', Schema.from_pyarrow_schema( + schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options), False) + table = catalog.get_table('default.numeric') + builder = table.new_batch_write_builder() + writer, commit = builder.new_write(), builder.new_commit() + try: + writer.write_arrow(data) + commit.commit(writer.prepare_commit()) + finally: + writer.close() + commit.close() + catalog.alter_table(table.identifier, [SchemaChange.set_option('query-auth.enabled', 'true')]) + return catalog.get_table('default.numeric'), server + + +@pytest.mark.parametrize('case', _native_cases(), ids=lambda case: case['name']) +def test_existing_numeric_casts_filter_and_mask_natively(rest_catalog, table_mode, case): + source_type = _paimon_type_to_arrow(case['fields'][0]['type']) + target_type = _paimon_type_to_arrow(case['transform']['type']) + count = len(case['rows']) + ids = list(range(1, count + 1)) + schema = pa.schema([('id', pa.int32()), ('v', source_type), ('masked', target_type)]) + data = pa.Table.from_arrays([pa.array(ids, type=pa.int32()), + source_array([row[0] for row in case['rows']], source_type), + pa.nulls(count, type=target_type)], schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + grant_key = table.identifier.get_full_name() + server.table_query_auth_store[grant_key] = AuthTableQueryResponse( + column_masking={'masked': json.dumps(case['transform'])}) + expected = source_array(case['values'], target_type) + non_null = [id_ for id_, value in zip(ids, case['values']) if value is not None] + for native in [False, True]: + result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) + assert result.column('masked').combine_chunks().equals(expected) + # Original masked values are all NULL: evaluating the user's predicate + # before the mask would lose every row, and LIMIT must follow filtering. + predicate = PredicateBuilder(table.fields).is_not_null('masked') + assert _read(table, native, ['id'], predicate, limit=1).to_pylist() == ( + [{'id': non_null[0]}] if non_null else []) + selected = next((value for value in case['values'] if value is not None), None) + rule = {'kind': 'LEAF', 'transform': case['transform'], + 'function': 'IS_NULL' if selected is None else 'EQUAL', + 'literals': [] if selected is None else [selected]} + server.table_query_auth_store[grant_key] = AuthTableQueryResponse(filter=[json.dumps(rule)]) + matching = [id_ for id_, value in zip(ids, case['values']) if value == selected] + for native in [False, True]: + # Only id is projected: the cast's source must be a hidden dependency. + assert _read(table, native, ['id'], limit=1).to_pylist() == ( + [{'id': matching[0]}] if matching else []) + + +@pytest.mark.parametrize('function', ['AND', 'OR', 'entries']) +def test_numeric_cast_errors_are_short_circuited_per_row(rest_catalog, table_mode, function): + schema = pa.schema([('id', pa.int32()), ('v', pa.string())]) + data = pa.table({'id': [0, 1, 2], 'v': ['bad', '1.9', None]}, schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + guard = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [0 if function == 'OR' else 1], + 'transform': {'name': 'FIELD_REF', 'fieldRef': {'name': 'id', 'type': 'INT'}}} + cast = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [1], 'transform': { + 'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'INT'}} + filters = [guard, cast] if function == 'entries' else [ + {'kind': 'COMPOUND', 'function': function, 'children': [guard, cast]}] + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + filter=[json.dumps(rule) for rule in filters]) + for native in [False, True]: + result = _read(table, native, ['id']).sort_by([('id', 'ascending')]).to_pylist() + assert result == ([{'id': 0}, {'id': 1}] if function == 'OR' else [{'id': 1}]) diff --git a/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py b/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py index 881983b779a3..af6655d99bc4 100644 --- a/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py +++ b/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py @@ -20,9 +20,12 @@ from contextlib import ExitStack from datetime import datetime, timezone from decimal import Decimal +import os from unittest.mock import patch +from urllib.parse import unquote, urlparse import pyarrow as pa +import pyarrow.parquet as pq import pytest from pypaimon import Schema @@ -85,6 +88,37 @@ def _read(table, native, predicate=None, projection=None): return result.sort_by([('id', 'ascending')]) +def test_large_utf8_old_parquet_reads_as_integer_without_native_fallback(rest_catalog): + catalog, _ = rest_catalog + _table(catalog, 'append', pa.string(), ['1.9', '-2.5', None]) + catalog.alter_table('default.t', [SchemaChange.update_column_type('v', AtomicType('INT'))], False) + table = catalog.get_table('default.t') + # Plan once before rewriting the disposable old file. Preserve its logical + # STRING schema while storing the supported LargeUtf8 Arrow representation. + planning_table = table.copy({'scan.native-plan.enabled': 'false', 'read.native.enabled': 'false'}) + splits = planning_table.new_read_builder().new_scan().plan().splits() + assert splits + for split in splits: + for meta in split.files: + path = meta.file_path + if path.startswith('file:'): + path = unquote(urlparse(path).path) + physical = pq.read_table(path) + index = physical.schema.get_field_index('v') + physical = physical.set_column(index, 'v', physical.column('v').cast(pa.large_string())) + pq.write_table(physical, path) + meta.file_size = os.stat(path).st_size + assert pq.read_schema(path).field('v').type == pa.large_string() + for native in (False, True): + reader = table.copy({'read.native.enabled': str(native).lower()}).new_read_builder().new_read() + with ExitStack() as stack: + if native: + stack.enter_context(patch('pypaimon.read.table_read.TableRead._create_split_read', + side_effect=AssertionError('Native read fell back'))) + result = reader.to_arrow(splits).sort_by([('id', 'ascending')]) + assert result.column('v').to_pylist() == [1, -2, None] + + _TEMPORAL_STRING_CASES = [ (pa.time32('ms'), [0, 100, 101, 12345678, None], ['00:00:00.0', '00:00:00.1', '00:00:00.101', '03:25:45.678', None]), From 7d97e226546be32fcc3f61e6206b998f9d93bb67 Mon Sep 17 00:00:00 2001 From: JingsongLi Date: Wed, 14 Oct 2026 14:23:11 +0800 Subject: [PATCH 2/4] [python] Complete Java scalar authorization casts and mask schemas --- .../pypaimon/casting/cast_executor.py | 260 ++ paimon-python/pypaimon/casting/cast_text.py | 154 + .../pypaimon/casting/floating_cast.py | 125 + paimon-python/pypaimon/casting/mask_output.py | 57 + .../pypaimon/casting/numeric_utils.py | 27 + .../pypaimon/casting/temporal_cast.py | 7 +- .../pypaimon/casting/temporal_string.py | 29 +- .../pypaimon/casting/temporal_utils.py | 11 +- .../pypaimon/common/predicate_json_parser.py | 126 +- .../read/reader/auth_masking_reader.py | 9 +- paimon-python/pypaimon/read/table_read.py | 35 +- .../tests/auth_masking_reader_test.py | 55 +- .../authorization_cast_completion_test.py | 2725 +++++++++++++++++ .../pypaimon/tests/mask_output_test.py | 86 + .../tests/native_cast_completion_test.py | 207 ++ .../tests/native_numeric_cast_test.py | 7 +- .../tests/predicate_json_parser_test.py | 8 +- 17 files changed, 3768 insertions(+), 160 deletions(-) create mode 100644 paimon-python/pypaimon/casting/cast_executor.py create mode 100644 paimon-python/pypaimon/casting/cast_text.py create mode 100644 paimon-python/pypaimon/casting/floating_cast.py create mode 100644 paimon-python/pypaimon/casting/mask_output.py create mode 100644 paimon-python/pypaimon/tests/authorization_cast_completion_test.py create mode 100644 paimon-python/pypaimon/tests/mask_output_test.py create mode 100644 paimon-python/pypaimon/tests/native_cast_completion_test.py diff --git a/paimon-python/pypaimon/casting/cast_executor.py b/paimon-python/pypaimon/casting/cast_executor.py new file mode 100644 index 000000000000..fce9a2ceb804 --- /dev/null +++ b/paimon-python/pypaimon/casting/cast_executor.py @@ -0,0 +1,260 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""The existing Python scalar CAST subset with Java's original executor.""" + +import re + +import pyarrow as pa + +from pypaimon.casting.cast_text import format_date, parse_date, parse_timestamp +from pypaimon.casting.floating_cast import parse_java_float +from pypaimon.casting.numeric_cast import cast_numeric, _numeric_to_integer +from pypaimon.casting.numeric_utils import java_number_string +from pypaimon.casting.schema_evolution import _timestamp_to_bigint +from pypaimon.casting.temporal_cast import cast_temporal +from pypaimon.casting.temporal_string import temporal_to_string, timestamp_object_to_string +from pypaimon.casting.temporal_utils import _signed +from pypaimon.table.row.generic_row import _parse_type_precision_scale + + +def _text(t): + return pa.types.is_string(t) or pa.types.is_large_string(t) + + +def _binary(t): + return pa.types.is_binary(t) or pa.types.is_large_binary(t) + + +def _primitive(t): + return pa.types.is_signed_integer(t) or pa.types.is_floating(t) + + +def _numeric(t): + return _primitive(t) or pa.types.is_decimal(t) + + +def _number(t): + return _primitive(t) or pa.types.is_date(t) or pa.types.is_time(t) + + +def _integer_object(t): + return t == pa.int32() or pa.types.is_date(t) or pa.types.is_time(t) + + +def supports_cast(source, target): + if _numeric(source) and _numeric(target): + return True + if pa.types.is_boolean(source) and (_primitive(target) or _text(target)): + return True + if pa.types.is_signed_integer(source) and pa.types.is_boolean(target): + return True + if _text(target) and (_numeric(source) or _text(source) or _binary(source) + or pa.types.is_date(source) or pa.types.is_time(source) or pa.types.is_timestamp(source)): + return True + if _binary(target) and (_text(source) or _binary(source)): + return True + if _text(source) and (_numeric(target) or pa.types.is_boolean(target) + or pa.types.is_date(target) or pa.types.is_timestamp(target)): + return True + if (source == pa.int64() or pa.types.is_date(source)) and pa.types.is_timestamp(target): + return True + if pa.types.is_timestamp(source) and (pa.types.is_timestamp(target) or pa.types.is_date(target) + or pa.types.is_time(target) or target == pa.int64()): + return True + return False + + +def _number_input(array): + if pa.types.is_date(array.type): + return array.cast(pa.date32(), safe=False).cast(pa.int32()) + if pa.types.is_time(array.type): + return array.cast(pa.time32('ms'), safe=False).cast(pa.int32()) + return array + + +def _timestamp_parts(array): + ticks = array.cast(pa.int64()).to_pylist() + unit = array.type.unit + return [None if value is None else + (_signed(value * 1000, 64), 0) if unit == 's' else + (value, 0) if unit == 'ms' else + (value // 1000, value % 1000 * 1000) if unit == 'us' else + (value // 1000000, value % 1000000) for value in ticks] + + +def _timestamp_storage(values, target): + quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] + ticks = [] + for value in values: + if value is None: + ticks.append(None) + continue + millis, nanos = value + full = millis * 1000000 + nanos + if full % quantum or not -(1 << 63) <= full // quantum < (1 << 63): + raise ValueError('Java timestamp result cannot be represented by the Arrow target') + ticks.append(full // quantum) + return pa.array(ticks, type=pa.int64()).cast(target) + + +def _fit_width(array, target): + width = re.fullmatch(r'\s*(CHAR|VARCHAR|BINARY|VARBINARY)(?:\s*\(\s*([0-9]+)\s*\))?' + r'\s*(?:(?:NOT\s+)?NULL)?\s*', target, flags=re.IGNORECASE) + if width is None: + return array + kind, length = width.group(1).upper(), int(width.group(2) or 1) + if not 1 <= length <= (1 << 31) - 1: + raise ValueError('Cast width must be between 1 and 2147483647') + pad = kind in ('CHAR', 'BINARY') + padding = ' ' if kind == 'CHAR' else b'\x00' + return pa.array([None if value is None else + (value[:length] + padding * max(0, length - len(value)) if pad else value[:length]) + for value in array.to_pylist()], type=array.type) + + +def cast_array(array, source_type, target_type): + # Keep the transport parser independent of value execution. + from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow + + source, target = _paimon_type_to_arrow(source_type), _paimon_type_to_arrow(target_type) + if pa.types.is_boolean(target) and (pa.types.is_floating(source) or pa.types.is_decimal(source)): + raise ValueError("Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast") + if not supports_cast(source, target): + raise pa.ArrowNotImplementedError('CAST is outside the existing Python/Java scalar rules: %s -> %s' + % (source_type, target_type)) + if array.null_count == len(array): + return pa.nulls(len(array), type=target) + current = array.type + + def require(valid): + if not valid: + raise ValueError('CAST source no longer has the runtime class its original Java executor expects') + + if _numeric(source) and _text(target): + require(_numeric(current) or _text(current) or pa.types.is_boolean(current) + or pa.types.is_date(current) or pa.types.is_time(current) or pa.types.is_timestamp(current)) + value = _number_input(array) + if pa.types.is_timestamp(value.type): + result = timestamp_object_to_string(value) + elif pa.types.is_floating(value.type): + result = pa.array([None if v is None else java_number_string(v, value.type == pa.float32()) + for v in value.to_pylist()], type=target) + elif pa.types.is_decimal(value.type): + result = pa.array([None if v is None else format(v, 'f') for v in value.to_pylist()], type=target) + else: + result = value.cast(target, safe=False) + elif _numeric(source) and _numeric(target): + require(pa.types.is_decimal(current) if pa.types.is_decimal(source) else _number(current)) + value = _number_input(array) + if pa.types.is_decimal(target) and _primitive(source): + value = (_numeric_to_integer(value, pa.int64()) if pa.types.is_signed_integer(source) + else value.cast(pa.float64(), safe=False)) + result = cast_numeric(value, target) + elif pa.types.is_signed_integer(source) and pa.types.is_boolean(target): + require(_number(current)) + result = _numeric_to_integer(_number_input(array), pa.int64()).cast(target, safe=False) + elif pa.types.is_boolean(source): + require(pa.types.is_boolean(current)) + result = array.cast(target, safe=False) + elif _text(source): + require(_text(current)) + if pa.types.is_floating(target): + result = pa.array([None if v is None else parse_java_float(v, target == pa.float32()) + for v in array.to_pylist()], type=target) + elif pa.types.is_date(target): + result = pa.array([None if v is None else parse_date(v) for v in array.to_pylist()], + type=pa.int32()).cast(target) + elif pa.types.is_timestamp(target): + precision = _parse_type_precision_scale(target_type)[0] + values = [None if v is None else parse_timestamp(v, precision, target.tz is not None) + for v in array.to_pylist()] + result = _timestamp_storage(values, target) + else: + result = cast_numeric(array, target) + if result is None: + result = array.cast(target, safe=False) + elif _binary(source): + require(_binary(current)) + if _text(target): + # Arrow may relabel binary buffers as UTF8 without validating them. + # Java BinaryString preserves these bytes; an Arrow string cannot. + for value in array.to_pylist(): + if value is not None: + value.decode("utf8") + result = array.cast(target, safe=False) + if _text(target): + return result # BinaryToString does not trim/pad character width. + elif pa.types.is_date(source): + if pa.types.is_timestamp(target): + require(_number(current)) + values = _number_input(array) + if target.tz is not None: + integers = _numeric_to_integer(values, pa.int32()).cast(pa.date32()) + result = cast_temporal(integers, target, source_type, target_type, strict=True) + else: + values = _numeric_to_integer(values, pa.int64()).to_pylist() + result = _timestamp_storage( + [None if v is None else (_signed(v * 86400000, 64), 0) for v in values], target) + else: + require(_integer_object(current)) + value = _number_input(array).cast(pa.int32()) + result = (pa.array([None if v is None else format_date(v) for v in value.to_pylist()], type=target) + if _text(target) else value.cast(target)) + elif pa.types.is_time(source): + require(_integer_object(current)) + value = _number_input(array).cast(pa.int32()).cast(pa.time32('ms')) + result = (temporal_to_string(value, source_type, 'STRING') if _text(target) else value.cast(target)) + elif pa.types.is_timestamp(source): + require(pa.types.is_timestamp(current)) + if _text(target): + result = temporal_to_string(array, source_type, 'STRING') + elif target == pa.int64(): + # The original timestamp kind selects the executor even after rebind. + value = array.cast(pa.timestamp(array.type.unit, source.tz)) + result = _timestamp_to_bigint(value) + else: + result = cast_temporal(array, target, source_type, target_type, strict=True) + if result is None: + precision = _parse_type_precision_scale(target_type)[0] + truncate = _parse_type_precision_scale(source_type)[0] > precision + values = [] + for value in _timestamp_parts(array): + if value is None: + values.append(None) + continue + millis, nanos = value + if truncate: + if precision <= 3: + quantum = 10 ** (3 - precision) + millis, nanos = _signed(millis // quantum * quantum, 64), 0 + else: + quantum = 10 ** (9 - precision) + nanos = nanos // quantum * quantum + values.append((millis, nanos)) + result = _timestamp_storage(values, target) + else: # BIGINT -> timestamp uses Number.longValue in epoch seconds. + require(_number(current)) + value = _numeric_to_integer(_number_input(array), pa.int64()) + if target.tz is not None: + result = cast_temporal(value, target, source_type, target_type, strict=True) + else: + values = [None if v is None else (_signed(v * 1000, 64), 0) for v in value.to_pylist()] + result = _timestamp_storage(values, target) + if pa.types.is_timestamp(target) and result.null_count > array.null_count: + raise ValueError('Java timestamp result cannot be represented by the Arrow target') + return _fit_width(result, target_type) diff --git a/paimon-python/pypaimon/casting/cast_text.py b/paimon-python/pypaimon/casting/cast_text.py new file mode 100644 index 000000000000..0def1cb4af9c --- /dev/null +++ b/paimon-python/pypaimon/casting/cast_text.py @@ -0,0 +1,154 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Java BinaryStringUtils date/timestamp text, including SMART resolution.""" + +import re + +from pypaimon.casting.numeric_cast import _parse_integer +from pypaimon.casting.numeric_utils import java_decimal_digit +from pypaimon.casting.temporal_utils import ( + _div, _rem, _signed, _java_date_parts, _ymd_to_epoch_day, + _epoch_day_to_java_date, _local_to_utc_seconds, +) + + +_TRIM = ''.join(chr(i) for i in range(33)) +_DIGITS = re.compile(r'[0-9]+\Z') + + +def _numeric(text): + text = text[1:] if text.startswith('-') else text + return bool(text) and all(java_decimal_digit(ch) is not None for ch in text) + + +def format_date(value): + year, month, day = _java_date_parts(value) + return '-'.join(''.join(chr(48 + _rem(_div(value, divisor), 10)) for divisor in divisors) + for value, divisors in [(year, (1000, 100, 10, 1)), (month, (10, 1)), (day, (10, 1))]) + + +def _days_in_month(year, month): + leap = year % 400 == 0 or year % 4 == 0 and year % 100 != 0 + return 29 if month == 2 and leap else 28 if month == 2 else 30 if month in (4, 6, 9, 11) else ( + 31 if 1 <= month <= 12 else 0) + + +def parse_date(text): + if _numeric(text): + return _parse_integer(text, 32) + position = text.find(' ') + date = text[:position] if position > 0 else text + components = date.split('-') + if len(components) > 3: + raise ValueError('Invalid Java DATE: %s' % text) + values = [0, 1, 1] + for i, component in enumerate(components): + component = component.strip(_TRIM) + if _DIGITS.fullmatch(component) is None or len(component.lstrip('0')) > 10: + raise ValueError('Invalid Java DATE: %s' % text) + values[i] = int(component.lstrip('0') or '0') + if values[i] > (1 << 31) - 1: + raise ValueError('Invalid Java DATE: %s' % text) + year, month, day = values + if not 0 <= year <= 9999 or not 1 <= day <= _days_in_month(year, month): + raise ValueError('Invalid Java DATE: %s' % text) + return _epoch_day_to_java_date(_ymd_to_epoch_day(year, month, day)) + + +def _component(text): + if not text: + return None + if len(text) > 21 or _DIGITS.fullmatch(text) is None: + raise ValueError('Invalid Java timestamp component') + first = int(text[:2]) + if len(text) > 2 and int(text[2:]) != first: + raise ValueError('Conflicting Java timestamp fields') + return first + + +def _time_components(text, space): + parts = text.split(':') + if not (3 if space else 2) <= len(parts) <= 3: + raise ValueError('Invalid Java timestamp time') + values = [_component(parts[0]), _component(parts[1]), None, None] + if len(parts) == 3: + second, dot, fraction = parts[2].partition('.') + values[2] = _component(second) + if dot: + if len(fraction) > 9 or fraction and _DIGITS.fullmatch(fraction) is None: + raise ValueError('Invalid Java timestamp fraction') + values[3] = int(fraction or '0') * 10 ** (9 - len(fraction)) + return values + + +def parse_timestamp(text, precision, local): + if not local and _numeric(text): + ticks = _parse_integer(text, 64) + if precision == 0: + return _signed(ticks * 1000, 64), 0 + if precision == 3: + return ticks, 0 + if precision in (6, 9): + divisor, factor = (1000, 1000) if precision == 6 else (1000000, 1) + return ticks // divisor, ticks % divisor * factor + raise ValueError('Unsupported numeric timestamp precision') + position = next((i for i, ch in enumerate(text) if ch in (' ', 'T')), len(text)) + date, rest = text[:position], text[position:] + parts = date.split('-') + if len(parts) != 3: + raise ValueError('Invalid Java timestamp date: %s' % text) + if not parts[1] and parts[2]: + raise ValueError('Java timestamp day needs its month') + year_text = parts[0] + digits = year_text[1:] if year_text.startswith('+') else year_text + if (_DIGITS.fullmatch(digits) is None or len(digits) > 19 + or (len(digits) <= 4 if year_text.startswith('+') else len(digits) != 4)): + raise ValueError('Invalid Java timestamp year') + year = int(digits) + complete_date = bool(parts[1]) and bool(parts[2]) + month, day = _component(parts[1]), _component(parts[2]) + month, day = 1 if month is None else month, 1 if day is None else day + if not 1 <= year <= 999999999 or not 1 <= month <= 12 or not 1 <= day <= 31: + raise ValueError('Invalid Java timestamp date') + epoch_day = _ymd_to_epoch_day(year, month, min(day, _days_in_month(year, month))) + values = [None] * 4 + if rest.startswith(' '): + other, separator, tail = rest[1:].partition('T') + values = _time_components(other, True) + rest = separator + tail + if rest.startswith('T'): + other = _time_components(rest[1:], False) + for i, value in enumerate(other): + if values[i] is not None and value is not None and values[i] != value: + raise ValueError('Conflicting Java timestamp time') + if value is not None: + values[i] = value + rest = '' + if rest: + raise ValueError('Invalid Java timestamp suffix') + if values[0] == 24 and (values[1] is None and values[2] is not None + or values[2] is None and values[3] is not None): + raise ValueError("Java timestamp requires a minute for 24-hour time with seconds") + hour, minute, second, nanos = [0 if v is None else v for v in values] + if (not 0 <= hour <= 24 or not 0 <= minute <= 59 or not 0 <= second <= 59 + or hour == 24 and (minute != 0 or second != 0 or nanos != 0)): + raise ValueError('Invalid Java timestamp time') + seconds = (epoch_day + (hour == 24 and complete_date)) * 86400 + hour % 24 * 3600 + minute * 60 + second + nanos = nanos // 10 ** (9 - precision) * 10 ** (9 - precision) + millis = _signed((_local_to_utc_seconds(seconds) if local else seconds) * 1000, 64) + return _signed(millis + nanos // 1000000, 64), nanos % 1000000 diff --git a/paimon-python/pypaimon/casting/floating_cast.py b/paimon-python/pypaimon/casting/floating_cast.py new file mode 100644 index 000000000000..886141c41220 --- /dev/null +++ b/paimon-python/pypaimon/casting/floating_cast.py @@ -0,0 +1,125 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Java float text, rounding directly to the target IEEE format.""" + +import math +import re +import struct + + +_TRIM = ''.join(chr(i) for i in range(33)) +_DECIMAL = re.compile(r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?[fFdD]?\Z') +_HEX = re.compile(r'[+-]?0[xX](?:[0-9a-fA-F]+(?:\.[0-9a-fA-F]*)?|\.[0-9a-fA-F]+)' + r'[pP][+-]?[0-9]+[fFdD]?\Z') + + +def _exponent(text): + negative = text.startswith('-') + digits = text.lstrip('+-').lstrip('0') + if len(digits) > 19: + return -(1 << 63) if negative else (1 << 63) - 1 + value = int(digits or '0') + return -value if negative else value + + +def _ieee_ratio(numerator, denominator, negative, single): + fraction, bias, packing = (23, 127, '>I') if single else (52, 1023, '>Q') + unpacking = '>f' if single else '>d' + sign = int(negative) << (31 if single else 63) + + def build(bits): + return struct.unpack(unpacking, struct.pack(packing, bits))[0] + + if not numerator: + return build(sign) + leading = numerator.bit_length() - denominator.bit_length() + if (numerator < denominator << leading if leading >= 0 else numerator << (-leading) < denominator): + leading -= 1 + if leading > bias: + return -math.inf if negative else math.inf + minimum = 1 - bias + if leading < minimum - fraction - 1: + return build(sign) + unit = max(leading, minimum) - fraction + if unit >= 0: + denominator <<= unit + else: + numerator <<= -unit + significand, remainder = divmod(numerator, denominator) + if 2 * remainder > denominator or 2 * remainder == denominator and significand % 2: + significand += 1 + if significand == 1 << (fraction + 1): + significand >>= 1 + unit += 1 + normal = unit + fraction + if normal > bias: + return -math.inf if negative else math.inf + bits = significand if significand < 1 << fraction else ( + (normal + bias) << fraction | (significand - (1 << fraction))) + return build(sign | bits) + + +def parse_java_float(text, single=False): + value = text.strip(_TRIM) + unsigned = value[1:] if value.startswith(('+', '-')) else value + if unsigned == 'NaN': + return math.nan + if unsigned == 'Infinity': + return -math.inf if value.startswith('-') else math.inf + hexadecimal = _HEX.fullmatch(value) is not None + if not hexadecimal and _DECIMAL.fullmatch(value) is None: + raise ValueError("Invalid Java floating value: '%s'" % text) + if value[-1:] in ('f', 'F', 'd', 'D'): + value = value[:-1] + negative = value.startswith('-') + value = value.lstrip('+-') + if hexadecimal: + mantissa, exponent = re.split('[pP]', value[2:]) + whole, _, fraction = mantissa.partition('.') + numerator = int(whole + fraction, 16) + exponent = _exponent(exponent) - 4 * len(fraction) + leading = numerator.bit_length() - 1 + exponent if numerator else 0 + bias, subnormal = (127, -150) if single else (1023, -1075) + if numerator and leading > bias: + return -math.inf if negative else math.inf + if not numerator or leading < subnormal: + return _ieee_ratio(0, 1, negative, single) + return _ieee_ratio(numerator << max(0, exponent), 1 << max(0, -exponent), negative, single) + parts = re.split('[eE]', value) + whole, _, fraction = parts[0].partition('.') + digits = (whole + fraction).lstrip('0') + exponent = (_exponent(parts[1]) if len(parts) == 2 else 0) - len(fraction) + adjusted = len(digits) - 1 + exponent + high, low = (38, -46) if single else (308, -324) + if not digits or adjusted < low: + return _ieee_ratio(0, 1, negative, single) + if adjusted > high: + return -math.inf if negative else math.inf + # Every IEEE midpoint has fewer than 800 significant decimal digits. + # Retain a sticky digit beyond that boundary instead of building unbounded + # decimal powers for a long input that is close to a rounding midpoint. + if len(digits) > 800: + remainder = digits[800:] + exponent += len(remainder) + digits = digits[:800] + if any(ch != '0' for ch in remainder): + digits += '1' + exponent -= 1 + numerator = int(digits) * 10 ** max(0, exponent) + denominator = 10 ** max(0, -exponent) + return _ieee_ratio(numerator, denominator, negative, single) diff --git a/paimon-python/pypaimon/casting/mask_output.py b/paimon-python/pypaimon/casting/mask_output.py new file mode 100644 index 000000000000..238d94428a0f --- /dev/null +++ b/paimon-python/pypaimon/casting/mask_output.py @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Adapt Java mask row objects to their Arrow output representation without loss.""" + +import pyarrow as pa + + +def _integer_object(type_): + return type_ == pa.int32() or type_ == pa.date32() or type_ == pa.time32('ms') + + +def _text(type_): + return (pa.types.is_string(type_) or pa.types.is_large_string(type_) + or getattr(pa.types, 'is_string_view', lambda _: False)(type_)) + + +def _binary(type_): + return (pa.types.is_binary(type_) or pa.types.is_large_binary(type_) + or getattr(pa.types, 'is_binary_view', lambda _: False)(type_)) + + +def cast_mask_output(array, target): + """Decimal and Timestamp getters preserve objects, not declared precision. + + Arrow needs one fixed storage type. Loss of a fractional digit or overflow + is an error, including when the executor itself validly returned NULL. + """ + if array.null_count == len(array): + return pa.nulls(len(array), type=target) + source = array.type + if source == target: + return array + if (pa.types.is_decimal(source) and pa.types.is_decimal(target) + or pa.types.is_timestamp(source) and pa.types.is_timestamp(target)): + # Python Arrow safe casts reject decimal rounding, timestamp truncation + # and overflow; Rust checks the coefficients/ticks before using Arrow. + return array.cast(target, safe=True) + if _integer_object(source) and _integer_object(target): + return array.cast(pa.int32()).cast(target) + if _text(source) and _text(target) or _binary(source) and target == pa.binary(): + return array.cast(target) + raise ValueError('Mask result %s does not have the Java row class of output %s' % (source, target)) diff --git a/paimon-python/pypaimon/casting/numeric_utils.py b/paimon-python/pypaimon/casting/numeric_utils.py index 6a04517f2366..b2cbc6bf449f 100644 --- a/paimon-python/pypaimon/casting/numeric_utils.py +++ b/paimon-python/pypaimon/casting/numeric_utils.py @@ -83,6 +83,30 @@ def java_double_decimal_text(value): Use integer arithmetic over IEEE-754 components to preserve those choices. The emitted coefficient/exponent is numeric text, not a display format. """ + return _floating_decimal_text(value, False) + + +def java_number_string(value, single_precision=False): + """Java 8/11/17 Number.toString; FLOAT uses its own rounding interval.""" + if not math.isfinite(value) or value == 0: + return java_floating_string(value) + text = _floating_decimal_text(value, single_precision) + coefficient, exponent = text.split('e') + sign = '-' if coefficient.startswith('-') else '' + digits = coefficient.lstrip('-') + adjusted = int(exponent) + len(digits) - 1 + digits = digits.rstrip('0') + if adjusted < -3 or adjusted >= 7: + return sign + digits[0] + '.' + (digits[1:] or '0') + 'E' + str(adjusted) + point = adjusted + 1 + if point <= 0: + return sign + '0.' + '0' * (-point) + digits + if point >= len(digits): + return sign + digits + '0' * (point - len(digits)) + '.0' + return sign + digits[:point] + '.' + digits[point:] + + +def _floating_decimal_text(value, single_precision): if not math.isfinite(value): return java_floating_string(value) if value == 0: @@ -99,6 +123,9 @@ def java_double_decimal_text(value): else: significant = 53 mantissa |= 1 << 52 + if single_precision: + bits = struct.unpack('>I', struct.pack('>f', value))[0] + significant = (bits & 0x007fffff).bit_length() if bits & 0x7f800000 == 0 else 24 trailing = (mantissa & -mantissa).bit_length() - 1 width = 53 - trailing tiny = max(0, width - exponent - 1) diff --git a/paimon-python/pypaimon/casting/temporal_cast.py b/paimon-python/pypaimon/casting/temporal_cast.py index 5700100446af..c6f6d1b9fc2e 100644 --- a/paimon-python/pypaimon/casting/temporal_cast.py +++ b/paimon-python/pypaimon/casting/temporal_cast.py @@ -26,7 +26,7 @@ from pypaimon.table.row.generic_row import _parse_type_precision_scale -def cast_temporal(array, target, source_type=None, target_type=None): +def cast_temporal(array, target, source_type=None, target_type=None, strict=False): timestamp = pa.types.is_timestamp(array.type) source_name = str(source_type).upper() if source_type is not None else '' ltz = timestamp and (array.type.tz is not None if source_type is None else @@ -87,6 +87,11 @@ def cast_temporal(array, target, source_type=None, target_type=None): value = millis * 1000 + sub_milli // 1000 else: value = millis * 1000000 + sub_milli + if strict: + quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] + if (millis * 1000000 + sub_milli != value * quantum + or not -(1 << 63) <= value < (1 << 63)): + raise ValueError('Java timestamp result cannot be represented by the Arrow target') if not -(1 << 63) <= value < (1 << 63): value = None values.append(value) diff --git a/paimon-python/pypaimon/casting/temporal_string.py b/paimon-python/pypaimon/casting/temporal_string.py index a47dba3a9ca4..07643ec5c7e0 100644 --- a/paimon-python/pypaimon/casting/temporal_string.py +++ b/paimon-python/pypaimon/casting/temporal_string.py @@ -19,7 +19,7 @@ import pyarrow as pa -from pypaimon.casting.temporal_utils import _epoch_day_to_date, _local_offset +from pypaimon.casting.temporal_utils import _epoch_day_to_date, _local_offset, _signed from pypaimon.table.row.generic_row import _parse_type_precision_scale @@ -118,3 +118,30 @@ def temporal_to_string(array, source_type=None, target_type=None): text = text.ljust(length) values.append(text) return pa.array(values, type=pa.string()) + + +def timestamp_object_to_string(array): + """Java Timestamp.toString: ISO wall time, regardless of the current LTZ zone.""" + values = [] + unit = array.type.unit + for value in array.cast(pa.int64()).to_pylist(): + if value is None: + values.append(None) + continue + millis = (_signed(value * 1000, 64) if unit == 's' else value if unit == 'ms' + else value // (1000 if unit == 'us' else 1000000)) + sub = value % (1000 if unit == 'us' else 1000000) * (1000 if unit == 'us' else 1) if unit in ('us', 'ns') else 0 + nanos = millis % 1000 * 1000000 + sub + day, second_of_day = divmod(millis // 1000, 86400) + year, month, day = _epoch_day_to_date(_signed(day, 32)) + year_text = ('%04d' % year if 0 <= year <= 9999 else '-%04d' % -year if year < 0 else '+%d' % year) + hour, second_of_day = divmod(second_of_day, 3600) + minute, second = divmod(second_of_day, 60) + text = '%s-%02d-%02dT%02d:%02d' % (year_text, month, day, hour, minute) + if second or nanos: + text += ':%02d' % second + if nanos: + precision = 3 if nanos % 1000000 == 0 else 6 if nanos % 1000 == 0 else 9 + text += '.' + ('%09d' % nanos)[:precision] + values.append(text) + return pa.array(values, type=pa.string()) diff --git a/paimon-python/pypaimon/casting/temporal_utils.py b/paimon-python/pypaimon/casting/temporal_utils.py index 7a923093d10d..8c60cdded0b2 100644 --- a/paimon-python/pypaimon/casting/temporal_utils.py +++ b/paimon-python/pypaimon/casting/temporal_utils.py @@ -68,7 +68,7 @@ def _rem(value, divisor): return value - _div(value, divisor) * divisor -def _java_date_to_epoch_day(date): +def _java_date_parts(date): j = _signed(date + 2440588 + 32044, 32) g, dg = _div(j, 146097), _rem(j, 146097) c = _div((_div(dg, 36524) + 1) * 3, 4) @@ -80,10 +80,19 @@ def _java_date_to_epoch_day(date): m = _div(da * 5 + 308, 153) - 2 d = da - _div((m + 4) * 153, 5) + 122 year, month, day = y - 4800 + _div(m + 2, 12), _rem(m + 2, 12) + 1, d + 1 + return year, month, day + + +def _java_date_to_epoch_day(date): + year, month, day = _java_date_parts(date) leap = year % 400 == 0 or year % 4 == 0 and year % 100 != 0 days = 29 if month == 2 and leap else 28 if month == 2 else 30 if month in (4, 6, 9, 11) else 31 if not 1 <= month <= 12 or not 1 <= day <= days: raise ValueError('Invalid Java DATE conversion: {}-{}-{}'.format(year, month, day)) + return _ymd_to_epoch_day(year, month, day) + + +def _ymd_to_epoch_day(year, month, day): year -= month <= 2 era, yoe = divmod(year, 400) march = month + (-3 if month > 2 else 9) diff --git a/paimon-python/pypaimon/common/predicate_json_parser.py b/paimon-python/pypaimon/common/predicate_json_parser.py index cf2df23bd212..9fc06a652305 100644 --- a/paimon-python/pypaimon/common/predicate_json_parser.py +++ b/paimon-python/pypaimon/common/predicate_json_parser.py @@ -23,7 +23,7 @@ import pyarrow as pa import pyarrow.compute as pc -from pypaimon.casting.numeric_cast import cast_numeric, _numeric_to_integer +from pypaimon.casting.cast_executor import cast_array # utf8_slice_codeunits needs an explicit integer stop on pyarrow 6 _MAX_STOP = 2 ** 31 - 1 @@ -156,32 +156,7 @@ def _apply_predicate_transform(transform: dict, batch: pa.RecordBatch, elif name == "CAST": col = batch.column(transform["fieldRef"]["name"]) - target = transform['type'] - width = re.fullmatch(r"\s*(CHAR|VARCHAR|BINARY|VARBINARY)(?=\s|\(|\Z)" - r"(?:\s*\(\s*([0-9]+)\s*\))?" - r"(?:\s*(?:NOT\s+)?NULL)?\s*", target, flags=re.IGNORECASE) - if width is not None: - kind, length = width.group(1).upper(), int(width.group(2) or 1) - if length < 1 or length > _INT_MAX: - raise ValueError('Cast width must be between 1 and 2147483647') - target_type = pa.string() if kind in ('CHAR', 'VARCHAR') else pa.binary() - else: - target_type = _paimon_type_to_arrow(target) - stored = _paimon_type_to_arrow(transform['fieldRef']['type']) - col = _cast_input_for_java_executor(col, stored, target_type) - result = cast_numeric(col, target_type) - if result is None: - result = pc.cast(col, target_type, safe=False) - # Java CastTransform enforces widths; Arrow uses unbounded arrays. - if width is not None: - pad = kind in ('CHAR', 'BINARY') - padding = ' ' if kind == 'CHAR' else b'\x00' - result = pa.array([ - None if value is None else - (value[:length] + padding * max(0, length - len(value)) if pad else value[:length]) - for value in result.to_pylist() - ], type=target_type) - return result + return cast_array(col, transform['fieldRef']['type'], transform['type']) elif name == "UPPER": input_col = _resolve_transform_input(transform["inputs"][0], batch) @@ -245,74 +220,6 @@ def _apply_predicate_transform(transform: dict, batch: pa.RecordBatch, raise ValueError(f"Unknown transform type: {name}") -def _cast_input_for_java_executor(col, stored, target): - # copyWithNewInputs retains Java's original executor. Character, Boolean - # and byte executors require their original runtime value class. - needs_class = (((pa.types.is_string(stored) or pa.types.is_large_string(stored)) and - not (pa.types.is_string(col.type) or pa.types.is_large_string(col.type))) or - (pa.types.is_boolean(stored) and not pa.types.is_boolean(col.type)) or - ((pa.types.is_binary(stored) or pa.types.is_large_binary(stored)) and - not (pa.types.is_binary(col.type) or pa.types.is_large_binary(col.type)))) - if needs_class: - if col.null_count != len(col): - raise ValueError('CAST source no longer has the runtime type its Java executor expects') - return pa.nulls(len(col), type=target) - - numeric = pa.types.is_integer(stored) or pa.types.is_floating(stored) or pa.types.is_decimal(stored) - if numeric and pa.types.is_boolean(target): - if not pa.types.is_signed_integer(stored): - raise ValueError('Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast') - if pa.types.is_date(col.type): - col = col.cast(pa.date32(), safe=False).cast(pa.int32()) - elif pa.types.is_time(col.type): - col = col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) - if not (pa.types.is_signed_integer(col.type) or pa.types.is_floating(col.type)): - if col.null_count != len(col): - raise ValueError('CAST source no longer has the Number class its Java executor expects') - return pa.nulls(len(col), type=target) - # NumericToBoolean retains Number.longValue, even for a rebound float. - return _numeric_to_integer(col, pa.int64()) - numeric_target = pa.types.is_signed_integer(target) or pa.types.is_floating(target) or pa.types.is_decimal(target) - if numeric and numeric_target: - decimal = pa.types.is_decimal(stored) - primitive = (pa.types.is_signed_integer(col.type) or pa.types.is_floating(col.type) or - pa.types.is_date(col.type) or pa.types.is_time(col.type)) - if (decimal and not pa.types.is_decimal(col.type)) or (not decimal and not primitive): - if col.null_count != len(col): - raise ValueError('CAST source no longer has the Number/Decimal class its Java executor expects') - return pa.nulls(len(col), type=target) - if pa.types.is_date(col.type): - col = col.cast(pa.date32(), safe=False).cast(pa.int32()) - elif pa.types.is_time(col.type): - col = col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) - if pa.types.is_decimal(target) and not decimal: - # NumericPrimitiveToDecimal retains longValue or doubleValue based - # on the stored source family, even when the actual field changes. - col = (_numeric_to_integer(col, pa.int64()) if pa.types.is_signed_integer(stored) - else col.cast(pa.float64(), safe=False)) - if numeric and pa.types.is_string(target) and col.type != stored: - # NumericToString accepts Object. DATE and TIME getters return Integer, - # so this executor prints epoch days / milliseconds, not calendar text. - if pa.types.is_date(col.type): - return col.cast(pa.date32(), safe=False).cast(pa.int32()) - if pa.types.is_time(col.type): - return col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) - if pa.types.is_decimal(col.type): - # Paimon Decimal.toString uses BigDecimal.toPlainString. Arrow may - # emit an exponent for a small scaled decimal, including zero. - return pa.array([None if value is None else format(value, 'f') for value in col.to_pylist()], - type=pa.string()) - if not (pa.types.is_integer(col.type) or pa.types.is_decimal(col.type) or - pa.types.is_boolean(col.type) or pa.types.is_string(col.type) or pa.types.is_large_string(col.type)): - # Timestamp.toString uses LocalDateTime text, and other objects - # have their own formatting. An Arrow cast would authorize other - # rows; refuse the unsupported rebound instead. - if col.null_count != len(col): - raise ValueError('CAST rebound source requires its original Java executor formatting') - return pa.nulls(len(col), type=target) - return col - - def _date_extract(name: str, field_ref: dict, batch: pa.RecordBatch) -> pa.Array: """Java calendar extraction on DATE days or Timestamp milliseconds. @@ -907,9 +814,10 @@ def _convert_literal(literal, target_type: pa.DataType): def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: type_str = paimon_type.strip().upper() + type_str = re.sub(r"(?<=\))\s*(?:NOT\s+)?NULL$|\s+(?:NOT\s+)?NULL$", "", type_str).strip() ltz_match = re.match( - r"^TIMESTAMP\s*\((\d+)\)\s+WITH\s+LOCAL\s+TIME\s+ZONE", type_str) + r"^TIMESTAMP\s*\(([0-9]+)\)\s+WITH\s+LOCAL\s+TIME\s+ZONE$", type_str) if ltz_match: precision = int(ltz_match.group(1)) return pa.timestamp(_timestamp_precision_to_unit(precision), tz="UTC") @@ -919,6 +827,8 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: raise ValueError(f"Cannot parse Paimon type: '{paimon_type}'") base_type = m.group(1).strip() params = m.group(2) + if params is not None and re.fullmatch(r"[0-9]+(?:\s*,\s*[0-9]+)?", params.strip()) is None: + raise ValueError("Invalid Java type parameters: %s" % paimon_type) simple_mapping = { "INT": pa.int32(), @@ -933,13 +843,15 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: "DATE": pa.date32(), } if base_type in simple_mapping: + if params is not None: + raise ValueError("Type does not take parameters: %s" % paimon_type) return simple_mapping[base_type] - if base_type in ("VARCHAR", "CHAR"): - return pa.string() - - if base_type in ("VARBINARY", "BINARY"): - return pa.binary() + if base_type in ("VARCHAR", "CHAR", "VARBINARY", "BINARY"): + length = int(params) if params is not None else 1 + if not 1 <= length <= (1 << 31) - 1: + raise ValueError("Cast width must be between 1 and 2147483647") + return pa.string() if base_type in ("VARCHAR", "CHAR") else pa.binary() if base_type == "TIMESTAMP": precision = int(params) if params else 6 @@ -952,15 +864,17 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: return pa.timestamp(unit, tz="UTC") if base_type == "TIME": - precision = int(params) if params else 6 - unit = _timestamp_precision_to_unit(precision) - return pa.time64(unit) if unit in ("us", "ns") else pa.time32(unit) + _timestamp_precision_to_unit(int(params) if params else 0) + return pa.time32("ms") if base_type == "DECIMAL": if params: parts = [x.strip() for x in params.split(",")] if len(parts) == 2: - return pa.decimal128(int(parts[0]), int(parts[1])) + precision, scale = int(parts[0]), int(parts[1]) + if not 1 <= precision <= 38 or not 0 <= scale <= precision: + raise ValueError("Invalid Java DECIMAL precision/scale: %s" % paimon_type) + return pa.decimal128(precision, scale) raise ValueError(f"DECIMAL type requires (precision, scale): '{paimon_type}'") raise ValueError( @@ -972,6 +886,8 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: def _timestamp_precision_to_unit(precision: int) -> str: + if not 0 <= precision <= 9: + raise ValueError("Timestamp precision must be between 0 and 9") if precision == 0: return "s" elif precision <= 3: diff --git a/paimon-python/pypaimon/read/reader/auth_masking_reader.py b/paimon-python/pypaimon/read/reader/auth_masking_reader.py index f34dbc748ad8..aee4878355f5 100644 --- a/paimon-python/pypaimon/read/reader/auth_masking_reader.py +++ b/paimon-python/pypaimon/read/reader/auth_masking_reader.py @@ -21,6 +21,8 @@ import pyarrow as pa +from pypaimon.casting.mask_output import cast_mask_output + from pypaimon.common.predicate_json_parser import ( _apply_predicate_transform, _collect_all_field_refs_from_transform, @@ -215,13 +217,14 @@ def apply_auth_masking(batch: pa.RecordBatch, parsed_rules: Dict[str, dict]): if col_name in original_batch.schema.names: col_idx = original_batch.schema.get_field_index(col_name) target_col_type = original_batch.schema.field(col_idx).type - masked_columns[col_idx] = _apply_predicate_transform( - transform, original_batch, null_type=target_col_type) + masked_columns[col_idx] = cast_mask_output( + _apply_predicate_transform(transform, original_batch, null_type=target_col_type), + target_col_type) for col_idx, masked_array in masked_columns.items(): original_field = original_batch.schema.field(col_idx) batch = batch.set_column( col_idx, - pa.field(original_field.name, masked_array.type, nullable=True), + original_field.with_type(masked_array.type).with_nullable(True), masked_array) return batch diff --git a/paimon-python/pypaimon/read/table_read.py b/paimon-python/pypaimon/read/table_read.py index a7188cd9c98a..537c2ae7b2f9 100644 --- a/paimon-python/pypaimon/read/table_read.py +++ b/paimon-python/pypaimon/read/table_read.py @@ -40,7 +40,8 @@ from pypaimon.read.reader.filter_record_batch_reader import FilterRecordBatchReader from pypaimon.read.split import Split from pypaimon.read.variant_read_type import has_variant_extractions -from pypaimon.read.read_type import (adapter_output_paths, extract_array, output_schema, reader_adapter) +from pypaimon.read.read_type import ( + OutputProjection, adapter_output_paths, extract_array, output_schema, reader_adapter) from pypaimon.read.split_read import (DataEvolutionSplitRead, MergeFileSplitRead, RawFileSplitRead, SplitRead, deferred_blob_field_names) @@ -294,7 +295,7 @@ def _new_arrow_batch_reader( splits: List[Split], blob_parallelism: Optional[int] = None, parallelism: Optional[int] = None): - schema = self._output_arrow_schema() + schema = self._output_arrow_schema(splits) if self.include_row_kind: schema = self._add_row_kind_to_schema(schema) effective = self._effective_parallelism(parallelism, len(splits)) @@ -392,7 +393,7 @@ def to_arrow( """ effective_bp = self._resolve_blob_parallelism(blob_parallelism) effective = self._effective_parallelism(parallelism, len(splits)) - schema = self._output_arrow_schema() + schema = self._output_arrow_schema(splits) if self.include_row_kind: schema = self._add_row_kind_to_schema(schema) @@ -462,8 +463,23 @@ def _reader_adapter(self): extra_names = {field.name for field in projected[0]} - {field.name for field in adapter[0]} return projected if predicate_field_names(self.predicate) & extra_names else adapter - def _output_arrow_schema(self): - return output_schema(PyarrowFieldParser.from_paimon_schema(self.read_type), self.output_projection) + def _output_arrow_schema(self, splits=None): + schema = PyarrowFieldParser.from_paimon_schema(self.read_type) + masks = set() + if splits: + for split in splits: + if isinstance(split, QueryAuthSplit) and split.auth_result is not None: + masks.update(split.auth_result.column_masking or {}) + elif self.table.options.query_auth_enabled: + # Before a plan or for an empty plan, the grant is unknown. Masks + # may null any top-level column, including a declared NOT NULL one. + masks.update(schema.names) + if masks: + schema = pyarrow.schema([ + field.with_nullable(True) if field.name in masks else field + for field in schema + ], metadata=schema.metadata) + return output_schema(schema, self.output_projection) @staticmethod def _apply_output_projection_to_schema(schema, projection): @@ -1646,13 +1662,18 @@ def _project_batch_to_output(self, batch: pyarrow.RecordBatch) -> pyarrow.Record _, paths = self._reader_adapter() outputs = adapter_output_paths(self.output_projection, self._adapter_read_type, paths) arrays = [extract_array(batch, path) for _, path in outputs] - fields = list(self._output_arrow_schema()) + # Project the already masked schema, retaining captured nullability. + adapted_projection = OutputProjection([(alias, path) for alias, path in outputs]) + actual = output_schema(batch.schema, adapted_projection) + declared = output_schema(PyarrowFieldParser.from_paimon_schema(self.read_type), self.output_projection) + fields = [field.with_nullable(actual[i].nullable) for i, field in enumerate(declared)] if self.include_row_kind and ROW_KIND_COLUMN in batch.schema.names: arrays.insert(0, batch.column(ROW_KIND_COLUMN)) fields.insert(0, batch.schema.field(ROW_KIND_COLUMN)) if not arrays: return batch.select([]) - return pyarrow.RecordBatch.from_arrays(arrays, schema=pyarrow.schema(fields)) + return pyarrow.RecordBatch.from_arrays( + arrays, schema=pyarrow.schema(fields, metadata=batch.schema.metadata)) if not self._needs_output_projection(): return batch output_names = list(self._output_column_names) diff --git a/paimon-python/pypaimon/tests/auth_masking_reader_test.py b/paimon-python/pypaimon/tests/auth_masking_reader_test.py index 66b837cb9712..89ae9cb2ea83 100644 --- a/paimon-python/pypaimon/tests/auth_masking_reader_test.py +++ b/paimon-python/pypaimon/tests/auth_masking_reader_test.py @@ -125,43 +125,24 @@ def test_cast_transform(self): self.assertEqual(result.column("age").type, pa.int64()) self.assertEqual(result.column("age").to_pylist(), [25, 30, 35]) - def test_cast_transform_changes_column_type(self): - """CAST transform changes the output column type (matching Java behavior).""" - batch = pa.RecordBatch.from_pydict( - {"id": pa.array([1, 2, 3], type=pa.int32())}, - schema=pa.schema([("id", pa.int32())]), - ) - fields = [_FakeField("id")] - result = self._apply_masking( - {"id": json.dumps({ - "name": "CAST", - "fieldRef": {"index": 0, "name": "id", "type": "INT"}, - "type": "BIGINT", - })}, - batch=batch, - fields=fields, - ) - self.assertEqual(result.column("id").type, pa.int64()) - self.assertEqual(result.column("id").to_pylist(), [1, 2, 3]) - - def test_cast_transform_int_to_string(self): - """CAST INT to STRING changes column type to string (matching Java).""" - batch = pa.RecordBatch.from_pydict( - {"id": pa.array([100, 200], type=pa.int32())}, - schema=pa.schema([("id", pa.int32())]), - ) - fields = [_FakeField("id")] - result = self._apply_masking( - {"id": json.dumps({ - "name": "CAST", - "fieldRef": {"index": 0, "name": "id", "type": "INT"}, - "type": "STRING", - })}, - batch=batch, - fields=fields, - ) - self.assertEqual(result.column("id").type, pa.string()) - self.assertEqual(result.column("id").to_pylist(), ["100", "200"]) + def test_cast_mask_rejects_a_different_java_output_class(self): + batch = pa.RecordBatch.from_pydict({"id": pa.array([1, 2], type=pa.int32())}) + for target in ("BIGINT", "STRING"): + with self.subTest(target=target), self.assertRaises(ValueError): + self._apply_masking({"id": json.dumps({ + "name": "CAST", "fieldRef": {"name": "id", "type": "INT"}, "type": target, + })}, batch=batch, fields=[_FakeField("id")]) + + def test_cast_masks_preserve_the_target_columns_java_class(self): + for target, arrow_type, expected in [("BIGINT", pa.int64(), [1, 2]), ("STRING", pa.string(), ["1", "2"])]: + batch = pa.RecordBatch.from_arrays([ + pa.array([1, 2], type=pa.int32()), pa.nulls(2, type=arrow_type), + ], names=["id", "masked"]) + result = self._apply_masking({"masked": json.dumps({ + "name": "CAST", "fieldRef": {"name": "id", "type": "INT"}, "type": target, + })}, batch=batch, fields=[_FakeField("id"), _FakeField("masked")]) + self.assertEqual(result.column("masked").type, arrow_type) + self.assertEqual(result.column("masked").to_pylist(), expected) def test_concat_transform(self): result = self._apply_masking({ diff --git a/paimon-python/pypaimon/tests/authorization_cast_completion_test.py b/paimon-python/pypaimon/tests/authorization_cast_completion_test.py new file mode 100644 index 000000000000..8c10120f9355 --- /dev/null +++ b/paimon-python/pypaimon/tests/authorization_cast_completion_test.py @@ -0,0 +1,2725 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Java scalar CAST completion vectors, in three system time zones.""" + +import json +import math +import time +from decimal import Decimal + +import pyarrow as pa +import pytest + +from pypaimon.common.predicate_json_parser import _apply_predicate_transform, _paimon_type_to_arrow + +# Actual Java CastExecutors/PredicateRemapper output on Paimon master 8de6fdbda9. +# JDK 17 and JDK 8 numeric formatting; no NaN or signed-zero vectors. +JAVA_CASES = [ + json.loads( + '{"name":"lexical STRING -> FLOAT","fields":[{"name":"v","type":"STRING"}],"rows":[["1.25"],["+' + '1.25"],[" 1.25 "],["\\t1.25\\n"],["1e3"],["1.25f"],["1.25D"],["0x1.8p2"],["0X1.8P+2f"],["1e-7"],' + '["1e400"],["\\uff11.\\uff12\\uff15"],["1_000"],["1.25junk"],[""],["bad"],[null]],"transform":{"na' + 'me":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"FLOAT"},"expected":{"UTC' + '":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"Nu' + 'mberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' + 'ror":"NumberFormatException"},{"error":"NumberFormatException"},null],"Asia/Shanghai":[1.25,1.' + '25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"NumberFormat' + 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"Numb' + 'erFormatException"},{"error":"NumberFormatException"},null],"America/New_York":[1.25,1.25,1.25' + ',1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"NumberFormatExcepti' + 'on"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberForma' + 'tException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"lexical STRING -> DOUBLE","fields":[{"name":"v","type":"STRING"}],"rows":[["1.25"],["' + '+1.25"],[" 1.25 "],["\\t1.25\\n"],["1e3"],["1.25f"],["1.25D"],["0x1.8p2"],["0X1.8P+2f"],["1e-7"]' + ',["1e400"],["\\uff11.\\uff12\\uff15"],["1_000"],["1.25junk"],[""],["bad"],[null]],"transform":{"n' + 'ame":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"DOUBLE"},"expected":{"U' + 'TC":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1e-07,"Infinity",{"error":"NumberFormatExcep' + 'tion"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFor' + 'matException"},{"error":"NumberFormatException"},null],"Asia/Shanghai":[1.25,1.25,1.25,1.25,10' + '00.0,1.25,1.25,6.0,6.0,1e-07,"Infinity",{"error":"NumberFormatException"},{"error":"NumberForm' + 'atException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"Nu' + 'mberFormatException"},null],"America/New_York":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1' + 'e-07,"Infinity",{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"' + 'NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},nu' + 'll]}}' + ), + json.loads( + '{"name":"format FLOAT -> STRING","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.25],[' + '0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.4028234663852886e+3' + '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"type"' + ':"STRING"},"expected":{"UTC":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","1.0E23"' + ',"1.6777216E7","0.1","3.4028235E38",null],"Asia/Shanghai":["1.0","1.25","0.001","1.0E-4","1.0E' + '-7","1.0E7","1.0E20","1.0E23","1.6777216E7","0.1","3.4028235E38",null],"America/New_York":["1.' + '0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","1.0E23","1.6777216E7","0.1","3.4028235E3' + '8",null]}}' + ), + json.loads( + '{"name":"format DOUBLE -> STRING","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1.25]' + ',[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.797693134' + '8623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DOU' + 'BLE"},"type":"STRING"},"expected":{"UTC":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E' + '20","9.999999999999999E22","9.007199254740992E15","0.1","1.7976931348623157E308",null],"Asia/S' + 'hanghai":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","9.999999999999999E22","9.00' + '7199254740992E15","0.1","1.7976931348623157E308",null],"America/New_York":["1.0","1.25","0.001' + '","1.0E-4","1.0E-7","1.0E7","1.0E20","9.999999999999999E22","9.007199254740992E15","0.1","1.79' + '76931348623157E308",null]}}' + ), + json.loads( + '{"name":"format FLOAT -> CHAR(3)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.25],' + '[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.4028234663852886e+' + '38],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"type' + '":"CHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3' + '.4",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.4",n' + 'ull],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.4",nul' + 'l]}}' + ), + json.loads( + '{"name":"format DOUBLE -> CHAR(3)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1.25' + '],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.79769313' + '48623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DO' + 'UBLE"},"type":"CHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9' + '.0","0.1","1.7",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.0","' + '0.1","1.7",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.0","0.' + '1","1.7",null]}}' + ), + json.loads( + '{"name":"format FLOAT -> VARCHAR(3)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.2' + '5],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.402823466385288' + '6e+38],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"t' + 'ype":"VARCHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0' + '.1","3.4",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","' + '3.4",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.' + '4",null]}}' + ), + json.loads( + '{"name":"format DOUBLE -> VARCHAR(3)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1' + '.25],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.79769' + '31348623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":' + '"DOUBLE"},"type":"VARCHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9' + '.9","9.0","0.1","1.7",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","' + '9.0","0.1","1.7",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.' + '0","0.1","1.7",null]}}' + ), + json.loads( + '{"name":"bytes-width BINARY(8) -> STRING","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[[' + '[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[' + '195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIN' + 'ARY(8)"},"type":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd' + '\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\uff' + 'fd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b",' + '"\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width BINARY(8) -> CHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[' + '[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[' + '[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BI' + 'NARY(8)"},"type":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\uff' + 'fd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\u' + 'fffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b' + '","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width BINARY(8) -> VARCHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows' + '":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]' + '],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":' + '"BINARY(8)"},"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd"' + ',"\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufff' + 'd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9' + '\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width VARBINARY(32) -> STRING","fields":[{"name":"v","type":"VARBINARY(32)"}],"' + 'rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,' + '128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","ty' + 'pe":"VARBINARY(32)"},"type":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\uf' + 'ffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\' + 'ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u' + '00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width VARBINARY(32) -> CHAR(3)","fields":[{"name":"v","type":"VARBINARY(32)"}],' + '"rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128' + ',128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","t' + 'ype":"VARBINARY(32)"},"type":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\' + 'ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b",' + '"\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","' + '\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width VARBINARY(32) -> VARCHAR(3)","fields":[{"name":"v","type":"VARBINARY(32)"' + '}],"rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,' + '128,128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v"' + ',"type":"VARBINARY(32)"},"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\uff' + 'fd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u' + '732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abc' + 'def","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width BYTES -> STRING","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,98,9' + '9,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,40]]' + ',[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"},"ty' + 'pe":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd' + '\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\' + 'ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\ufffd","\\u' + 'fffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width BYTES -> CHAR(3)","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,98,' + '99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,40]' + '],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"},"t' + 'ype":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\uff' + 'fd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufff' + 'd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\ufffd","' + '\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"bytes-width BYTES -> VARCHAR(3)","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,' + '98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,' + '40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"}' + ',"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\uff' + 'fd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd",' + '"\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\uf' + 'ffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' + ), + json.loads( + '{"name":"text-time STRING -> DATE","fields":[{"name":"v","type":"STRING"}],"rows":[["1970-01-0' + '2"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 03:04:05.' + '006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-29"],["20' + '01-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1"],["-1"' + '],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST","field' + 'Ref":{"index":99,"name":"v","type":"STRING"},"type":"DATE"},"expected":{"UTC":[1,1,{"error":"D' + 'ateTimeException"},1,1,-1,11016,{"error":"DateTimeException"},{"error":"DateTimeException"},1,' + '1,1970,31,0,1,-1,1001,-1001,{"error":"NumberFormatException"},{"error":"DateTimeException"},nu' + 'll],"Asia/Shanghai":[1,1,{"error":"DateTimeException"},1,1,-1,11016,{"error":"DateTimeExceptio' + 'n"},{"error":"DateTimeException"},1,1,1970,31,0,1,-1,1001,-1001,{"error":"NumberFormatExceptio' + 'n"},{"error":"DateTimeException"},null],"America/New_York":[1,1,{"error":"DateTimeException"},' + '1,1,-1,11016,{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1970,31,0,1,-1,10' + '01,-1001,{"error":"NumberFormatException"},{"error":"DateTimeException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(0)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(0)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1000,"nanos":0},' + '{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExc' + 'eption"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970000,"n' + 'anos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{' + '"millis":-1000,"nanos":0},{"millis":1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis"' + ':-1000,"nanos":0},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":86400000' + ',"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimePars' + 'eException"},{"error":"DateTimeParseException"},{"millis":-1000,"nanos":0},{"millis":951782400' + '000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":' + '86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970000,"nanos":0},{"error":"' + 'DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":-1000,"nan' + 'os":0},{"millis":1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{' + '"error":"DateTimeParseException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"mi' + 'llis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"e' + 'rror":"DateTimeParseException"},{"millis":-1000,"nanos":0},{"millis":951782400000,"nanos":0},{' + '"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos"' + ':0},{"error":"DateTimeParseException"},{"millis":1970000,"nanos":0},{"error":"DateTimeParseExc' + 'eption"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis"' + ':1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"error":"DateTim' + 'eParseException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(1)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(1)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{' + '"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExce' + 'ption"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeExce' + 'ption"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeExcep' + 'tion"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},' + '{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"milli' + 's":86400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"error":"D' + 'ateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{"millis"' + ':951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},' + '{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},' + '{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{' + '"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error"' + ':"RuntimeException"},{"error":"DateTimeParseException"},null],"America/New_York":[{"millis":86' + '400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"error":"DateTi' + 'meParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{"millis":9517' + '82400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"mil' + 'lis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"err' + 'or":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"erro' + 'r":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Run' + 'timeException"},{"error":"DateTimeParseException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(2)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(2)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"' + 'millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExcep' + 'tion"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeExcep' + 'tion"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeExcept' + 'ion"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{' + '"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis' + '":86400000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"error":"Da' + 'teTimeParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"millis":9' + '51782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"' + 'millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"' + 'error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"e' + 'rror":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"' + 'RuntimeException"},{"error":"DateTimeParseException"},null],"America/New_York":[{"millis":8640' + '0000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"error":"DateTime' + 'ParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"millis":9517824' + '00000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' + '":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error"' + ':"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":' + '"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Runtim' + 'eException"},{"error":"DateTimeParseException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":0},{"millis":97445123,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"m' + 'illis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExcept' + 'ion"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970,"nanos":' + '0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":' + '-1,"nanos":0},{"millis":1001,"nanos":0},{"millis":-1001,"nanos":0},{"millis":92233720368547758' + '07,"nanos":0},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":86400000,"na' + 'nos":0},{"millis":97445123,"nanos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseExc' + 'eption"},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"na' + 'nos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":8640000' + '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970,"nanos":0},{"error":"DateTimePa' + 'rseException"},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":-1,"nanos":0},{"millis"' + ':1001,"nanos":0},{"millis":-1001,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"error":' + '"DateTimeParseException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"millis":97' + '445123,"nanos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' + 'ateTimeParseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"nanos":0},{"millis":98' + '3318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error' + '":"DateTimeParseException"},{"millis":1970,"nanos":0},{"error":"DateTimeParseException"},{"mil' + 'lis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":-1,"nanos":0},{"millis":1001,"nanos":0},{"m' + 'illis":-1001,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"error":"DateTimeParseExcept' + 'ion"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(4)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(4)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445123,"nanos":4' + '00000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' + 'os":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error"' + ':"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":' + '"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Runtim' + 'eException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shang' + 'hai":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445123,"nan' + 'os":400000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1' + ',"nanos":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":' + '"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"e' + 'rror":"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"er' + 'ror":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"R' + 'untimeException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Ameri' + 'ca/New_York":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445' + '123,"nanos":400000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mi' + 'llis":-1,"nanos":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{' + '"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseExcepti' + 'on"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeExceptio' + 'n"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"e' + 'rror":"RuntimeException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null' + ']}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":97445123,"nanos":4' + '56000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' + 'os":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' + '":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nan' + 'os":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"nanos":999000},' + '{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},null],"Asia/Shan' + 'ghai":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":97445123,"na' + 'nos":456000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-' + '1,"nanos":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error"' + ':"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"' + 'millis":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":' + '0,"nanos":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"nanos":99' + '9000},{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},null],"Ame' + 'rica/New_York":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":974' + '45123,"nanos":456000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"' + 'millis":-1,"nanos":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0}' + ',{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseExcep' + 'tion"},{"millis":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{' + '"millis":0,"nanos":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"' + 'nanos":999000},{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},n' + 'ull]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(9)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' + '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' + '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' + '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' + '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' + '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(9)"},"expected":{"UTC":' + '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":4' + '56789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' + 'os":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' + '":0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos' + '":1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"mil' + 'lis":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{' + '"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":456' + '789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nanos' + '":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTi' + 'meParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":' + '0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos":' + '1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"milli' + 's":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null],"America/New_York":[' + '{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":45' + '6789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nano' + 's":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateT' + 'imeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis"' + ':0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos"' + ':1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"mill' + 'is":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"' + 'STRING"}],"rows":[["1970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.12345' + '6789"],["1970-01-02 03:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.99' + '9999999"],["2000-02-29"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],' + '["1970-02"],["0"],["1"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"tra' + 'nsform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)' + ' WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":97445123,"n' + 'anos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimePa' + 'rseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"nanos":0},{"millis":98331840000' + '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTi' + 'meParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"err' + 'or":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcept' + 'ion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTime' + 'ParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000,' + '"nanos":0},{"millis":68645123,"nanos":0},{"millis":68645123,"nanos":0},{"error":"DateTimeParse' + 'Exception"},{"error":"DateTimeParseException"},{"millis":-28800001,"nanos":0},{"millis":951753' + '600000,"nanos":0},{"millis":983289600000,"nanos":0},{"error":"DateTimeParseException"},{"milli' + 's":57600000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{' + '"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' + 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' + 'TimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nul' + 'l],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":115445123,"nanos":0},{"millis"' + ':115445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"' + 'millis":17999999,"nanos":0},{"millis":951800400000,"nanos":0},{"millis":983336400000,"nanos":0' + '},{"error":"DateTimeParseException"},{"millis":104400000,"nanos":0},{"error":"DateTimeParseExc' + 'eption"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateT' + 'imeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"er' + 'ror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcep' + 'tion"},{"error":"DateTimeParseException"},null]}}' + ), + json.loads( + '{"name":"text-time STRING -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"' + 'STRING"}],"rows":[["1970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.12345' + '6789"],["1970-01-02 03:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.99' + '9999999"],["2000-02-29"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],' + '["1970-02"],["0"],["1"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"tra' + 'nsform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)' + ' WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":97445123,"n' + 'anos":456000},{"millis":97445123,"nanos":456000},{"error":"DateTimeParseException"},{"error":"' + 'DateTimeParseException"},{"millis":-1,"nanos":999000},{"millis":951782400000,"nanos":0},{"mill' + 'is":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{' + '"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' + 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' + 'TimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"e' + 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"mi' + 'llis":57600000,"nanos":0},{"millis":68645123,"nanos":456000},{"millis":68645123,"nanos":456000' + '},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-28800001,"n' + 'anos":999000},{"millis":951753600000,"nanos":0},{"millis":983289600000,"nanos":0},{"error":"Da' + 'teTimeParseException"},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"erro' + 'r":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcepti' + 'on"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeP' + 'arseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error"' + ':"DateTimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":' + '115445123,"nanos":456000},{"millis":115445123,"nanos":456000},{"error":"DateTimeParseException' + '"},{"error":"DateTimeParseException"},{"millis":17999999,"nanos":999000},{"millis":95180040000' + '0,"nanos":0},{"millis":983336400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":10' + '4400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"err' + 'or":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcept' + 'ion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTime' + 'ParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},null]}}' + ), + json.loads( + '{"name":"date DATE -> STRING","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1],[0]' + ',[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"index"' + ':99,"name":"v","type":"DATE"},"type":"STRING"},"expected":{"UTC":["0000-01-01","1969-12-31","1' + '970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(",")*,0-0+-0)",null],"Asia/Shanghai":["0000-01' + '-01","1969-12-31","1970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(",")*,0-0+-0)",null],"Amer' + 'ica/New_York":["0000-01-01","1969-12-31","1970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(","' + ')*,0-0+-0)",null]}}' + ), + json.loads( + '{"name":"date DATE -> CHAR(5)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1],[0' + '],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"index' + '":99,"name":"v","type":"DATE"},"type":"CHAR(5)"},"expected":{"UTC":["0000-","1969-","1970-","1' + '970-","2000-",")*,0-",")*,0-",null],"Asia/Shanghai":["0000-","1969-","1970-","1970-","2000-","' + ')*,0-",")*,0-",null],"America/New_York":["0000-","1969-","1970-","1970-","2000-",")*,0-",")*,0' + '-",null]}}' + ), + json.loads( + '{"name":"date DATE -> VARCHAR(5)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1]' + ',[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"in' + 'dex":99,"name":"v","type":"DATE"},"type":"VARCHAR(5)"},"expected":{"UTC":["0000-","1969-","197' + '0-","1970-","2000-",")*,0-",")*,0-",null],"Asia/Shanghai":["0000-","1969-","1970-","1970-","20' + '00-",")*,0-",")*,0-",null],"America/New_York":["0000-","1969-","1970-","1970-","2000-",")*,0-"' + ',")*,0-",null]}}' + ), + json.loads( + '{"name":"date DATE -> TIMESTAMP(3)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-' + '1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"' + 'index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-62167' + '219200000,"nanos":0},{"millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,' + '"nanos":0},{"millis":951782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis"' + ':-185542587187200000,"nanos":0},null],"Asia/Shanghai":[{"millis":-62167219200000,"nanos":0},{"' + 'millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":95' + '1782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"n' + 'anos":0},null],"America/New_York":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"n' + 'anos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0' + '},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"date DATE -> TIMESTAMP(6)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-' + '1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"' + 'index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-62167' + '219200000,"nanos":0},{"millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,' + '"nanos":0},{"millis":951782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis"' + ':-185542587187200000,"nanos":0},null],"Asia/Shanghai":[{"millis":-62167219200000,"nanos":0},{"' + 'millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":95' + '1782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"n' + 'anos":0},null],"America/New_York":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"n' + 'anos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0' + '},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"date DATE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"DATE"}]' + ',"rows":[[-719528],[-1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name"' + ':"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(3) WITH LOCAL TIME ' + 'ZONE"},"expected":{"UTC":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"nanos":0},' + '{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0},{"error' + '":"DateTimeException"},{"error":"DateTimeException"},null],"Asia/Shanghai":[{"millis":-6216724' + '8343000,"nanos":0},{"millis":-115200000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":57' + '600000,"nanos":0},{"millis":951753600000,"nanos":0},{"error":"DateTimeException"},{"error":"Da' + 'teTimeException"},null],"America/New_York":[{"millis":-62167201438000,"nanos":0},{"millis":-68' + '400000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":104400000,"nanos":0},{"millis":95180' + '0400000,"nanos":0},{"error":"DateTimeException"},{"error":"DateTimeException"},null]}}' + ), + json.loads( + '{"name":"time-text TIME(0) -> STRING","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0],[10' + '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' + '"index":99,"name":"v","type":"TIME(0)"},"type":"STRING"},"expected":{"UTC":["00:00:00","00:00:' + '00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"Asia/Shanghai":["00:00:00","' + '00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"America/New_York":["00' + ':00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null]}}' + ), + json.loads( + '{"name":"time-text TIME(0) -> CHAR(12)","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0],[' + '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIME(0)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00 "' + ',"00:00:00 ","00:00:00 ","03:04:05 ","23:59:59 ","23:59:59 ","24:00:00 ",nul' + 'l],"Asia/Shanghai":["00:00:00 ","00:00:00 ","00:00:00 ","03:04:05 ","23:59:59 "' + ',"23:59:59 ","24:00:00 ",null],"America/New_York":["00:00:00 ","00:00:00 ","00:00:' + '00 ","03:04:05 ","23:59:59 ","23:59:59 ","24:00:00 ",null]}}' + ), + json.loads( + '{"name":"time-text TIME(0) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0' + '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"TIME(0)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' + '0","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"Asia/Shanghai":["0' + '0:00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"America/New_' + 'York":["00:00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null]}}' + ), + json.loads( + '{"name":"time-text TIME(1) -> STRING","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0],[10' + '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' + '"index":99,"name":"v","type":"TIME(1)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' + '0:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",null],"Asia/Shanghai"' + ':["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",n' + 'ull],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:' + '59:59.9","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"time-text TIME(1) -> CHAR(12)","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0],[' + '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIME(1)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' + ',"00:00:00.1 ","00:00:00.1 ","03:04:05.0 ","23:59:59.9 ","23:59:59.9 ","24:00:00.0 ",nul' + 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.1 ","03:04:05.0 ","23:59:59.9 "' + ',"23:59:59.9 ","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' + '00.1 ","03:04:05.0 ","23:59:59.9 ","23:59:59.9 ","24:00:00.0 ",null]}}' + ), + json.loads( + '{"name":"time-text TIME(1) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0' + '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"TIME(1)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' + '0.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",null],"Asia' + '/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:' + '00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:' + '59.9","23:59:59.9","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"time-text TIME(3) -> STRING","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[10' + '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' + '"index":99,"name":"v","type":"TIME(3)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' + '0:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null],"Asia/S' + 'hanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999' + '","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.00' + '6","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"time-text TIME(3) -> CHAR(12)","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[' + '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIME(3)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' + ',"00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",nul' + 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999"' + ',"23:59:59.999","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' + '00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",null]}}' + ), + json.loads( + '{"name":"time-text TIME(3) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0' + '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"TIME(3)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' + '0.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",nul' + 'l],"Asia/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23' + ':59:59.999","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","0' + '3:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"time-text TIME(6) -> STRING","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0],[10' + '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' + '"index":99,"name":"v","type":"TIME(6)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' + '0:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null],"Asia/S' + 'hanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999' + '","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.00' + '6","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"time-text TIME(6) -> CHAR(12)","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0],[' + '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIME(6)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' + ',"00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",nul' + 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999"' + ',"23:59:59.999","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' + '00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",null]}}' + ), + json.loads( + '{"name":"time-text TIME(6) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0' + '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"TIME(6)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' + '0.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",nul' + 'l],"Asia/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23' + ':59:59.999","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","0' + '3:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(0)","fields":[{"name":"v","type":"BIGINT"}],"rows":' + '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(0)"},"e' + 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' + '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' + 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' + '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' + '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' + '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(3)","fields":[{"name":"v","type":"BIGINT"}],"rows":' + '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(3)"},"e' + 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' + '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' + 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' + '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' + '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' + '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(6)","fields":[{"name":"v","type":"BIGINT"}],"rows":' + '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(6)"},"e' + 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' + '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' + 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' + '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' + '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' + '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(9)","fields":[{"name":"v","type":"BIGINT"}],"rows":' + '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' + 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(9)"},"e' + 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' + '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' + 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' + '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' + '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' + '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","typ' + 'e":"BIGINT"}],"rows":[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-92233720368547758' + '08],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' + 'e":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001000,"nanos":0},{"mil' + 'lis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"n' + 'anos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null],"Asia/Shanghai":[{"millis":27' + '799000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":288010' + '00,"nanos":0},{"millis":1263367000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000' + ',"nanos":0},null],"America/New_York":[{"millis":-19001000,"nanos":0},{"millis":-18001000,"nano' + 's":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1216567000,"nano' + 's":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"epoch-seconds BIGINT -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","typ' + 'e":"BIGINT"}],"rows":[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-92233720368547758' + '08],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' + 'e":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001000,"nanos":0},{"mil' + 'lis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"n' + 'anos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null],"Asia/Shanghai":[{"millis":27' + '799000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":288010' + '00,"nanos":0},{"millis":1263367000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000' + ',"nanos":0},null],"America/New_York":[{"millis":-19001000,"nanos":0},{"millis":-18001000,"nano' + 's":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1216567000,"nano' + 's":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,' + '-1,0,0,1,1710037800,1730597400,1710055800,1730615400,9223372036854775,-9223372036854776,null],' + '"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,9223372036854775,-' + '9223372036854776,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,173' + '0615400,9223372036854775,-9223372036854776,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows":' + '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' + '00123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0' + ',0,0,19792,20030,19792,20030,-622191233,622191232,null],"Asia/Shanghai":[-1,-1,-1,0,0,0,19792,' + '20030,19792,20030,-622191233,622191232,null],"America/New_York":[-1,-1,-1,0,0,0,19792,20030,19' + '792,20030,-622191233,622191232,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIME(0)"},"expected":{"UTC":[8639' + '8999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60424192,null],"Asi' + 'a/Shanghai":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60' + '424192,null],"America/New_York":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,' + '23400123,25975807,60424192,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIME(3)"},"expected":{"UTC":[8639' + '8999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60424192,null],"Asi' + 'a/Shanghai":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60' + '424192,null],"America/New_York":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,' + '23400123,25975807,60424192,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"STRING"},"expected":{"UTC":["1969-' + '12-31 23:59:58.999","1969-12-31 23:59:59.000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.0' + '00","1970-01-01 00:00:00.001","1970-01-01 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 ' + '01:30:00.123","2024-03-10 07:30:00.123","2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5' + '471-09-26 16:47:04.192",null],"Asia/Shanghai":["1969-12-31 23:59:58.999","1969-12-31 23:59:59.' + '000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.000","1970-01-01 00:00:00.001","1970-01-01' + ' 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 01:30:00.123","2024-03-10 07:30:00.123","' + '2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5471-09-26 16:47:04.192",null],"America/Ne' + 'w_York":["1969-12-31 23:59:58.999","1969-12-31 23:59:59.000","1969-12-31 23:59:59.999","1970-0' + '1-01 00:00:00.000","1970-01-01 00:00:00.001","1970-01-01 00:00:01.001","2024-03-10 02:30:00.12' + '3","2024-11-03 01:30:00.123","2024-03-10 07:30:00.123","2024-11-03 06:30:00.123","/+-.-04-06 0' + '7:12:55.807","5471-09-26 16:47:04.192",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],' + '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' + '730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST",' + '"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"VARCHAR(12)"},"expected":{"UT' + 'C":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0",' + '"2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","5471-09-26 1",null' + '],"Asia/Shanghai":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0",' + '"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","547' + '1-09-26 1",null],"America/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 ' + '0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","' + '/+-.-04-06 0","5471-09-26 1",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' + ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(0)"},"expected":{"' + 'UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"milli' + 's":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nano' + 's":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":17306154' + '00000,"nanos":0},{"millis":9223372036854775000,"nanos":0},{"millis":9223372036854775616,"nanos' + '":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1' + '000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"milli' + 's":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos"' + ':0},{"millis":1730615400000,"nanos":0},{"millis":9223372036854775000,"nanos":0},{"millis":9223' + '372036854775616,"nanos":0},null],"America/New_York":[{"millis":-2000,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' + '":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"mill' + 'is":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":9223372036854775000,' + '"nanos":0},{"millis":9223372036854775616,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' + ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(1)"},"expected":{"' + 'UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis' + '":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos' + '":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":173061540' + '0100,"nanos":0},{"millis":9223372036854775800,"nanos":0},{"millis":9223372036854775716,"nanos"' + ':0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-10' + '0,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis"' + ':1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0' + '},{"millis":1730615400100,"nanos":0},{"millis":9223372036854775800,"nanos":0},{"millis":922337' + '2036854775716,"nanos":0},null],"America/New_York":[{"millis":-1100,"nanos":0},{"millis":-1000,' + '"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1' + '000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis"' + ':1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":9223372036854775800,"na' + 'nos":0},{"millis":9223372036854775716,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' + ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(3)"},"expected":{"' + 'UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":' + '0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":' + '0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":17306154001' + '23,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":' + '0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"' + 'nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17' + '10037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{' + '"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720' + '36854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"n' + 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,' + '"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":171' + '0055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos"' + ':0},{"millis":-9223372036854775808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' + ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(6)"},"expected":{"' + 'UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":' + '0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":' + '0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":17306154001' + '23,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":' + '0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"' + 'nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17' + '10037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{' + '"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720' + '36854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"n' + 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,' + '"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":171' + '0055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos"' + ':0},{"millis":-9223372036854775808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"tran' + 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTA' + 'MP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"na' + 'nos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"' + 'nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710' + '055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-53757322505224193,"nanos":0' + '},{"millis":53757322505224192,"nanos":0},null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0}' + ',{"millis":-28801000,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},' + '{"millis":-28799999,"nanos":0},{"millis":-28798999,"nanos":0},{"millis":1710009000123,"nanos":' + '0},{"millis":1730568600123,"nanos":0},{"millis":1710027000123,"nanos":0},{"millis":17305866001' + '23,"nanos":0},{"millis":-53757322534367193,"nanos":0},{"millis":53757322476424192,"nanos":0},n' + 'ull],"America/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis"' + ':17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":180' + '01001,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"milli' + 's":1710070200123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":-53757322487462193,"n' + 'anos":0},{"millis":53757322519624192,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"tran' + 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTA' + 'MP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"na' + 'nos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"' + 'nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710' + '055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-53757322505224193,"nanos":0' + '},{"millis":53757322505224192,"nanos":0},null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0}' + ',{"millis":-28801000,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},' + '{"millis":-28799999,"nanos":0},{"millis":-28798999,"nanos":0},{"millis":1710009000123,"nanos":' + '0},{"millis":1730568600123,"nanos":0},{"millis":1710027000123,"nanos":0},{"millis":17305866001' + '23,"nanos":0},{"millis":-53757322534367193,"nanos":0},{"millis":53757322476424192,"nanos":0},n' + 'ull],"America/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis"' + ':17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":180' + '01001,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"milli' + 's":1710070200123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":-53757322487462193,"n' + 'anos":0},{"millis":53757322519624192,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":' + '1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' + '6)"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,17306' + '15400,-1,0,1,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400' + ',-1,0,1,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-' + '1,0,1,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows":' + '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' + '00123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":10' + '00}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6)' + '"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia' + '/Shanghai":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"America/New_York":[-1,-1,-1,0' + ',0,0,19792,20030,19792,20030,-1,0,0,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos"' + ':1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(6)"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123' + ',27000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,' + '9000123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,' + '86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos"' + ':1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(6)"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123' + ',27000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,' + '9000123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,' + '86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":' + '1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' + '6)"},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999000","1969-12-31 23:59:59.000' + '000","1969-12-31 23:59:59.999000","1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1' + '970-01-01 00:00:01.001000","2024-03-10 02:30:00.123000","2024-11-03 01:30:00.123000","2024-03-' + '10 07:30:00.123000","2024-11-03 06:30:00.123000","1969-12-31 23:59:59.999999","1970-01-01 00:0' + '0:00.000123","1970-01-01 00:00:01.000001",null],"Asia/Shanghai":["1969-12-31 23:59:58.999000",' + '"1969-12-31 23:59:59.000000","1969-12-31 23:59:59.999000","1970-01-01 00:00:00.000000","1970-0' + '1-01 00:00:00.001000","1970-01-01 00:00:01.001000","2024-03-10 02:30:00.123000","2024-11-03 01' + ':30:00.123000","2024-03-10 07:30:00.123000","2024-11-03 06:30:00.123000","1969-12-31 23:59:59.' + '999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:01.000001",null],"America/New_York":["1' + '969-12-31 23:59:58.999000","1969-12-31 23:59:59.000000","1969-12-31 23:59:59.999000","1970-01-' + '01 00:00:00.000000","1970-01-01 00:00:00.001000","1970-01-01 00:00:01.001000","2024-03-10 02:3' + '0:00.123000","2024-11-03 01:30:00.123000","2024-03-10 07:30:00.123000","2024-11-03 06:30:00.12' + '3000","1969-12-31 23:59:59.999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:01.000001",n' + 'ull]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],' + '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' + '730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"na' + 'nos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMES' + 'TAMP(6)"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2' + '","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2' + '024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1969-12-31 2' + '","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2' + '024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],' + '"America/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0"' + ',"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","19' + '70-01-01 0","1970-01-01 0",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' + 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' + 'STAMP(6)"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' + '":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"mill' + 'is":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"m' + 'illis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"na' + 'nos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"' + 'nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"mill' + 'is":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos"' + ':0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"mill' + 'is":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos' + '":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' + 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' + 'STAMP(6)"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis"' + ':1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"milli' + 's":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"mil' + 'lis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},' + '{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos' + '":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nan' + 'os":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"n' + 'anos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":' + '-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{' + '"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1' + '730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},' + '{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' + 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' + 'STAMP(6)"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1' + '001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis"' + ':1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis"' + ':0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"mi' + 'llis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{' + '"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0}' + ',{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0}' + ',{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-1001,"n' + 'anos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1' + ',"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":17305974001' + '23,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":' + '-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' + 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' + 'STAMP(6)"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-100' + '0,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1' + '001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis"' + ':1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"mi' + 'llis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"Asia/Shanghai":[{"millis":-1001,"n' + 'anos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1' + ',"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":17305974001' + '23,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":' + '-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"America/New' + '_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis' + '":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos' + '":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":173061540' + '0123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos' + '":1000},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000' + '}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"n' + 'ame":"v","type":"TIMESTAMP(6)"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":' + '[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"na' + 'nos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"' + 'millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"n' + 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/' + 'Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-28800001,"' + 'nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-28798999,"n' + 'anos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis":17100' + '27000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":0},{"millis' + '":-28800000,"nanos":0},{"millis":-28799000,"nanos":0},null],"America/New_York":[{"millis":1799' + '8999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000' + ',"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"millis":171005580012' + '3,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nanos":0},{"millis":1' + '730633400123,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":' + '18001000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000' + '}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"n' + 'ame":"v","type":"TIMESTAMP(6)"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":' + '[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"na' + 'nos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"' + 'millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"n' + 'anos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000}' + ',null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis' + '":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis"' + ':-28798999,"nanos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"' + 'millis":1710027000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos' + '":999000},{"millis":-28800000,"nanos":123000},{"millis":-28799000,"nanos":1000},null],"America' + '/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"na' + 'nos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos"' + ':0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200' + '123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":17999999,"nanos":999000},{"millis"' + ':18000000,"nanos":123000},{"millis":18001000,"nanos":1000},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":' + '1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"' + '},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,17306154' + '00,-1,0,1,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1' + ',0,1,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0' + ',1,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows":' + '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' + '00123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":1}' + '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"},' + '"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia/Sh' + 'anghai":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"America/New_York":[-1,-1,-1,0,0,' + '0,19792,20030,19792,20030,-1,0,0,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos"' + ':1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)' + '"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27' + '000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,900' + '0123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,863' + '99999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"row' + 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' + '15400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos"' + ':1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)' + '"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27' + '000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,900' + '0123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,863' + '99999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows' + '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' + '5400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":' + '1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"' + '},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999000000","1969-12-31 23:59:59.000' + '000000","1969-12-31 23:59:59.999000000","1970-01-01 00:00:00.000000000","1970-01-01 00:00:00.0' + '01000000","1970-01-01 00:00:01.001000000","2024-03-10 02:30:00.123000000","2024-11-03 01:30:00' + '.123000000","2024-03-10 07:30:00.123000000","2024-11-03 06:30:00.123000000","1969-12-31 23:59:' + '59.999999999","1970-01-01 00:00:00.000123456","1970-01-01 00:00:01.000000001",null],"Asia/Shan' + 'ghai":["1969-12-31 23:59:58.999000000","1969-12-31 23:59:59.000000000","1969-12-31 23:59:59.99' + '9000000","1970-01-01 00:00:00.000000000","1970-01-01 00:00:00.001000000","1970-01-01 00:00:01.' + '001000000","2024-03-10 02:30:00.123000000","2024-11-03 01:30:00.123000000","2024-03-10 07:30:0' + '0.123000000","2024-11-03 06:30:00.123000000","1969-12-31 23:59:59.999999999","1970-01-01 00:00' + ':00.000123456","1970-01-01 00:00:01.000000001",null],"America/New_York":["1969-12-31 23:59:58.' + '999000000","1969-12-31 23:59:59.000000000","1969-12-31 23:59:59.999000000","1970-01-01 00:00:0' + '0.000000000","1970-01-01 00:00:00.001000000","1970-01-01 00:00:01.001000000","2024-03-10 02:30' + ':00.123000000","2024-11-03 01:30:00.123000000","2024-03-10 07:30:00.123000000","2024-11-03 06:' + '30:00.123000000","1969-12-31 23:59:59.999999999","1970-01-01 00:00:00.000123456","1970-01-01 0' + '0:00:01.000000001",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],' + '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' + '730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"na' + 'nos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAM' + 'P(9)"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2","' + '1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024' + '-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1969-12-31 2","' + '1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024' + '-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Am' + 'erica/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1' + '970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-' + '01-01 0","1970-01-01 0",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' + 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' + 'MP(9)"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"' + 'nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1' + '000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis"' + ':1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' + 'is":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0},{' + '"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos' + '":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nan' + 'os":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"' + 'nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis"' + ':-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0}' + ',{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis"' + ':1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' + 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' + 'MP(9)"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"' + 'nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":10' + '00,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":' + '1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"millis' + '":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},{"m' + 'illis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0' + '},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos"' + ':0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nano' + 's":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-11' + '00,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"mi' + 'llis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730' + '597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"m' + 'illis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' + 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' + 'MP(9)"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"' + 'nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001' + ',"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":17' + '10055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,' + '"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"milli' + 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' + 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' + 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"' + 'millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-1001,"nano' + 's":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"n' + 'anos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,' + '"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,' + '"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' + ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' + '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' + 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' + 'MP(9)"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"' + 'nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001' + ',"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":17' + '10055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"milli' + 's":0,"nanos":123000},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":' + '0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nano' + 's":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"na' + 'nos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"na' + 'nos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null],"America/New_York":[{' + '"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nano' + 's":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mi' + 'llis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nan' + 'os":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null' + ']}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(9)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456' + '}],[{"millis":1000,"nanos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name' + '":"v","type":"TIMESTAMP(9)"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"' + 'millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos' + '":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mil' + 'lis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nano' + 's":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Sha' + 'nghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-28800001,"nan' + 'os":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-28798999,"nano' + 's":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis":17100270' + '00123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-' + '28800000,"nanos":0},{"millis":-28799000,"nanos":0},null],"America/New_York":[{"millis":1799899' + '9,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"n' + 'anos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"millis":1710055800123,"' + 'nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nanos":0},{"millis":1730' + '633400123,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":180' + '01000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(9)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' + '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456' + '}],[{"millis":1000,"nanos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name' + '":"v","type":"TIMESTAMP(9)"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"' + 'millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos' + '":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mil' + 'lis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nano' + 's":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null]' + ',"Asia/Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-288' + '00001,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-2879' + '8999,"nanos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis' + '":1710027000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":9990' + '00},{"millis":-28800000,"nanos":123000},{"millis":-28799000,"nanos":0},null],"America/New_York' + '":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{' + '"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"mil' + 'lis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nano' + 's":0},{"millis":1730633400123,"nanos":0},{"millis":17999999,"nanos":999000},{"millis":18000000' + ',"nanos":123000},{"millis":18001000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> BIGINT","fields":[{"name":"v","type":"' + 'TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' + '3],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808' + '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WI' + 'TH LOCAL TIME ZONE"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,' + '1710055800,1730615400,-53757322505225,53757322505224,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,171' + '0037800,1730597400,1710055800,1730615400,-53757322505225,53757322505224,null],"America/New_Yor' + 'k":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-53757322505225,53757322505224,' + 'null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> DATE","fields":[{"name":"v","type":"TI' + 'MESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123]' + ',[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],' + '[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WITH' + ' LOCAL TIME ZONE"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-6' + '22191233,622191233,null],"Asia/Shanghai":[0,0,0,0,0,0,19792,20030,19792,20030,-622191233,62219' + '1234,null],"America/New_York":[-1,-1,-1,-1,-1,-1,19791,20029,19792,20030,-622191233,622191233,' + 'null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIME(0)","fields":[{"name":"v","type":' + '"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' + '23],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-922337203685477580' + '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) W' + 'ITH LOCAL TIME ZONE"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001' + ',9000123,5400123,27000123,23400123,25975807,60424192,null],"Asia/Shanghai":[28798999,28799000,' + '28799999,28800000,28800001,28801001,37800123,34200123,55800123,52200123,54775807,3167192,null]' + ',"America/New_York":[68398999,68399000,68399999,68400000,68400001,68401001,77400123,77400123,1' + '2600123,5400123,11575807,42662192,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIME(3)","fields":[{"name":"v","type":' + '"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' + '23],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-922337203685477580' + '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) W' + 'ITH LOCAL TIME ZONE"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001' + ',9000123,5400123,27000123,23400123,25975807,60424192,null],"Asia/Shanghai":[28798999,28799000,' + '28799999,28800000,28800001,28801001,37800123,34200123,55800123,52200123,54775807,3167192,null]' + ',"America/New_York":[68398999,68399000,68399999,68400000,68400001,68401001,77400123,77400123,1' + '2600123,5400123,11575807,42662192,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"' + 'TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' + '3],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808' + '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WI' + 'TH LOCAL TIME ZONE"},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999","1969-12-31' + ' 23:59:59.000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.000","1970-01-01 00:00:00.001","' + '1970-01-01 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 01:30:00.123","2024-03-10 07:30' + ':00.123","2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5471-09-26 16:47:04.192",null],"' + 'Asia/Shanghai":["1970-01-01 07:59:58.999","1970-01-01 07:59:59.000","1970-01-01 07:59:59.999",' + '"1970-01-01 08:00:00.000","1970-01-01 08:00:00.001","1970-01-01 08:00:01.001","2024-03-10 10:3' + '0:00.123","2024-11-03 09:30:00.123","2024-03-10 15:30:00.123","2024-11-03 14:30:00.123","5471-' + '09-27 00:47:04.191","5471-09-27 00:52:47.192",null],"America/New_York":["1969-12-31 18:59:58.9' + '99","1969-12-31 18:59:59.000","1969-12-31 18:59:59.999","1969-12-31 19:00:00.000","1969-12-31 ' + '19:00:00.001","1969-12-31 19:00:01.001","2024-03-09 21:30:00.123","2024-11-02 21:30:00.123","2' + '024-03-10 03:30:00.123","2024-11-03 01:30:00.123","/+-.-04-06 03:12:55.807","/+-.-04-06 02:16:' + '53.808",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> VARCHAR(12)","fields":[{"name":"v","ty' + 'pe":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037' + '800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-92233720368547' + '75808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' + '3) WITH LOCAL TIME ZONE"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 ' + '2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","' + '2024-03-10 0","2024-11-03 0","/+-.-04-06 0","5471-09-26 1",null],"Asia/Shanghai":["1970-01-01 ' + '0","1970-01-01 0","1970-01-01 0","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 1","' + '2024-11-03 0","2024-03-10 1","2024-11-03 1","5471-09-27 0","5471-09-27 0",null],"America/New_Y' + 'ork":["1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1' + '","2024-03-09 2","2024-11-02 2","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","/+-.-04-06 0",nu' + 'll]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(0)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' + '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"na' + 'nos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"' + 'nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":9223' + '372036854775000,"nanos":0},{"millis":9223372036854775616,"nanos":0},null],"Asia/Shanghai":[{"m' + 'illis":28798000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799000,"nanos":0},{"milli' + 's":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},{"millis":1' + '710066600000,"nanos":0},{"millis":1730626200000,"nanos":0},{"millis":1710084600000,"nanos":0},' + '{"millis":1730644200000,"nanos":0},{"millis":-9223372036825976000,"nanos":0},{"millis":-922337' + '2036825633000,"nanos":0},null],"America/New_York":[{"millis":-18002000,"nanos":0},{"millis":-1' + '8001000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-18' + '000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1710019800000,"nanos":0},{"millis":' + '1730583000000,"nanos":0},{"millis":1710041400000,"nanos":0},{"millis":1730597400000,"nanos":0}' + ',{"millis":9223372036840375000,"nanos":0},{"millis":9223372036837013000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(1)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' + '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nan' + 'os":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"n' + 'anos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":92233' + '72036854775800,"nanos":0},{"millis":9223372036854775716,"nanos":0},null],"Asia/Shanghai":[{"mi' + 'llis":28798900,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799900,"nanos":0},{"millis' + '":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},{"millis":17' + '10066600100,"nanos":0},{"millis":1730626200100,"nanos":0},{"millis":1710084600100,"nanos":0},{' + '"millis":1730644200100,"nanos":0},{"millis":-9223372036825975900,"nanos":0},{"millis":-9223372' + '036825632900,"nanos":0},null],"America/New_York":[{"millis":-18001100,"nanos":0},{"millis":-18' + '001000,"nanos":0},{"millis":-18000100,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-180' + '00000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1710019800100,"nanos":0},{"millis":1' + '730583000100,"nanos":0},{"millis":1710041400100,"nanos":0},{"millis":1730597400100,"nanos":0},' + '{"millis":9223372036840375800,"nanos":0},{"millis":9223372036837013800,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(3)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' + '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos' + '":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nan' + 'os":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372' + '036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null],"Asia/Shanghai":[{"mil' + 'lis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799999,"nanos":0},{"millis"' + ':28800000,"nanos":0},{"millis":28800001,"nanos":0},{"millis":28801001,"nanos":0},{"millis":171' + '0066600123,"nanos":0},{"millis":1730626200123,"nanos":0},{"millis":1710084600123,"nanos":0},{"' + 'millis":1730644200123,"nanos":0},{"millis":-9223372036825975809,"nanos":0},{"millis":-92233720' + '36825632808,"nanos":0},null],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-180' + '01000,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-1799' + '9999,"nanos":0},{"millis":-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":17' + '30583000123,"nanos":0},{"millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{' + '"millis":9223372036840375807,"nanos":0},{"millis":9223372036837013808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(6)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' + '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' + '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0' + '},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos' + '":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nan' + 'os":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372' + '036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null],"Asia/Shanghai":[{"mil' + 'lis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799999,"nanos":0},{"millis"' + ':28800000,"nanos":0},{"millis":28800001,"nanos":0},{"millis":28801001,"nanos":0},{"millis":171' + '0066600123,"nanos":0},{"millis":1730626200123,"nanos":0},{"millis":1710084600123,"nanos":0},{"' + 'millis":1730644200123,"nanos":0},{"millis":-9223372036825975809,"nanos":0},{"millis":-92233720' + '36825632808,"nanos":0},null],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-180' + '01000,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-1799' + '9999,"nanos":0},{"millis":-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":17' + '30583000123,"nanos":0},{"millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{' + '"millis":9223372036840375807,"nanos":0},{"millis":9223372036837013808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fi' + 'elds":[{"name":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' + '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[922337203685477' + '5807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' + '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"e' + 'xpected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0}' + ',{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17100378001' + '23,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":' + '1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720368547758' + '08,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"m' + 'illis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{' + '"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"' + 'nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis' + '":-9223372036854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"milli' + 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' + 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' + 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775' + '807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fi' + 'elds":[{"name":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' + '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[922337203685477' + '5807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' + '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"e' + 'xpected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0}' + ',{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17100378001' + '23,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":' + '1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720368547758' + '08,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"m' + 'illis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{' + '"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"' + 'nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis' + '":-9223372036854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"milli' + 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' + 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' + 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775' + '807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> BIGINT","fields":[{"name":"v","type":"' + 'TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' + '3],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0' + ',"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"BIGINT"},"expected' + '":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null],"Asia/Shangh' + 'ai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null],"America/New_York' + '":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> DATE","fields":[{"name":"v","type":"TI' + 'MESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123]' + ',[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"' + 'nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{' + '"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"DATE"},"expected":{"' + 'UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia/Shanghai":[0,0,0,0,0,0,19792,2' + '0030,19792,20030,0,0,0,null],"America/New_York":[-1,-1,-1,-1,-1,-1,19791,20029,19792,20030,-1,' + '-1,-1,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIME(0)","fields":[{"name":"v","type":' + '"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' + '23],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":' + '0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef' + '":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIME(0)"},"expect' + 'ed":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1' + '000,null],"Asia/Shanghai":[28798999,28799000,28799999,28800000,28800001,28801001,37800123,3420' + '0123,55800123,52200123,28799999,28800000,28801000,null],"America/New_York":[68398999,68399000,' + '68399999,68400000,68400001,68401001,77400123,77400123,12600123,5400123,68399999,68400000,68401' + '000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIME(3)","fields":[{"name":"v","type":' + '"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' + '23],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":' + '0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef' + '":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIME(3)"},"expect' + 'ed":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1' + '000,null],"Asia/Shanghai":[28798999,28799000,28799999,28800000,28800001,28801001,37800123,3420' + '0123,55800123,52200123,28799999,28800000,28801000,null],"America/New_York":[68398999,68399000,' + '68399999,68400000,68400001,68401001,77400123,77400123,12600123,5400123,68399999,68400000,68401' + '000,null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"' + 'TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' + '3],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0' + ',"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef"' + ':{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"STRING"},"expected' + '":{"UTC":["1969-12-31 23:59:58.999000","1969-12-31 23:59:59.000000","1969-12-31 23:59:59.99900' + '0","1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1970-01-01 00:00:01.001000","202' + '4-03-10 02:30:00.123000","2024-11-03 01:30:00.123000","2024-03-10 07:30:00.123000","2024-11-03' + ' 06:30:00.123000","1969-12-31 23:59:59.999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:' + '01.000001",null],"Asia/Shanghai":["1970-01-01 07:59:58.999000","1970-01-01 07:59:59.000000","1' + '970-01-01 07:59:59.999000","1970-01-01 08:00:00.000000","1970-01-01 08:00:00.001000","1970-01-' + '01 08:00:01.001000","2024-03-10 10:30:00.123000","2024-11-03 09:30:00.123000","2024-03-10 15:3' + '0:00.123000","2024-11-03 14:30:00.123000","1970-01-01 07:59:59.999999","1970-01-01 08:00:00.00' + '0123","1970-01-01 08:00:01.000001",null],"America/New_York":["1969-12-31 18:59:58.999000","196' + '9-12-31 18:59:59.000000","1969-12-31 18:59:59.999000","1969-12-31 19:00:00.000000","1969-12-31' + ' 19:00:00.001000","1969-12-31 19:00:01.001000","2024-03-09 21:30:00.123000","2024-11-02 21:30:' + '00.123000","2024-03-10 03:30:00.123000","2024-11-03 01:30:00.123000","1969-12-31 18:59:59.9999' + '99","1969-12-31 19:00:00.000123","1969-12-31 19:00:01.000001",null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> VARCHAR(12)","fields":[{"name":"v","ty' + 'pe":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037' + '800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mill' + 'is":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"VARCHAR(12)"}' + ',"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0"' + ',"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","19' + '70-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1970-01-01 0","1970-01-01 0","1970-01-01 0"' + ',"1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 1","2024-11-03 0","2024-03-10 1","20' + '24-11-03 1","1970-01-01 0","1970-01-01 0","1970-01-01 0",null],"America/New_York":["1969-12-31' + ' 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","2024-03-09 2",' + '"2024-11-02 2","2024-03-10 0","2024-11-03 0","1969-12-31 1","1969-12-31 1","1969-12-31 1",null' + ']}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(0)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' + 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(0)' + '"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"n' + 'anos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":171' + '0037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"' + 'millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1' + '000,"nanos":0},null],"Asia/Shanghai":[{"millis":28798000,"nanos":0},{"millis":28799000,"nanos"' + ':0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800000,"nanos":0},' + '{"millis":28801000,"nanos":0},{"millis":1710066600000,"nanos":0},{"millis":1730626200000,"nano' + 's":0},{"millis":1710084600000,"nanos":0},{"millis":1730644200000,"nanos":0},{"millis":28799000' + ',"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_Yor' + 'k":[{"millis":-18002000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18001000,"nanos":' + '0},{"millis":-18000000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0' + '},{"millis":1710019800000,"nanos":0},{"millis":1730583000000,"nanos":0},{"millis":171004140000' + '0,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-1800' + '0000,"nanos":0},{"millis":-17999000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(1)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' + 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(1)' + '"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"na' + 'nos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710' + '037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"m' + 'illis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":100' + '0,"nanos":0},null],"Asia/Shanghai":[{"millis":28798900,"nanos":0},{"millis":28799000,"nanos":0' + '},{"millis":28799900,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"' + 'millis":28801000,"nanos":0},{"millis":1710066600100,"nanos":0},{"millis":1730626200100,"nanos"' + ':0},{"millis":1710084600100,"nanos":0},{"millis":1730644200100,"nanos":0},{"millis":28799900,"' + 'nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_York"' + ':[{"millis":-18001100,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000100,"nanos":0}' + ',{"millis":-18000000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},' + '{"millis":1710019800100,"nanos":0},{"millis":1730583000100,"nanos":0},{"millis":1710041400100,' + '"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":-18000100,"nanos":0},{"millis":-180000' + '00,"nanos":0},{"millis":-17999000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(3)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' + 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3)' + '"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nano' + 's":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003' + '7800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"mil' + 'lis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"n' + 'anos":0},null],"Asia/Shanghai":[{"millis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"' + 'millis":28799999,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800001,"nanos":0},{"mill' + 'is":28801001,"nanos":0},{"millis":1710066600123,"nanos":0},{"millis":1730626200123,"nanos":0},' + '{"millis":1710084600123,"nanos":0},{"millis":1730644200123,"nanos":0},{"millis":28799999,"nano' + 's":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_York":[{"' + 'millis":-18001001,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000001,"nanos":0},{"m' + 'illis":-18000000,"nanos":0},{"millis":-17999999,"nanos":0},{"millis":-17998999,"nanos":0},{"mi' + 'llis":1710019800123,"nanos":0},{"millis":1730583000123,"nanos":0},{"millis":1710041400123,"nan' + 'os":0},{"millis":1730597400123,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"' + 'nanos":0},{"millis":-17999000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(6)","fields":[{"name":"v","t' + 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' + '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' + 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' + 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6)' + '"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nano' + 's":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003' + '7800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"mil' + 'lis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"milli' + 's":1000,"nanos":1000},null],"Asia/Shanghai":[{"millis":28798999,"nanos":0},{"millis":28799000,' + '"nanos":0},{"millis":28799999,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800001,"nan' + 'os":0},{"millis":28801001,"nanos":0},{"millis":1710066600123,"nanos":0},{"millis":173062620012' + '3,"nanos":0},{"millis":1710084600123,"nanos":0},{"millis":1730644200123,"nanos":0},{"millis":2' + '8799999,"nanos":999000},{"millis":28800000,"nanos":123000},{"millis":28801000,"nanos":1000},nu' + 'll],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-18001000,"nanos":0},{"millis' + '":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999999,"nanos":0},{"millis"' + ':-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":1730583000123,"nanos":0},{"' + 'millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":-18000001,"nanos' + '":999000},{"millis":-18000000,"nanos":123000},{"millis":-17999000,"nanos":1000},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fi' + 'elds":[{"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' + '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"n' + 'anos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform' + '":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}' + ',"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"m' + 'illis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},' + '{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0' + '},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0' + '},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nan' + 'os":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"' + 'nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123' + ',"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1' + ',"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"milli' + 's":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},' + '{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":' + '1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0}' + ',{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fi' + 'elds":[{"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' + '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"n' + 'anos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform' + '":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}' + ',"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"m' + 'illis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},' + '{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0' + '},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":9' + '99000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"Asia/Shanghai":[{"milli' + 's":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},' + '{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":' + '1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0}' + ',{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"' + 'America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":' + '0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003780' + '0123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis' + '":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":' + '1000,"nanos":1000},null]}}' + ), + json.loads( + '{"name":"rebound INT -> STRING","fields":[{"name":"v","type":"INT"}],"rows":[[0],[1],[-1],[nul' + 'l]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type":"STRING' + '"},"expected":{"UTC":["1970-01-01","1970-01-02","1969-12-31",null],"Asia/Shanghai":["1970-01-0' + '1","1970-01-02","1969-12-31",null],"America/New_York":["1970-01-01","1970-01-02","1969-12-31",' + 'null]}}' + ), + json.loads( + '{"name":"rebound DATE -> STRING","fields":[{"name":"v","type":"DATE"}],"rows":[[0],[1],[-1],[n' + 'ull]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME(3)"},"type":"S' + 'TRING"},"expected":{"UTC":["00:00:00.0","00:00:00.001","23:59:59.999",null],"Asia/Shanghai":["' + '00:00:00.0","00:00:00.001","23:59:59.999",null],"America/New_York":["00:00:00.0","00:00:00.001' + '","23:59:59.999",null]}}' + ), + json.loads( + '{"name":"rebound TIME(3) -> STRING","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[1],[' + '-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type"' + ':"STRING"},"expected":{"UTC":["1970-01-01","1970-01-02","1969-12-31",null],"Asia/Shanghai":["1' + '970-01-01","1970-01-02","1969-12-31",null],"America/New_York":["1970-01-01","1970-01-02","1969' + '-12-31",null]}}' + ), + json.loads( + '{"name":"rebound DATE -> TIMESTAMP(3)","fields":[{"name":"v","type":"DATE"}],"rows":[[0],[1],[' + '-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' + 'e":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"milli' + 's":-1000,"nanos":0},null],"Asia/Shanghai":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"' + 'millis":-1000,"nanos":0},null],"America/New_York":[{"millis":0,"nanos":0},{"millis":1000,"nano' + 's":0},{"millis":-1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"rebound INT -> TIMESTAMP(3)","fields":[{"name":"v","type":"INT"}],"rows":[[0],[1],[-1' + '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type"' + ':"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis"' + ':-1000,"nanos":0},null],"Asia/Shanghai":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"mi' + 'llis":-1000,"nanos":0},null],"America/New_York":[{"millis":0,"nanos":0},{"millis":1000,"nanos"' + ':0},{"millis":-1000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"rebound TIMESTAMP(3) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"TI' + 'MESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[0],[1],[-1],[null]],"transform":{"name":"CAST","fi' + 'eldRef":{"index":99,"name":"v","type":"TIMESTAMP(6)"},"type":"STRING"},"expected":{"UTC":["197' + '0-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969-12-31 23:59:59.999000",null],"Asia' + '/Shanghai":["1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969-12-31 23:59:59.999' + '000",null],"America/New_York":["1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969' + '-12-31 23:59:59.999000",null]}}' + ), + json.loads( + '{"name":"rebound TIMESTAMP(6) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows":' + '[[0],[1],[-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIM' + 'ESTAMP(3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01 00:00:00.000","1970-01-01 00:00:00' + '.001","1969-12-31 23:59:59.999",null],"Asia/Shanghai":["1970-01-01 00:00:00.000","1970-01-01 0' + '0:00:00.001","1969-12-31 23:59:59.999",null],"America/New_York":["1970-01-01 00:00:00.000","19' + '70-01-01 00:00:00.001","1969-12-31 23:59:59.999",null]}}' + ), + json.loads( + '{"name":"rebound STRING -> VARCHAR(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["abcde' + 'f"],["\\u00e9\\u732b"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","typ' + 'e":"BINARY(8)"},"type":"VARCHAR(3)"},"expected":{"UTC":[{"error":"ClassCastException"},{"error' + '":"ClassCastException"},null],"Asia/Shanghai":[{"error":"ClassCastException"},{"error":"ClassC' + 'astException"},null],"America/New_York":[{"error":"ClassCastException"},{"error":"ClassCastExc' + 'eption"},null]}}' + ), + json.loads( + '{"name":"rebound BINARY(8) -> VARCHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[[' + '[97,98,99,100,101,102]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","' + 'type":"STRING"},"type":"VARCHAR(3)"},"expected":{"UTC":[{"error":"ClassCastException"},null],"' + 'Asia/Shanghai":[{"error":"ClassCastException"},null],"America/New_York":[{"error":"ClassCastEx' + 'ception"},null]}}' + ), + json.loads( + '{"name":"grammar STRING -> DATE","fields":[{"name":"v","type":"STRING"}],"rows":[["1970-011-02' + '2"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01-02 0303' + ':0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"],["1970' + '-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03:04:05T0' + '6:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.124"],["' + '1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24:00:00.0' + '01"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01"],["000' + '1-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["+1"],["-' + '1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":{"index"' + ':99,"name":"v","type":"STRING"},"type":"DATE"},"expected":{"UTC":[325,{"error":"DateTimeExcept' + 'ion"},355,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeExcept' + 'ion"},1,1,1,1,{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1,1,1,{"error":"' + 'DateTimeException"},1,1,1,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error"' + ':"DateTimeException"},-719528,-719162,{"error":"DateTimeException"},{"error":"DateTimeExceptio' + 'n"},{"error":"DateTimeException"},1,{"error":"DateTimeException"},-1,{"error":"DateTimeExcepti' + 'on"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null],"Asia/Shanghai"' + ':[325,{"error":"DateTimeException"},355,{"error":"DateTimeException"},{"error":"DateTimeExcept' + 'ion"},{"error":"DateTimeException"},1,1,1,1,{"error":"DateTimeException"},{"error":"DateTimeEx' + 'ception"},1,1,1,1,1,{"error":"DateTimeException"},1,1,1,{"error":"DateTimeException"},{"error"' + ':"DateTimeException"},{"error":"DateTimeException"},-719528,-719162,{"error":"DateTimeExceptio' + 'n"},{"error":"DateTimeException"},{"error":"DateTimeException"},1,{"error":"DateTimeException"' + '},-1,{"error":"DateTimeException"},{"error":"NumberFormatException"},{"error":"NumberFormatExc' + 'eption"},null],"America/New_York":[325,{"error":"DateTimeException"},355,{"error":"DateTimeExc' + 'eption"},{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1,1,{"error":"DateTim' + 'eException"},{"error":"DateTimeException"},1,1,1,1,1,{"error":"DateTimeException"},1,1,1,{"err' + 'or":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeException"},-719528,-' + '719162,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeException' + '"},1,{"error":"DateTimeException"},-1,{"error":"DateTimeException"},{"error":"NumberFormatExce' + 'ption"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"grammar STRING -> TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["197' + '0-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01' + '-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"' + '],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03' + ':04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.' + '124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24' + ':00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01' + '"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["' + '+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":' + '{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":86' + '400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0' + ',"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nano' + 's":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParse' + 'Exception"},{"millis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":9744500' + '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTi' + 'meParseException"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172' + '800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mill' + 'is":983318400000,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException' + '"},{"error":"DateTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeP' + 'arseException"},{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"mill' + 'is":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"error":"D' + 'ateTimeParseException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},nu' + 'll],"Asia/Shanghai":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"Dat' + 'eTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"n' + 'anos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseEx' + 'ception"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"DateTimeP' + 'arseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":974' + '45123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"millis":1' + '72800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"},{"error"' + ':"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"nanos":0}' + ',{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621355968000' + '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0},{"error"' + ':"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"' + 'millis":-1,"nanos":0},{"error":"DateTimeParseException"},{"error":"NumberFormatException"},{"e' + 'rror":"NumberFormatException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"milli' + 's":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"Dat' + 'eTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,' + '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":974' + '40000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"Da' + 'teTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"mill' + 'is":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error' + '":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":' + '0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimePars' + 'eException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis"' + ':253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{' + '"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"error":"DateTimeParseException"},{' + '"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"grammar STRING -> TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["197' + '0-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01' + '-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"' + '],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03' + ':04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.' + '124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24' + ':00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01' + '"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["' + '+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":' + '{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":86' + '400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0' + ',"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nano' + 's":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParse' + 'Exception"},{"millis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":9744500' + '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTi' + 'meParseException"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172' + '800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mill' + 'is":983318400000,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException' + '"},{"error":"DateTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeP' + 'arseException"},{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"mill' + 'is":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":999000},{"erro' + 'r":"DateTimeParseException"},{"error":"NumberFormatException"},{"error":"NumberFormatException' + '"},null],"Asia/Shanghai":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"error"' + ':"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"millis"' + ':0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimePa' + 'rseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis' + '":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"mill' + 'is":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"},{"e' + 'rror":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"nano' + 's":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-6213559' + '6800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException' + '"},{"millis":-1,"nanos":999000},{"error":"DateTimeParseException"},{"error":"NumberFormatExcep' + 'tion"},{"error":"NumberFormatException"},null],"America/New_York":[{"millis":86400000,"nanos":' + '0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"e' + 'rror":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis"' + ':97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"m' + 'illis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"' + 'error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTimeParseExceptio' + 'n"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":' + '0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":98331840000' + '0,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Da' + 'teTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeParseException"}' + ',{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"n' + 'anos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":999000},{"error":"DateTimePar' + 'seException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' + ), + json.loads( + '{"name":"grammar STRING -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"ST' + 'RING"}],"rows":[["1970-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],[' + '"1970-01-"],["1970-01-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"' + '],["1970-01-02 03:04"],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04' + ':05"],["1970-01-02 03:04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 0' + '3:04:05.123T03:04:05.124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.' + '000"],["1970-01-02 24:00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001' + '-04-32"],["0000-01-01"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970' + '-01-02 03:04:05."],["+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"nam' + 'e":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3) WITH LOCAL T' + 'IME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"er' + 'ror":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"mil' + 'lis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTi' + 'meParseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"' + 'DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"mi' + 'llis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"' + 'millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"}' + ',{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"' + 'nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621' + '35596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0}' + ',{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseExcep' + 'tion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTim' + 'eParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000' + ',"nanos":0},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-288000' + '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":-28800000,"nanos":0},{"millis":6864' + '5000,"nanos":0},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Dat' + 'eTimeParseException"},{"millis":68640000,"nanos":0},{"error":"DateTimeParseException"},{"milli' + 's":68645000,"nanos":0},{"error":"DateTimeParseException"},{"millis":68645123,"nanos":0},{"erro' + 'r":"DateTimeParseException"},{"millis":144000000,"nanos":0},{"millis":144000000,"nanos":0},{"m' + 'illis":144000000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseExceptio' + 'n"},{"millis":983289600000,"nanos":0},{"millis":988560000000,"nanos":0},{"error":"DateTimePars' + 'eException"},{"error":"DateTimeParseException"},{"millis":-62135625943000,"nanos":0},{"error":' + '"DateTimeParseException"},{"millis":253402272000000,"nanos":0},{"error":"DateTimeParseExceptio' + 'n"},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' + 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' + 'TimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":104400' + '000,"nanos":0},{"error":"DateTimeParseException"},{"millis":18000000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":18000000,"nanos":0},{"millis":115445000,"nanos":0},{"millis":11' + '5445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mil' + 'lis":115440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,"nanos":0},{"' + 'error":"DateTimeParseException"},{"millis":115445123,"nanos":0},{"error":"DateTimeParseExcepti' + 'on"},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos"' + ':0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":9833364000' + '00,"nanos":0},{"millis":988603200000,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' + 'ateTimeParseException"},{"millis":-62135579038000,"nanos":0},{"error":"DateTimeParseException"' + '},{"millis":253402318800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,' + '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Dat' + 'eTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nu' + 'll]}}' + ), + json.loads( + '{"name":"grammar STRING -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"ST' + 'RING"}],"rows":[["1970-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],[' + '"1970-01-"],["1970-01-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"' + '],["1970-01-02 03:04"],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04' + ':05"],["1970-01-02 03:04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 0' + '3:04:05.123T03:04:05.124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.' + '000"],["1970-01-02 24:00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001' + '-04-32"],["0000-01-01"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970' + '-01-02 03:04:05."],["+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"nam' + 'e":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6) WITH LOCAL T' + 'IME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"er' + 'ror":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"mil' + 'lis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTi' + 'meParseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"' + 'DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"mi' + 'llis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"' + 'millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"}' + ',{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"' + 'nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621' + '35596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0}' + ',{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseExcep' + 'tion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTim' + 'eParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000' + ',"nanos":0},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-288000' + '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":-28800000,"nanos":0},{"millis":6864' + '5000,"nanos":0},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Dat' + 'eTimeParseException"},{"millis":68640000,"nanos":0},{"error":"DateTimeParseException"},{"milli' + 's":68645000,"nanos":0},{"error":"DateTimeParseException"},{"millis":68645123,"nanos":0},{"erro' + 'r":"DateTimeParseException"},{"millis":144000000,"nanos":0},{"millis":144000000,"nanos":0},{"m' + 'illis":144000000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseExceptio' + 'n"},{"millis":983289600000,"nanos":0},{"millis":988560000000,"nanos":0},{"error":"DateTimePars' + 'eException"},{"error":"DateTimeParseException"},{"millis":-62135625943000,"nanos":0},{"error":' + '"DateTimeParseException"},{"millis":253402272000000,"nanos":0},{"error":"DateTimeParseExceptio' + 'n"},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' + 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' + 'TimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":104400' + '000,"nanos":0},{"error":"DateTimeParseException"},{"millis":18000000,"nanos":0},{"error":"Date' + 'TimeParseException"},{"millis":18000000,"nanos":0},{"millis":115445000,"nanos":0},{"millis":11' + '5445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mil' + 'lis":115440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,"nanos":0},{"' + 'error":"DateTimeParseException"},{"millis":115445123,"nanos":0},{"error":"DateTimeParseExcepti' + 'on"},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos"' + ':0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":9833364000' + '00,"nanos":0},{"millis":988603200000,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' + 'ateTimeParseException"},{"millis":-62135579038000,"nanos":0},{"error":"DateTimeParseException"' + '},{"millis":253402318800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,' + '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Dat' + 'eTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nu' + 'll]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"ro' + 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' + '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":25' + '3402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337203685477580' + '7,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"type' + '":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:' + '01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00' + ':00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:00","1' + '970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59",' + '"2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.80' + '7"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","19' + '69-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-' + '0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"' + 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' + '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' + '253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854775' + '807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"ty' + 'pe":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' + '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T0' + '0:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00 "' + ',"1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","' + '2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"A' + 'merica/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-1' + '2-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01' + '-01T00:00 ","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854' + '775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' + '"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01' + 'T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T0' + '0:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1970-01' + '-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T' + '22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New_York"' + ':["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969' + '-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-' + '06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],' + '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' + 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' + ':253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337203685477' + '5807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBLE"}' + ',"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' + '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01' + '-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:' + '00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:5' + '9:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12' + ':55.807"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:0' + '1","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:' + '00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854' + '775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBLE' + '"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-0' + '1-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-0' + '1-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:0' + '0 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:' + '59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:1' + '2"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","' + '1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0' + '001-01-01T00:00 ","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3' + ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' + 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' + 'llis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036' + '854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' + 'BLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970' + '-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-0' + '1-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1' + '970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-' + '11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New' + '_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59."' + ',"1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-17015' + '32-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' + '(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' + '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' + 'millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":92233720' + '36854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"D' + 'ECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001' + '","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.1' + '23","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["' + '1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1' + '969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-17015' + '32-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970' + '-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+1' + '0000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' + 'MP(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' + ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' + '{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337' + '2036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":' + '"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:0' + '0:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:' + '20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1' + '970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","196' + '9-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701' + '532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' + '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-0' + '1T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' + 'STAMP(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' + '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' + '],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922' + '3372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' + 'e":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00' + ':00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:' + '20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-0' + '1-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23' + ':59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"' + '],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12' + '-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T' + '00:00","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"ro' + 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' + '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":0,' + '"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"t' + 'ype":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' + '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' + '0:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' + '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' + '0:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' + '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-0' + '1T00:00:00.000123"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"' + 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' + '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' + '0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' + '"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' + '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T' + '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' + '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1' + '969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT' + '"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' + '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T' + '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","' + '1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."],"Am' + 'erica/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T2' + '3:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],' + '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' + 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' + ':0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBL' + 'E"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' + '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' + '1-01T00:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' + '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' + '1-01T00:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' + '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' + '0-01-01T00:00:00.000123"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' + 'BLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","197' + '0-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-' + '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' + '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:' + '00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' + '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6' + ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' + 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' + 'llis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"' + 'DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1' + '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-' + '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' + ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-1' + '2-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' + '(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' + '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' + 'millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type"' + ':"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.' + '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' + '0.123","1970-01-01T00:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.' + '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' + '0.123","1970-01-01T00:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:' + '00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:1' + '3:20.123","1970-01-01T00:00:00.000123"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' + 'MP(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' + ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' + '{"millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' + 'e":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T0' + '0:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:' + '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00."' + ',"1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","' + '1970-01-01T00:00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970' + '-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-0' + '1-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' + 'STAMP(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' + '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' + '],[{"millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","' + 'type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01' + 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' + '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","19' + '70-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-0' + '1-01T00:00:00."],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:' + '00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:0' + '0."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"ro' + 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' + '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":0,' + '"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"t' + 'ype":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' + '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' + '0:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' + '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-0' + '1T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' + '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' + '0-01-01T00:00:00.000123456"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"' + 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' + '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' + '0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' + '"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' + '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T' + '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' + '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1' + '969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT' + '"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' + '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T' + '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","' + '1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."],"Am' + 'erica/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T2' + '3:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],' + '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' + 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' + ':0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBL' + 'E"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' + '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' + '1-01T00:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' + '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' + '0-01-01T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001",' + '"1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123' + '","1970-01-01T00:00:00.000123456"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}' + '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' + 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' + 's":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' + 'BLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","197' + '0-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-' + '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' + '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:' + '00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' + '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9' + ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' + 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' + 'llis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"' + 'DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1' + '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-' + '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' + ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00.' + '"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-1' + '2-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' + '(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' + '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' + 'millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type"' + ':"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.' + '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' + '0.123","1970-01-01T00:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:' + '00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:1' + '3:20.123","1970-01-01T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T' + '00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-1' + '4T22:13:20.123","1970-01-01T00:00:00.000123456"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' + 'MP(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' + ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' + '{"millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' + 'e":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T0' + '0:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:' + '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00."' + ',"1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","' + '1970-01-01T00:00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970' + '-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-0' + '1-01T00:00:00."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' + 'STAMP(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' + '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' + '],[{"millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","' + 'type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01' + 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' + '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","19' + '70-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-0' + '1-01T00:00:00."],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:' + '00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:0' + '0."]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> STRING","fields":[{"name":"v","type"' + ':"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0' + '}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"milli' + 's":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000' + ',"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef"' + ':{"index":0,"name":"v","type":"INT"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1' + '970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59",' + '"2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.80' + '7"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-' + '12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-000' + '1-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","1970-01-' + '01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-1' + '1-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> CHAR(20)","fields":[{"name":"v","typ' + 'e":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos"' + ':0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"mil' + 'lis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552000' + '00,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRe' + 'f":{"index":0,"name":"v","type":"INT"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00' + ' ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:5' + '9 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12' + '"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969' + '-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-' + '01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970-01-01' + 'T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T2' + '2:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> VARCHAR(20)","fields":[{"name":"v","' + 'type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nan' + 'os":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"' + 'millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552' + '00000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":0,"name":"v","type":"INT"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01' + 'T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:' + '59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"A' + 'sia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:' + '59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00",' + '"-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' + '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-0' + '1T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> STRING","fields":[{"name":"v","ty' + 'pe":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos' + '":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"mi' + 'llis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200' + '000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldR' + 'ef":{"index":0,"name":"v","type":"DOUBLE"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:' + '00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:5' + '9:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12' + ':55.807"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01",' + '"1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00"' + ',"-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","19' + '70-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","' + '2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807' + '"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","' + 'type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nan' + 'os":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"' + 'millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552' + '00000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fiel' + 'dRef":{"index":0,"name":"v","type":"DOUBLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01' + 'T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T2' + '3:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06' + 'T07:12"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 "' + ',"1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","' + '-0001-01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970' + '-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-1' + '1-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v' + '","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"' + 'nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],' + '[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987' + '55200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","f' + 'ieldRef":{"index":0,"name":"v","type":"DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970' + '-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T' + '23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:1' + '2"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-' + '31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T0' + '0:00","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1' + '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+1000' + '0-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> STRING","fields":[{"name":' + '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1' + ',"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}' + '],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-6219' + '8755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST",' + '"fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["' + '1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1' + '969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-17015' + '32-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01' + '-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+1000' + '0-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01' + '-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-' + '31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-0' + '6T07:12:55.807"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name' + '":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis"' + ':1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":' + '0}],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62' + '198755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST' + '","fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC' + '":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59."' + ',"1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","' + '-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01' + '-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01' + '-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00' + ':00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:5' + '9:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07' + ':12"]}}' + ), + json.loads( + '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"n' + 'ame":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"mill' + 'is":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nano' + 's":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":' + '-62198755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"C' + 'AST","fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected"' + ':{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.' + '","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701' + '532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' + ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00",' + '"-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01' + 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' + '13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' + ), + json.loads( + '{"name":"timefull_STRING_to_TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["19' + '70-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["1970-01-01T24:00"],["' + '+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]],"transform":{"name"' + ':"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{' + '"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' + '":946684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos"' + ':0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"Asia/Shanghai' + '":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":94' + '6684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},' + '{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"America/New_York"' + ':[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":946' + '684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},{' + '"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timefull_STRING_to_TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["19' + '70-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["1970-01-01T24:00"],["' + '+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]],"transform":{"name"' + ':"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{' + '"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' + '":946684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos"' + ':0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"Asia/Shanghai' + '":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":94' + '6684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},' + '{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"America/New_York"' + ':[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":946' + '684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},{' + '"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timefull_STRING_to_TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"S' + 'TRING"}],"rows":[["1970-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["' + '1970-01-01T24:00"],["+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]' + '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMEST' + 'AMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,' + '"nanos":0},{"millis":0,"nanos":0},{"millis":946684800000,"nanos":0},{"millis":86400000,"nanos"' + ':0},{"millis":-5336598346174303232,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":173' + '0597400000,"nanos":0},null],"Asia/Shanghai":[{"millis":28828800000,"nanos":0},{"millis":-28800' + '000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":946656000000,"nanos":0},{"millis":5760' + '0000,"nanos":0},{"millis":-5336598346203103232,"nanos":0},{"millis":1710009000000,"nanos":0},{' + '"millis":1730568600000,"nanos":0},null],"America/New_York":[{"millis":28875600000,"nanos":0},{' + '"millis":18000000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":946702800000,"nanos":0},{' + '"millis":104400000,"nanos":0},{"millis":-5336598346156303232,"nanos":0},{"millis":171005580000' + '0,"nanos":0},{"millis":1730611800000,"nanos":0},null]}}' + ), + json.loads( + '{"name":"timefull_STRING_to_TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"S' + 'TRING"}],"rows":[["1970-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["' + '1970-01-01T24:00"],["+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]' + '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMEST' + 'AMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,' + '"nanos":0},{"millis":0,"nanos":0},{"millis":946684800000,"nanos":0},{"millis":86400000,"nanos"' + ':0},{"millis":-5336598346174303232,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":173' + '0597400000,"nanos":0},null],"Asia/Shanghai":[{"millis":28828800000,"nanos":0},{"millis":-28800' + '000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":946656000000,"nanos":0},{"millis":5760' + '0000,"nanos":0},{"millis":-5336598346203103232,"nanos":0},{"millis":1710009000000,"nanos":0},{' + '"millis":1730568600000,"nanos":0},null],"America/New_York":[{"millis":28875600000,"nanos":0},{' + '"millis":18000000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":946702800000,"nanos":0},{' + '"millis":104400000,"nanos":0},{"millis":-5336598346156303232,"nanos":0},{"millis":171005580000' + '0,"nanos":0},{"millis":1730611800000,"nanos":0},null]}}' + ), +] + + +def source_array(values, type_): + if pa.types.is_floating(type_): + values = [None if v is None else float(v) for v in values] + elif pa.types.is_binary(type_): + values = [None if v is None else bytes(v) for v in values] + elif pa.types.is_decimal(type_): + values = [None if v is None else Decimal(v) for v in values] + elif pa.types.is_timestamp(type_): + quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[type_.unit] + converted = [] + for v in values: + if v is None: + converted.append(None) + continue + millis = v['millis'] if isinstance(v, dict) else v + nanos = v.get('nanos', 0) if isinstance(v, dict) else 0 + full = millis * 1000000 + nanos + if full % quantum or not -(1 << 63) <= full // quantum < (1 << 63): + raise OverflowError('Java timestamp cannot be stored in the Arrow source') + converted.append(full // quantum) + values = converted + return pa.array(values, type=type_) + + +def external(array): + type_ = array.type + if pa.types.is_timestamp(type_): + value = array.cast(pa.int64()).to_pylist()[0] + if value is None: + return None + full = value * {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[type_.unit] + return {'millis': full // 1000000, 'nanos': full % 1000000} + if pa.types.is_date(type_) or pa.types.is_time(type_): + return array.cast(pa.int32()).to_pylist()[0] + value = array.to_pylist()[0] + if isinstance(value, Decimal): + return format(value, 'f') + if isinstance(value, float) and math.isinf(value): + return 'Infinity' if value > 0 else '-Infinity' + return list(value) if isinstance(value, bytes) else value + + +def unrepresentable(expected, target): + if not pa.types.is_timestamp(target) or not isinstance(expected, dict) or 'millis' not in expected: + return False + full = expected['millis'] * 1000000 + expected['nanos'] + quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] + return bool(full % quantum) or not -(1 << 63) <= full // quantum < (1 << 63) + + +def invalid_utf8(value, source): + if value is None or not pa.types.is_binary(source): + return False + try: + bytes(value).decode('utf8') + except UnicodeDecodeError: + return True + return False + + +@pytest.mark.parametrize('zone', ['UTC', 'Asia/Shanghai', 'America/New_York']) +@pytest.mark.parametrize('case', JAVA_CASES, ids=lambda case: case['name']) +def test_scalar_cast_completion_matches_actual_java(case, zone, monkeypatch): + monkeypatch.setenv('TZ', zone) + time.tzset() + try: + source = _paimon_type_to_arrow(case['fields'][0]['type']) + target = _paimon_type_to_arrow(case['transform']['type']) + for row, expected in zip(case['rows'], case['expected'][zone]): + try: + array = source_array([row[0]], source) + except OverflowError: + continue + batch = pa.RecordBatch.from_pydict({'v': array}) + error = (isinstance(expected, dict) and 'error' in expected + or unrepresentable(expected, target) or invalid_utf8(row[0], source)) + if error: + with pytest.raises((ValueError, TypeError, OverflowError, pa.ArrowException)): + _apply_predicate_transform(case['transform'], batch) + else: + assert external(_apply_predicate_transform(case['transform'], batch)) == expected, row + finally: + monkeypatch.undo() + time.tzset() + + +@pytest.mark.parametrize('type_', ['VARCHAR(0)', 'CHAR(2147483648)', 'BINARY(0)', 'VARBINARY(2147483648)']) +@pytest.mark.parametrize('values', [[], [None]]) +def test_invalid_cast_width_is_validated_before_null_short_circuit(type_, values): + batch = pa.RecordBatch.from_pydict({'v': pa.array(values, type=pa.string())}) + rule = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': type_} + with pytest.raises(ValueError, match='Cast width'): + _apply_predicate_transform(rule, batch) + + +@pytest.mark.parametrize('suffix', [' 24::00', 'T24::00', 'T24::00.', ' 24:00:.', 'T24:00:.000']) +def test_smart_timestamp_rejects_partial_24_hour_time(suffix): + batch = pa.RecordBatch.from_pydict({'v': ['1970-01-02' + suffix]}) + rule = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'TIMESTAMP(3)'} + with pytest.raises(ValueError): + _apply_predicate_transform(rule, batch) + + +def test_existing_python_java_capability_matrix_is_complete(): + # Independent 20 by 20 matrix from the old Python path and actual Java. + from pypaimon.casting.cast_executor import supports_cast + types = [ + 'BOOLEAN', + 'TINYINT', + 'SMALLINT', + 'INT', + 'BIGINT', + 'FLOAT', + 'DOUBLE', + 'DECIMAL(12,3)', + 'STRING', + 'CHAR(8)', + 'VARCHAR(8)', + 'BINARY(8)', + 'VARBINARY(32)', + 'BYTES', + 'DATE', + 'TIME(3)', + 'TIMESTAMP(3)', + 'TIMESTAMP(6)', + 'TIMESTAMP(3) WITH LOCAL TIME ZONE', + 'TIMESTAMP(6) WITH LOCAL TIME ZONE', + ] + supported = [ + '01111110111000000000', + '11111111111000000000', + '11111111111000000000', + '11111111111000000000', + '11111111111000001111', + '01111111111000000000', + '01111111111000000000', + '01111111111000000000', + '11111111111111101111', + '11111111111111101111', + '11111111111111101111', + '00000000111111000000', + '00000000111111000000', + '00000000111111000000', + '00000000111000001111', + '00000000111000000000', + '00001000111000111111', + '00001000111000111111', + '00001000111000111111', + '00001000111000111111', + ] + for source, expected in zip(types, supported): + for target, expected in zip(types, expected): + actual = supports_cast(_paimon_type_to_arrow(source), _paimon_type_to_arrow(target)) + assert actual == (expected == '1'), (source, target) + + +@pytest.mark.parametrize('type_', ['DECIMAL(4,-1)', 'DECIMAL(4,5)', 'DECIMAL(39,0)', + 'TIMESTAMP(10)', 'TIMESTAMP(3) WITH LOCAL TIME ZONE GARBAGE', + 'CHAR(+1)', 'CHAR(١)', 'CHAR(1_0)', 'TIMESTAMP(١)', 'DECIMAL(٤,٢)']) +def test_invalid_java_cast_types_are_rejected_for_null_input(type_): + batch = pa.RecordBatch.from_pydict({'v': pa.array([None], type=pa.string())}) + with pytest.raises(ValueError): + _apply_predicate_transform({'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': type_}, + batch) diff --git a/paimon-python/pypaimon/tests/mask_output_test.py b/paimon-python/pypaimon/tests/mask_output_test.py new file mode 100644 index 000000000000..78f47e666d32 --- /dev/null +++ b/paimon-python/pypaimon/tests/mask_output_test.py @@ -0,0 +1,86 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Authorization outputs preserve Java object values in canonical Arrow storage.""" + +from decimal import Decimal + +import pyarrow as pa +import pytest + +from pypaimon.casting.mask_output import cast_mask_output +from pypaimon.read.reader.auth_masking_reader import apply_auth_masking + + +@pytest.mark.parametrize('source', [pa.int32(), pa.date32(), pa.time32('ms')]) +@pytest.mark.parametrize('target', [pa.int32(), pa.date32(), pa.time32('ms')]) +def test_integer_class_masks_preserve_raw_values(source, target): + values = pa.array([-1, 123, None], type=source) + actual = cast_mask_output(values, target) + assert actual.cast(pa.int32()).to_pylist() == [-1, 123, None] + + +@pytest.mark.parametrize('type_name,target,values', [ + ('large_string', pa.string(), ['a', None]), ('string_view', pa.string(), ['a', None]), + ('large_binary', pa.binary(), [b'a', None]), ('binary_view', pa.binary(), [b'a', None]), +]) +def test_equivalent_arrow_string_and_byte_encodings_are_normalized(type_name, target, values): + factory = getattr(pa, type_name, None) + if factory is None: + pytest.skip('Physical view encoding is unavailable in this PyArrow version') + actual = cast_mask_output(pa.array(values, type=factory()), target) + assert actual.type == target and actual.to_pylist() == values + + +def test_decimal_mask_output_never_rounds_or_overflows(): + target = pa.decimal128(4, 2) + actual = cast_mask_output(pa.array([Decimal('2.670'), None], type=pa.decimal128(7, 3)), target) + assert actual.to_pylist() == [Decimal('2.67'), None] + for value in ('2.675', '-2.675', '1000.000'): + with pytest.raises(pa.ArrowInvalid): + cast_mask_output(pa.array([Decimal(value)], type=pa.decimal128(7, 3)), target) + + +def test_timestamp_mask_output_never_truncates_or_overflows(): + target = pa.timestamp('ms') + actual = cast_mask_output(pa.array([1000, None], type=pa.timestamp('us')), target) + assert actual.cast(pa.int64()).to_pylist() == [1, None] + for value in (1001, -1001): + with pytest.raises(pa.ArrowInvalid): + cast_mask_output(pa.array([value], type=pa.timestamp('us')), target) + with pytest.raises(pa.ArrowInvalid): + cast_mask_output(pa.array([(1 << 63) - 1], type=target), pa.timestamp('ns')) + + +def test_masking_preserves_field_and_schema_metadata(): + schema = pa.schema([pa.field('v', pa.string(), nullable=False, metadata={b'field': b'id'})], + metadata={b'table': b'contract'}) + batch = pa.RecordBatch.from_arrays([pa.array(['secret'])], schema=schema) + output = apply_auth_masking(batch, {'v': {'name': 'NULL'}}) + assert output.column(0).to_pylist() == [None] + assert output.schema.field(0).nullable + assert output.schema.field(0).metadata == schema.field(0).metadata + assert output.schema.metadata == schema.metadata + assert not batch.schema.field(0).nullable + + +@pytest.mark.parametrize('values', [[], [None, None]]) +def test_null_and_empty_masks_skip_runtime_class_check(values): + output = cast_mask_output(pa.array(values, type=pa.string()), pa.int32()) + assert output.type == pa.int32() and output.to_pylist() == values + with pytest.raises(ValueError): + cast_mask_output(pa.array(['bad', None]), pa.int32()) diff --git a/paimon-python/pypaimon/tests/native_cast_completion_test.py b/paimon-python/pypaimon/tests/native_cast_completion_test.py new file mode 100644 index 000000000000..28921c0bccfe --- /dev/null +++ b/paimon-python/pypaimon/tests/native_cast_completion_test.py @@ -0,0 +1,207 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Java CAST completion through real REST plans and strict Native readers.""" + +import json +import time +from decimal import Decimal + +import pyarrow as pa +import pytest + +from pypaimon import Schema +from pypaimon.api.api_response import AuthTableQueryResponse +from pypaimon.common.predicate_builder import PredicateBuilder +from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow +from pypaimon.schema.data_types import DataTypeParser +from pypaimon.tests import native_numeric_cast_test +from pypaimon.tests.authorization_cast_completion_test import ( + JAVA_CASES, invalid_utf8, source_array, unrepresentable, +) + +rest_catalog = native_numeric_cast_test.rest_catalog +table_mode = native_numeric_cast_test.table_mode +_read = native_numeric_cast_test._read +_create_table = native_numeric_cast_test._create_table +pytestmark = native_numeric_cast_test.pytestmark + + +def _native_cases(): + cases = [] + for case in JAVA_CASES: + source = _paimon_type_to_arrow(case['fields'][0]['type']) + target = _paimon_type_to_arrow(case['transform']['type']) + pairs = [] + for row, value in zip(case['rows'], case['expected']['UTC']): + if (isinstance(value, dict) and 'error' in value or unrepresentable(value, target) + or invalid_utf8(row[0], source)): + continue + try: + source_array([row[0]], source) + except OverflowError: + continue + pairs.append((row, value)) + if any(value is not None for _, value in pairs): + cases.append(dict(case, rows=[row for row, _ in pairs], values=[v for _, v in pairs])) + return cases + + +def _definition(schema, table_mode, case): + mode, options = table_mode + definition = Schema.from_pyarrow_schema( + schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options) + definition.fields[1].type = DataTypeParser.parse_data_type(case['fields'][0]['type']) + definition.fields[2].type = DataTypeParser.parse_data_type(case['transform']['type']) + return definition + + +@pytest.mark.parametrize('case', _native_cases(), ids=lambda case: case['name']) +def test_all_scalar_cast_families_mask_hidden_fields_natively(rest_catalog, table_mode, case, monkeypatch): + monkeypatch.setenv('TZ', 'UTC') + time.tzset() + try: + source = _paimon_type_to_arrow(case['fields'][0]['type']) + target = _paimon_type_to_arrow(case['transform']['type']) + count = len(case['rows']) + schema = pa.schema([('id', pa.int32()), ('v', source), ('masked', target)]) + data = pa.Table.from_arrays([ + pa.array(range(count), type=pa.int32()), + source_array([row[0] for row in case['rows']], source), pa.nulls(count, type=target), + ], schema=schema) + definition = _definition(schema, table_mode, case) + table, server = _create_table(rest_catalog, table_mode, schema, data, definition) + grant_key = table.identifier.get_full_name() + server.table_query_auth_store[grant_key] = AuthTableQueryResponse( + column_masking={'masked': json.dumps(case['transform'])}) + expected = source_array(case['values'], target) + for native in [False, True]: + result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) + assert result.column('masked').combine_chunks().equals(expected) + predicate = PredicateBuilder(table.fields).is_not_null('masked') + first = next(i for i, value in enumerate(case['values']) if value is not None) + assert _read(table, native, ['id'], predicate, limit=1).to_pylist() == [{'id': first}] + # A transformed authorization predicate also needs its hidden source. + rule = {'kind': 'LEAF', 'transform': case['transform'], 'function': 'IS_NOT_NULL', 'literals': []} + server.table_query_auth_store[grant_key] = AuthTableQueryResponse(filter=[json.dumps(rule)]) + expected_ids = [{'id': i} for i, v in enumerate(case['values']) if v is not None] + for native in [False, True]: + assert _read(table, native, ['id']).sort_by([('id', 'ascending')]).to_pylist() == expected_ids + finally: + monkeypatch.undo() + time.tzset() + + +@pytest.mark.parametrize('mask', ['null', 'overflow']) +def test_not_null_mask_outputs_remain_nullable_and_physical_type_is_unchanged(rest_catalog, table_mode, mask): + target = pa.string() if mask == 'null' else pa.decimal128(4, 2) + schema = pa.schema([pa.field('id', pa.int32(), nullable=False), pa.field('v', pa.int32()), + pa.field('masked', target, nullable=False)]) + data = pa.Table.from_arrays([pa.array([0, 1], type=pa.int32()), pa.array([1, 100], type=pa.int32()), + pa.array(['secret'] * 2 if mask == 'null' else [Decimal('0')] * 2, + type=target)], schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + transform = ({'name': 'NULL'} if mask == 'null' else { + 'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'INT'}, 'type': 'DECIMAL(4,2)'}) + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + column_masking={'masked': json.dumps(transform)}) + expected = [None, None] if mask == 'null' else [Decimal('1.00'), None] + for native in [False, True]: + result = _read(table, native, ['masked', 'id']).sort_by([('id', 'ascending')]) + assert result.column('masked').to_pylist() == expected + assert result.schema.field('masked').nullable + assert not result.schema.field('id').nullable + empty = _read(table, native, ['masked'], limit=0) + assert empty.num_rows == 0 and empty.schema.field('masked').nullable + builder = table.copy({'read.native.enabled': str(native).lower(), + 'scan.native-plan.enabled': str(native).lower()}).new_read_builder() + builder.with_projection(['masked', 'id']) + splits = builder.new_scan().plan().splits() + reader = builder.new_read() + assert not reader.read_type[0].type.nullable + with reader.to_arrow_batch_reader(splits) as batches: + assert batches.schema.field('masked').nullable + assert batches.read_all().column('masked').to_pylist() == expected + if not native: + # A captured split enforces its grant even if this handle has no + # live authorization option. The output schema follows that split. + captured = table.copy({'query-auth.enabled': 'false', 'read.native.enabled': 'false', + 'scan.native-plan.enabled': 'false'}).new_read_builder() + captured.with_projection(['masked', 'id']) + with captured.new_read().to_arrow_batch_reader(splits) as batches: + batch = batches.read_next_batch() + assert batches.schema.equals(batch.schema, check_metadata=True) + assert batch.column('masked').to_pylist() == expected + assert batch.schema.field('masked').nullable + assert not batch.schema.field('id').nullable + + +@pytest.mark.parametrize('target,mask_type,values,expected', [ + (pa.decimal128(4, 2), 'DECIMAL(6,3)', ['2.670', '1000'], [Decimal('2.67'), None]), + (pa.timestamp('ms'), 'TIMESTAMP(6)', ['1000', '-1000'], [1, -1]), +]) +def test_masks_adapt_decimal_and_timestamp_storage_without_loss( + rest_catalog, table_mode, target, mask_type, values, expected): + schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', target)]) + data = pa.Table.from_arrays([pa.array([0, 1], type=pa.int32()), pa.array(values), + pa.nulls(2, type=target)], schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': mask_type} + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + column_masking={'masked': json.dumps(transform)}) + for native in [False, True]: + result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) + assert result.column('masked').combine_chunks().equals(pa.array(expected, type=target)) + + +@pytest.mark.parametrize('target,mask_type,value', [ + (pa.decimal128(4, 2), 'DECIMAL(6,3)', '2.675'), + (pa.decimal128(4, 2), 'DECIMAL(7,3)', '1000'), + (pa.timestamp('ms'), 'TIMESTAMP(6)', '1001'), +]) +def test_mask_output_representation_never_rounds_or_truncates( + rest_catalog, table_mode, target, mask_type, value): + schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', target)]) + data = pa.Table.from_arrays([pa.array([0], type=pa.int32()), pa.array([value]), + pa.nulls(1, type=target)], schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': mask_type} + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + column_masking={'masked': json.dumps(transform)}) + for native in [False, True]: + with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): + _read(table, native, ['masked']) + + +@pytest.mark.parametrize('guard', [True, False]) +def test_mask_class_checks_follow_authorization_row_filter(rest_catalog, table_mode, guard): + schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', pa.int32())]) + table, server = _create_table( + rest_catalog, table_mode, schema, + pa.table({'id': [0, 1], 'v': [None, 'bad'], 'masked': [1, 2]}, schema=schema)) + transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'STRING'} + filter_ = {'kind': 'LEAF', 'function': 'IS_NULL', 'literals': [], + 'transform': {'name': 'FIELD_REF', 'fieldRef': {'name': 'v', 'type': 'STRING'}}} + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + filter=[json.dumps(filter_)] if guard else None, column_masking={'masked': json.dumps(transform)}) + for native in [False, True]: + if guard: + assert _read(table, native, ['id', 'masked']).to_pylist() == [{'id': 0, 'masked': None}] + else: + with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): + _read(table, native, ['masked']) + assert _read(table, native, ['masked'], limit=0).num_rows == 0 diff --git a/paimon-python/pypaimon/tests/native_numeric_cast_test.py b/paimon-python/pypaimon/tests/native_numeric_cast_test.py index 36929b9355ca..12b479beee2c 100644 --- a/paimon-python/pypaimon/tests/native_numeric_cast_test.py +++ b/paimon-python/pypaimon/tests/native_numeric_cast_test.py @@ -59,11 +59,12 @@ def table_mode(request): return request.param -def _create_table(rest_catalog, table_mode, schema, data): +def _create_table(rest_catalog, table_mode, schema, data, paimon_schema=None): catalog, server = rest_catalog mode, options = table_mode - catalog.create_table('default.numeric', Schema.from_pyarrow_schema( - schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options), False) + definition = paimon_schema or Schema.from_pyarrow_schema( + schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options) + catalog.create_table('default.numeric', definition, False) table = catalog.get_table('default.numeric') builder = table.new_batch_write_builder() writer, commit = builder.new_write(), builder.new_commit() diff --git a/paimon-python/pypaimon/tests/predicate_json_parser_test.py b/paimon-python/pypaimon/tests/predicate_json_parser_test.py index 7dc1991d664a..048dbd538faa 100644 --- a/paimon-python/pypaimon/tests/predicate_json_parser_test.py +++ b/paimon-python/pypaimon/tests/predicate_json_parser_test.py @@ -420,13 +420,17 @@ def test_rebound_numeric_to_string_uses_decimal_plain_text(self): def test_rebound_numeric_to_string_refuses_other_object_formatting(self): transform = {'name': 'CAST', 'fieldRef': {'name': 's', 'type': 'INT'}, 'type': 'STRING'} - for array in [pa.array([0, None], type=pa.timestamp('ms')), pa.array([b'a', None]), - pa.array([1.0, None], type=pa.float64())]: + for array in [pa.array([b'a', None])]: with self.subTest(type=array.type), self.assertRaises(ValueError): _apply_predicate_transform(transform, pa.RecordBatch.from_pydict({'s': array})) nulls = pa.RecordBatch.from_pydict({'s': pa.nulls(2, type=array.type)}) self.assertEqual(_apply_predicate_transform(transform, nulls).to_pylist(), [None, None]) + def test_rebound_numeric_to_string_formats_float_runtime_values(self): + transform = {'name': 'CAST', 'fieldRef': {'name': 's', 'type': 'INT'}, 'type': 'STRING'} + batch = pa.RecordBatch.from_pydict({'s': pa.array([1.0, None], type=pa.float64())}) + self.assertEqual(_apply_predicate_transform(transform, batch).to_pylist(), ['1.0', None]) + def test_empty_concat_is_the_empty_string(self): self.assertEqual(_apply_predicate_transform({'name': 'CONCAT', 'inputs': []}, self.batch).to_pylist(), [''] * len(self.batch)) From 461b1e67e282908ed56ac4e764cfef5d7b15d0ed Mon Sep 17 00:00:00 2001 From: JingsongLi Date: Wed, 14 Oct 2026 21:49:08 +0800 Subject: [PATCH 3/4] Keep Python authorization cast changes limited to native integration --- .../pypaimon/casting/cast_executor.py | 260 -- paimon-python/pypaimon/casting/cast_text.py | 154 - .../pypaimon/casting/decimal_cast.py | 19 +- .../pypaimon/casting/floating_cast.py | 125 - paimon-python/pypaimon/casting/mask_output.py | 57 - .../pypaimon/casting/numeric_cast.py | 152 - .../pypaimon/casting/numeric_utils.py | 45 - .../pypaimon/casting/schema_evolution.py | 50 +- .../pypaimon/casting/temporal_cast.py | 7 +- .../pypaimon/casting/temporal_string.py | 29 +- .../pypaimon/casting/temporal_utils.py | 11 +- .../pypaimon/common/predicate_json_parser.py | 93 +- .../read/reader/auth_masking_reader.py | 7 +- .../tests/auth_masking_reader_test.py | 55 +- .../authorization_cast_completion_test.py | 2725 ----------------- .../tests/authorization_numeric_cast_test.py | 569 ---- .../pypaimon/tests/mask_output_test.py | 86 - .../tests/native_cast_completion_test.py | 327 +- .../tests/native_numeric_cast_test.py | 132 - .../native_schema_evolution_cast_test.py | 13 +- .../tests/predicate_json_parser_test.py | 8 +- 21 files changed, 366 insertions(+), 4558 deletions(-) delete mode 100644 paimon-python/pypaimon/casting/cast_executor.py delete mode 100644 paimon-python/pypaimon/casting/cast_text.py delete mode 100644 paimon-python/pypaimon/casting/floating_cast.py delete mode 100644 paimon-python/pypaimon/casting/mask_output.py delete mode 100644 paimon-python/pypaimon/casting/numeric_cast.py delete mode 100644 paimon-python/pypaimon/tests/authorization_cast_completion_test.py delete mode 100644 paimon-python/pypaimon/tests/authorization_numeric_cast_test.py delete mode 100644 paimon-python/pypaimon/tests/mask_output_test.py delete mode 100644 paimon-python/pypaimon/tests/native_numeric_cast_test.py diff --git a/paimon-python/pypaimon/casting/cast_executor.py b/paimon-python/pypaimon/casting/cast_executor.py deleted file mode 100644 index fce9a2ceb804..000000000000 --- a/paimon-python/pypaimon/casting/cast_executor.py +++ /dev/null @@ -1,260 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""The existing Python scalar CAST subset with Java's original executor.""" - -import re - -import pyarrow as pa - -from pypaimon.casting.cast_text import format_date, parse_date, parse_timestamp -from pypaimon.casting.floating_cast import parse_java_float -from pypaimon.casting.numeric_cast import cast_numeric, _numeric_to_integer -from pypaimon.casting.numeric_utils import java_number_string -from pypaimon.casting.schema_evolution import _timestamp_to_bigint -from pypaimon.casting.temporal_cast import cast_temporal -from pypaimon.casting.temporal_string import temporal_to_string, timestamp_object_to_string -from pypaimon.casting.temporal_utils import _signed -from pypaimon.table.row.generic_row import _parse_type_precision_scale - - -def _text(t): - return pa.types.is_string(t) or pa.types.is_large_string(t) - - -def _binary(t): - return pa.types.is_binary(t) or pa.types.is_large_binary(t) - - -def _primitive(t): - return pa.types.is_signed_integer(t) or pa.types.is_floating(t) - - -def _numeric(t): - return _primitive(t) or pa.types.is_decimal(t) - - -def _number(t): - return _primitive(t) or pa.types.is_date(t) or pa.types.is_time(t) - - -def _integer_object(t): - return t == pa.int32() or pa.types.is_date(t) or pa.types.is_time(t) - - -def supports_cast(source, target): - if _numeric(source) and _numeric(target): - return True - if pa.types.is_boolean(source) and (_primitive(target) or _text(target)): - return True - if pa.types.is_signed_integer(source) and pa.types.is_boolean(target): - return True - if _text(target) and (_numeric(source) or _text(source) or _binary(source) - or pa.types.is_date(source) or pa.types.is_time(source) or pa.types.is_timestamp(source)): - return True - if _binary(target) and (_text(source) or _binary(source)): - return True - if _text(source) and (_numeric(target) or pa.types.is_boolean(target) - or pa.types.is_date(target) or pa.types.is_timestamp(target)): - return True - if (source == pa.int64() or pa.types.is_date(source)) and pa.types.is_timestamp(target): - return True - if pa.types.is_timestamp(source) and (pa.types.is_timestamp(target) or pa.types.is_date(target) - or pa.types.is_time(target) or target == pa.int64()): - return True - return False - - -def _number_input(array): - if pa.types.is_date(array.type): - return array.cast(pa.date32(), safe=False).cast(pa.int32()) - if pa.types.is_time(array.type): - return array.cast(pa.time32('ms'), safe=False).cast(pa.int32()) - return array - - -def _timestamp_parts(array): - ticks = array.cast(pa.int64()).to_pylist() - unit = array.type.unit - return [None if value is None else - (_signed(value * 1000, 64), 0) if unit == 's' else - (value, 0) if unit == 'ms' else - (value // 1000, value % 1000 * 1000) if unit == 'us' else - (value // 1000000, value % 1000000) for value in ticks] - - -def _timestamp_storage(values, target): - quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] - ticks = [] - for value in values: - if value is None: - ticks.append(None) - continue - millis, nanos = value - full = millis * 1000000 + nanos - if full % quantum or not -(1 << 63) <= full // quantum < (1 << 63): - raise ValueError('Java timestamp result cannot be represented by the Arrow target') - ticks.append(full // quantum) - return pa.array(ticks, type=pa.int64()).cast(target) - - -def _fit_width(array, target): - width = re.fullmatch(r'\s*(CHAR|VARCHAR|BINARY|VARBINARY)(?:\s*\(\s*([0-9]+)\s*\))?' - r'\s*(?:(?:NOT\s+)?NULL)?\s*', target, flags=re.IGNORECASE) - if width is None: - return array - kind, length = width.group(1).upper(), int(width.group(2) or 1) - if not 1 <= length <= (1 << 31) - 1: - raise ValueError('Cast width must be between 1 and 2147483647') - pad = kind in ('CHAR', 'BINARY') - padding = ' ' if kind == 'CHAR' else b'\x00' - return pa.array([None if value is None else - (value[:length] + padding * max(0, length - len(value)) if pad else value[:length]) - for value in array.to_pylist()], type=array.type) - - -def cast_array(array, source_type, target_type): - # Keep the transport parser independent of value execution. - from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow - - source, target = _paimon_type_to_arrow(source_type), _paimon_type_to_arrow(target_type) - if pa.types.is_boolean(target) and (pa.types.is_floating(source) or pa.types.is_decimal(source)): - raise ValueError("Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast") - if not supports_cast(source, target): - raise pa.ArrowNotImplementedError('CAST is outside the existing Python/Java scalar rules: %s -> %s' - % (source_type, target_type)) - if array.null_count == len(array): - return pa.nulls(len(array), type=target) - current = array.type - - def require(valid): - if not valid: - raise ValueError('CAST source no longer has the runtime class its original Java executor expects') - - if _numeric(source) and _text(target): - require(_numeric(current) or _text(current) or pa.types.is_boolean(current) - or pa.types.is_date(current) or pa.types.is_time(current) or pa.types.is_timestamp(current)) - value = _number_input(array) - if pa.types.is_timestamp(value.type): - result = timestamp_object_to_string(value) - elif pa.types.is_floating(value.type): - result = pa.array([None if v is None else java_number_string(v, value.type == pa.float32()) - for v in value.to_pylist()], type=target) - elif pa.types.is_decimal(value.type): - result = pa.array([None if v is None else format(v, 'f') for v in value.to_pylist()], type=target) - else: - result = value.cast(target, safe=False) - elif _numeric(source) and _numeric(target): - require(pa.types.is_decimal(current) if pa.types.is_decimal(source) else _number(current)) - value = _number_input(array) - if pa.types.is_decimal(target) and _primitive(source): - value = (_numeric_to_integer(value, pa.int64()) if pa.types.is_signed_integer(source) - else value.cast(pa.float64(), safe=False)) - result = cast_numeric(value, target) - elif pa.types.is_signed_integer(source) and pa.types.is_boolean(target): - require(_number(current)) - result = _numeric_to_integer(_number_input(array), pa.int64()).cast(target, safe=False) - elif pa.types.is_boolean(source): - require(pa.types.is_boolean(current)) - result = array.cast(target, safe=False) - elif _text(source): - require(_text(current)) - if pa.types.is_floating(target): - result = pa.array([None if v is None else parse_java_float(v, target == pa.float32()) - for v in array.to_pylist()], type=target) - elif pa.types.is_date(target): - result = pa.array([None if v is None else parse_date(v) for v in array.to_pylist()], - type=pa.int32()).cast(target) - elif pa.types.is_timestamp(target): - precision = _parse_type_precision_scale(target_type)[0] - values = [None if v is None else parse_timestamp(v, precision, target.tz is not None) - for v in array.to_pylist()] - result = _timestamp_storage(values, target) - else: - result = cast_numeric(array, target) - if result is None: - result = array.cast(target, safe=False) - elif _binary(source): - require(_binary(current)) - if _text(target): - # Arrow may relabel binary buffers as UTF8 without validating them. - # Java BinaryString preserves these bytes; an Arrow string cannot. - for value in array.to_pylist(): - if value is not None: - value.decode("utf8") - result = array.cast(target, safe=False) - if _text(target): - return result # BinaryToString does not trim/pad character width. - elif pa.types.is_date(source): - if pa.types.is_timestamp(target): - require(_number(current)) - values = _number_input(array) - if target.tz is not None: - integers = _numeric_to_integer(values, pa.int32()).cast(pa.date32()) - result = cast_temporal(integers, target, source_type, target_type, strict=True) - else: - values = _numeric_to_integer(values, pa.int64()).to_pylist() - result = _timestamp_storage( - [None if v is None else (_signed(v * 86400000, 64), 0) for v in values], target) - else: - require(_integer_object(current)) - value = _number_input(array).cast(pa.int32()) - result = (pa.array([None if v is None else format_date(v) for v in value.to_pylist()], type=target) - if _text(target) else value.cast(target)) - elif pa.types.is_time(source): - require(_integer_object(current)) - value = _number_input(array).cast(pa.int32()).cast(pa.time32('ms')) - result = (temporal_to_string(value, source_type, 'STRING') if _text(target) else value.cast(target)) - elif pa.types.is_timestamp(source): - require(pa.types.is_timestamp(current)) - if _text(target): - result = temporal_to_string(array, source_type, 'STRING') - elif target == pa.int64(): - # The original timestamp kind selects the executor even after rebind. - value = array.cast(pa.timestamp(array.type.unit, source.tz)) - result = _timestamp_to_bigint(value) - else: - result = cast_temporal(array, target, source_type, target_type, strict=True) - if result is None: - precision = _parse_type_precision_scale(target_type)[0] - truncate = _parse_type_precision_scale(source_type)[0] > precision - values = [] - for value in _timestamp_parts(array): - if value is None: - values.append(None) - continue - millis, nanos = value - if truncate: - if precision <= 3: - quantum = 10 ** (3 - precision) - millis, nanos = _signed(millis // quantum * quantum, 64), 0 - else: - quantum = 10 ** (9 - precision) - nanos = nanos // quantum * quantum - values.append((millis, nanos)) - result = _timestamp_storage(values, target) - else: # BIGINT -> timestamp uses Number.longValue in epoch seconds. - require(_number(current)) - value = _numeric_to_integer(_number_input(array), pa.int64()) - if target.tz is not None: - result = cast_temporal(value, target, source_type, target_type, strict=True) - else: - values = [None if v is None else (_signed(v * 1000, 64), 0) for v in value.to_pylist()] - result = _timestamp_storage(values, target) - if pa.types.is_timestamp(target) and result.null_count > array.null_count: - raise ValueError('Java timestamp result cannot be represented by the Arrow target') - return _fit_width(result, target_type) diff --git a/paimon-python/pypaimon/casting/cast_text.py b/paimon-python/pypaimon/casting/cast_text.py deleted file mode 100644 index 0def1cb4af9c..000000000000 --- a/paimon-python/pypaimon/casting/cast_text.py +++ /dev/null @@ -1,154 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Java BinaryStringUtils date/timestamp text, including SMART resolution.""" - -import re - -from pypaimon.casting.numeric_cast import _parse_integer -from pypaimon.casting.numeric_utils import java_decimal_digit -from pypaimon.casting.temporal_utils import ( - _div, _rem, _signed, _java_date_parts, _ymd_to_epoch_day, - _epoch_day_to_java_date, _local_to_utc_seconds, -) - - -_TRIM = ''.join(chr(i) for i in range(33)) -_DIGITS = re.compile(r'[0-9]+\Z') - - -def _numeric(text): - text = text[1:] if text.startswith('-') else text - return bool(text) and all(java_decimal_digit(ch) is not None for ch in text) - - -def format_date(value): - year, month, day = _java_date_parts(value) - return '-'.join(''.join(chr(48 + _rem(_div(value, divisor), 10)) for divisor in divisors) - for value, divisors in [(year, (1000, 100, 10, 1)), (month, (10, 1)), (day, (10, 1))]) - - -def _days_in_month(year, month): - leap = year % 400 == 0 or year % 4 == 0 and year % 100 != 0 - return 29 if month == 2 and leap else 28 if month == 2 else 30 if month in (4, 6, 9, 11) else ( - 31 if 1 <= month <= 12 else 0) - - -def parse_date(text): - if _numeric(text): - return _parse_integer(text, 32) - position = text.find(' ') - date = text[:position] if position > 0 else text - components = date.split('-') - if len(components) > 3: - raise ValueError('Invalid Java DATE: %s' % text) - values = [0, 1, 1] - for i, component in enumerate(components): - component = component.strip(_TRIM) - if _DIGITS.fullmatch(component) is None or len(component.lstrip('0')) > 10: - raise ValueError('Invalid Java DATE: %s' % text) - values[i] = int(component.lstrip('0') or '0') - if values[i] > (1 << 31) - 1: - raise ValueError('Invalid Java DATE: %s' % text) - year, month, day = values - if not 0 <= year <= 9999 or not 1 <= day <= _days_in_month(year, month): - raise ValueError('Invalid Java DATE: %s' % text) - return _epoch_day_to_java_date(_ymd_to_epoch_day(year, month, day)) - - -def _component(text): - if not text: - return None - if len(text) > 21 or _DIGITS.fullmatch(text) is None: - raise ValueError('Invalid Java timestamp component') - first = int(text[:2]) - if len(text) > 2 and int(text[2:]) != first: - raise ValueError('Conflicting Java timestamp fields') - return first - - -def _time_components(text, space): - parts = text.split(':') - if not (3 if space else 2) <= len(parts) <= 3: - raise ValueError('Invalid Java timestamp time') - values = [_component(parts[0]), _component(parts[1]), None, None] - if len(parts) == 3: - second, dot, fraction = parts[2].partition('.') - values[2] = _component(second) - if dot: - if len(fraction) > 9 or fraction and _DIGITS.fullmatch(fraction) is None: - raise ValueError('Invalid Java timestamp fraction') - values[3] = int(fraction or '0') * 10 ** (9 - len(fraction)) - return values - - -def parse_timestamp(text, precision, local): - if not local and _numeric(text): - ticks = _parse_integer(text, 64) - if precision == 0: - return _signed(ticks * 1000, 64), 0 - if precision == 3: - return ticks, 0 - if precision in (6, 9): - divisor, factor = (1000, 1000) if precision == 6 else (1000000, 1) - return ticks // divisor, ticks % divisor * factor - raise ValueError('Unsupported numeric timestamp precision') - position = next((i for i, ch in enumerate(text) if ch in (' ', 'T')), len(text)) - date, rest = text[:position], text[position:] - parts = date.split('-') - if len(parts) != 3: - raise ValueError('Invalid Java timestamp date: %s' % text) - if not parts[1] and parts[2]: - raise ValueError('Java timestamp day needs its month') - year_text = parts[0] - digits = year_text[1:] if year_text.startswith('+') else year_text - if (_DIGITS.fullmatch(digits) is None or len(digits) > 19 - or (len(digits) <= 4 if year_text.startswith('+') else len(digits) != 4)): - raise ValueError('Invalid Java timestamp year') - year = int(digits) - complete_date = bool(parts[1]) and bool(parts[2]) - month, day = _component(parts[1]), _component(parts[2]) - month, day = 1 if month is None else month, 1 if day is None else day - if not 1 <= year <= 999999999 or not 1 <= month <= 12 or not 1 <= day <= 31: - raise ValueError('Invalid Java timestamp date') - epoch_day = _ymd_to_epoch_day(year, month, min(day, _days_in_month(year, month))) - values = [None] * 4 - if rest.startswith(' '): - other, separator, tail = rest[1:].partition('T') - values = _time_components(other, True) - rest = separator + tail - if rest.startswith('T'): - other = _time_components(rest[1:], False) - for i, value in enumerate(other): - if values[i] is not None and value is not None and values[i] != value: - raise ValueError('Conflicting Java timestamp time') - if value is not None: - values[i] = value - rest = '' - if rest: - raise ValueError('Invalid Java timestamp suffix') - if values[0] == 24 and (values[1] is None and values[2] is not None - or values[2] is None and values[3] is not None): - raise ValueError("Java timestamp requires a minute for 24-hour time with seconds") - hour, minute, second, nanos = [0 if v is None else v for v in values] - if (not 0 <= hour <= 24 or not 0 <= minute <= 59 or not 0 <= second <= 59 - or hour == 24 and (minute != 0 or second != 0 or nanos != 0)): - raise ValueError('Invalid Java timestamp time') - seconds = (epoch_day + (hour == 24 and complete_date)) * 86400 + hour % 24 * 3600 + minute * 60 + second - nanos = nanos // 10 ** (9 - precision) * 10 ** (9 - precision) - millis = _signed((_local_to_utc_seconds(seconds) if local else seconds) * 1000, 64) - return _signed(millis + nanos // 1000000, 64), nanos % 1000000 diff --git a/paimon-python/pypaimon/casting/decimal_cast.py b/paimon-python/pypaimon/casting/decimal_cast.py index 9f8c7b97aeb6..eb7170dbea2d 100644 --- a/paimon-python/pypaimon/casting/decimal_cast.py +++ b/paimon-python/pypaimon/casting/decimal_cast.py @@ -22,7 +22,7 @@ import pyarrow as pa -from pypaimon.casting.numeric_utils import java_double_decimal_text, java_decimal_digit +from pypaimon.casting.numeric_utils import java_double_decimal_text _DECIMAL_TEXT = re.compile(r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?\Z') @@ -37,9 +37,8 @@ def cast_decimal(array, target): fails the conversion instead of silently becoming NULL. """ floating = pa.types.is_floating(array.type) - text = pa.types.is_string(array.type) or pa.types.is_large_string(array.type) - integral = pa.types.is_signed_integer(array.type) - if not pa.types.is_decimal(target) or not (floating or text or integral or pa.types.is_decimal(array.type)): + text = pa.types.is_string(array.type) + if not pa.types.is_decimal(target) or not (floating or text or pa.types.is_decimal(array.type)): return None values = [] # The caller's rounding traps and exponent limits must not affect reads. @@ -56,21 +55,11 @@ def cast_decimal(array, target): value = java_double_decimal_text(value) if floating or text: if _DECIMAL_TEXT.fullmatch(value) is None: - # BigDecimal accepts BMP decimal digits, unlike the - # ASCII-only BinaryStringUtils integer text parser. - normalized = [] - for character in value: - digit = java_decimal_digit(character) - normalized.append(str(digit) if digit is not None else character) - value = ''.join(normalized) - if _DECIMAL_TEXT.fullmatch(value) is None: - raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) + raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) try: value = Decimal(value) except InvalidOperation as error: raise pa.ArrowInvalid('Invalid decimal schema-evolution value: %s' % value) from error - if integral: - value = Decimal(value) # BigDecimal validates the adjusted input scale, then setScale and # BigInteger.TEN.pow check their supported range before precision. # Zero bypasses the power check, but still needs a valid input scale. diff --git a/paimon-python/pypaimon/casting/floating_cast.py b/paimon-python/pypaimon/casting/floating_cast.py deleted file mode 100644 index 886141c41220..000000000000 --- a/paimon-python/pypaimon/casting/floating_cast.py +++ /dev/null @@ -1,125 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Java float text, rounding directly to the target IEEE format.""" - -import math -import re -import struct - - -_TRIM = ''.join(chr(i) for i in range(33)) -_DECIMAL = re.compile(r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?[fFdD]?\Z') -_HEX = re.compile(r'[+-]?0[xX](?:[0-9a-fA-F]+(?:\.[0-9a-fA-F]*)?|\.[0-9a-fA-F]+)' - r'[pP][+-]?[0-9]+[fFdD]?\Z') - - -def _exponent(text): - negative = text.startswith('-') - digits = text.lstrip('+-').lstrip('0') - if len(digits) > 19: - return -(1 << 63) if negative else (1 << 63) - 1 - value = int(digits or '0') - return -value if negative else value - - -def _ieee_ratio(numerator, denominator, negative, single): - fraction, bias, packing = (23, 127, '>I') if single else (52, 1023, '>Q') - unpacking = '>f' if single else '>d' - sign = int(negative) << (31 if single else 63) - - def build(bits): - return struct.unpack(unpacking, struct.pack(packing, bits))[0] - - if not numerator: - return build(sign) - leading = numerator.bit_length() - denominator.bit_length() - if (numerator < denominator << leading if leading >= 0 else numerator << (-leading) < denominator): - leading -= 1 - if leading > bias: - return -math.inf if negative else math.inf - minimum = 1 - bias - if leading < minimum - fraction - 1: - return build(sign) - unit = max(leading, minimum) - fraction - if unit >= 0: - denominator <<= unit - else: - numerator <<= -unit - significand, remainder = divmod(numerator, denominator) - if 2 * remainder > denominator or 2 * remainder == denominator and significand % 2: - significand += 1 - if significand == 1 << (fraction + 1): - significand >>= 1 - unit += 1 - normal = unit + fraction - if normal > bias: - return -math.inf if negative else math.inf - bits = significand if significand < 1 << fraction else ( - (normal + bias) << fraction | (significand - (1 << fraction))) - return build(sign | bits) - - -def parse_java_float(text, single=False): - value = text.strip(_TRIM) - unsigned = value[1:] if value.startswith(('+', '-')) else value - if unsigned == 'NaN': - return math.nan - if unsigned == 'Infinity': - return -math.inf if value.startswith('-') else math.inf - hexadecimal = _HEX.fullmatch(value) is not None - if not hexadecimal and _DECIMAL.fullmatch(value) is None: - raise ValueError("Invalid Java floating value: '%s'" % text) - if value[-1:] in ('f', 'F', 'd', 'D'): - value = value[:-1] - negative = value.startswith('-') - value = value.lstrip('+-') - if hexadecimal: - mantissa, exponent = re.split('[pP]', value[2:]) - whole, _, fraction = mantissa.partition('.') - numerator = int(whole + fraction, 16) - exponent = _exponent(exponent) - 4 * len(fraction) - leading = numerator.bit_length() - 1 + exponent if numerator else 0 - bias, subnormal = (127, -150) if single else (1023, -1075) - if numerator and leading > bias: - return -math.inf if negative else math.inf - if not numerator or leading < subnormal: - return _ieee_ratio(0, 1, negative, single) - return _ieee_ratio(numerator << max(0, exponent), 1 << max(0, -exponent), negative, single) - parts = re.split('[eE]', value) - whole, _, fraction = parts[0].partition('.') - digits = (whole + fraction).lstrip('0') - exponent = (_exponent(parts[1]) if len(parts) == 2 else 0) - len(fraction) - adjusted = len(digits) - 1 + exponent - high, low = (38, -46) if single else (308, -324) - if not digits or adjusted < low: - return _ieee_ratio(0, 1, negative, single) - if adjusted > high: - return -math.inf if negative else math.inf - # Every IEEE midpoint has fewer than 800 significant decimal digits. - # Retain a sticky digit beyond that boundary instead of building unbounded - # decimal powers for a long input that is close to a rounding midpoint. - if len(digits) > 800: - remainder = digits[800:] - exponent += len(remainder) - digits = digits[:800] - if any(ch != '0' for ch in remainder): - digits += '1' - exponent -= 1 - numerator = int(digits) * 10 ** max(0, exponent) - denominator = 10 ** max(0, -exponent) - return _ieee_ratio(numerator, denominator, negative, single) diff --git a/paimon-python/pypaimon/casting/mask_output.py b/paimon-python/pypaimon/casting/mask_output.py deleted file mode 100644 index 238d94428a0f..000000000000 --- a/paimon-python/pypaimon/casting/mask_output.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Adapt Java mask row objects to their Arrow output representation without loss.""" - -import pyarrow as pa - - -def _integer_object(type_): - return type_ == pa.int32() or type_ == pa.date32() or type_ == pa.time32('ms') - - -def _text(type_): - return (pa.types.is_string(type_) or pa.types.is_large_string(type_) - or getattr(pa.types, 'is_string_view', lambda _: False)(type_)) - - -def _binary(type_): - return (pa.types.is_binary(type_) or pa.types.is_large_binary(type_) - or getattr(pa.types, 'is_binary_view', lambda _: False)(type_)) - - -def cast_mask_output(array, target): - """Decimal and Timestamp getters preserve objects, not declared precision. - - Arrow needs one fixed storage type. Loss of a fractional digit or overflow - is an error, including when the executor itself validly returned NULL. - """ - if array.null_count == len(array): - return pa.nulls(len(array), type=target) - source = array.type - if source == target: - return array - if (pa.types.is_decimal(source) and pa.types.is_decimal(target) - or pa.types.is_timestamp(source) and pa.types.is_timestamp(target)): - # Python Arrow safe casts reject decimal rounding, timestamp truncation - # and overflow; Rust checks the coefficients/ticks before using Arrow. - return array.cast(target, safe=True) - if _integer_object(source) and _integer_object(target): - return array.cast(pa.int32()).cast(target) - if _text(source) and _text(target) or _binary(source) and target == pa.binary(): - return array.cast(target) - raise ValueError('Mask result %s does not have the Java row class of output %s' % (source, target)) diff --git a/paimon-python/pypaimon/casting/numeric_cast.py b/paimon-python/pypaimon/casting/numeric_cast.py deleted file mode 100644 index 62e27fec58c0..000000000000 --- a/paimon-python/pypaimon/casting/numeric_cast.py +++ /dev/null @@ -1,152 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Existing Java numeric and Boolean CAST rules shared by readers and auth.""" - -import math -import re - -import pyarrow as pa - -from pypaimon.casting.decimal_cast import cast_decimal - - -def _narrow_integer(value, bits): - half = 1 << (bits - 1) - return (value + half) % (half * 2) - half - - -def _numeric_to_integer(array, target_type): - bits = target_type.bit_width - floating = pa.types.is_floating(array.type) - intermediate_bits = 64 if bits == 64 else 32 - lower = -(1 << (intermediate_bits - 1)) - upper = (1 << (intermediate_bits - 1)) - 1 - values = [] - for value in array.to_pylist(): - if value is None: - values.append(None) - continue - # Number.byteValue/shortValue first convert floats to int; Java's - # float-to-int/long conversion saturates before the final narrowing. - if floating: - # Java's floating-point narrowing maps NaN to zero. - if math.isnan(value): - value = 0 - else: - value = lower if value <= lower else upper if value >= upper else int(value) - else: - # BigDecimal.longValue truncates towards zero and retains low bits. - value = int(value) - values.append(_narrow_integer(value, bits)) - return pa.array(values, type=target_type) - - -def _parse_integer(text, bits): - if not text: - raise ValueError('Empty integer value') - negative = text[0] == '-' - index = int(text[0] in ('+', '-')) - if index == len(text): - raise ValueError('Invalid integer value: %s' % text) - limit = 1 << (bits - 1) - if not negative: - limit -= 1 - value = 0 - while index < len(text) and text[index] != '.': - digit = text[index] - if digit < '0' or digit > '9': - raise ValueError('Invalid integer value: %s' % text) - value = value * 10 + ord(digit) - ord('0') - if value > limit: - raise ValueError('Integer value overflow: %s' % text) - index += 1 - if index < len(text) and any(digit < '0' or digit > '9' for digit in text[index + 1:]): - raise ValueError('Invalid integer value: %s' % text) - return -value if negative else value - - -def _parse_boolean(text): - lowered = text.lower() - if lowered in ('t', 'true', 'y', 'yes', '1'): - return True - if lowered in ('f', 'false', 'n', 'no', '0'): - return False - raise ValueError("Cannot parse '%s' as BOOLEAN" % text) - - -def cast_numeric(array, target, target_paimon_type=None): - """Return None outside the existing numeric/Boolean CAST subset. - - Invalid text is an error, decimal precision overflow is NULL, and numeric - narrowing follows Number/BigDecimal conversion rather than Arrow storage. - The caller retains the original Java executor when rebinding field refs. - """ - source = array.type - text = pa.types.is_string(source) or pa.types.is_large_string(source) - integer = pa.types.is_signed_integer(source) - numeric = integer or pa.types.is_floating(source) or pa.types.is_decimal(source) - numeric_target = pa.types.is_signed_integer(target) or pa.types.is_floating(target) or pa.types.is_decimal(target) - if pa.types.is_boolean(target) and text: - return pa.array([None if value is None else _parse_boolean(value) for value in array.to_pylist()], - type=target) - if pa.types.is_boolean(target) and numeric: - if not integer: - raise ValueError('Java has no FLOAT/DOUBLE/DECIMAL to BOOLEAN cast') - return pa.array([None if value is None else value != 0 for value in array.to_pylist()], type=target) - if pa.types.is_signed_integer(target) and text: - return pa.array([None if value is None else _parse_integer(value, target.bit_width) - for value in array.to_pylist()], type=target) - if pa.types.is_decimal(source) and (pa.types.is_string(target) or pa.types.is_large_string(target)): - values = [None if value is None else format(value, 'f') for value in array.to_pylist()] - # Arrow carries no declared CHAR/VARCHAR length. Authorization callers - # apply widths themselves; old-file reads pass the logical target here. - width = re.fullmatch(r'(CHAR|VARCHAR)(?:\(\s*([0-9]+)\s*\))?(?:\s+(?:NOT\s+)?NULL)?', - str(target_paimon_type).strip().upper()) - if width is not None: - kind, length = width.group(1), int(width.group(2) or 1) - values = [None if value is None else (value[:length].ljust(length) if kind == 'CHAR' else value[:length]) - for value in values] - return pa.array(values, type=target) - if pa.types.is_decimal(target) and (numeric or text): - return cast_decimal(array, target) - if pa.types.is_boolean(source) and pa.types.is_decimal(target): - # PyPaimon does not support this pair; keep the existing capability - # boundary instead of introducing another Java CAST category here. - return None - if numeric_target and (numeric or pa.types.is_boolean(source)): - if pa.types.is_signed_integer(target) and numeric: - return _numeric_to_integer(array, target) - if pa.types.is_decimal(source): - # DecimalToNumericPrimitive first obtains a double, then casts to - # FLOAT if requested; direct decimal-to-float can double-round differently. - def decimal_double(value): - if value is None: - return None - if source.precision > 18: - return float(value) - digits = value.as_tuple() - unscaled = 0 - for digit in digits.digits: - unscaled = unscaled * 10 + digit - if digits.sign: - unscaled = -unscaled - return float(unscaled) / (10 ** source.scale) - - return pa.array([decimal_double(value) for value in array.to_pylist()], type=target) - return array.cast(target, safe=False) - return None diff --git a/paimon-python/pypaimon/casting/numeric_utils.py b/paimon-python/pypaimon/casting/numeric_utils.py index b2cbc6bf449f..a44ec07cfacd 100644 --- a/paimon-python/pypaimon/casting/numeric_utils.py +++ b/paimon-python/pypaimon/casting/numeric_utils.py @@ -22,24 +22,6 @@ from decimal import Decimal -# Java Character.digit scans UTF-16 chars, so supplementary digits do not -# participate. -_DECIMAL_ZEROES = ( - 0x0030, 0x0660, 0x06f0, 0x07c0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0be6, 0x0c66, - 0x0ce6, 0x0d66, 0x0de6, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x1090, 0x17e0, 0x1810, 0x1946, - 0x19d0, 0x1a80, 0x1a90, 0x1b50, 0x1bb0, 0x1c40, 0x1c50, 0xa620, 0xa8d0, 0xa900, 0xa9d0, - 0xa9f0, 0xaa50, 0xabf0, 0xff10, -) - - -def java_decimal_digit(character): - code = ord(character) - for zero in _DECIMAL_ZEROES: - if zero <= code < zero + 10: - return code - zero - return None - - def java_floating_string(value, single_precision=False) -> str: # Java's JDK 19+ contract selects a shortest round-tripping form with at # least two significant digits before applying its notation thresholds. @@ -83,30 +65,6 @@ def java_double_decimal_text(value): Use integer arithmetic over IEEE-754 components to preserve those choices. The emitted coefficient/exponent is numeric text, not a display format. """ - return _floating_decimal_text(value, False) - - -def java_number_string(value, single_precision=False): - """Java 8/11/17 Number.toString; FLOAT uses its own rounding interval.""" - if not math.isfinite(value) or value == 0: - return java_floating_string(value) - text = _floating_decimal_text(value, single_precision) - coefficient, exponent = text.split('e') - sign = '-' if coefficient.startswith('-') else '' - digits = coefficient.lstrip('-') - adjusted = int(exponent) + len(digits) - 1 - digits = digits.rstrip('0') - if adjusted < -3 or adjusted >= 7: - return sign + digits[0] + '.' + (digits[1:] or '0') + 'E' + str(adjusted) - point = adjusted + 1 - if point <= 0: - return sign + '0.' + '0' * (-point) + digits - if point >= len(digits): - return sign + digits + '0' * (point - len(digits)) + '.0' - return sign + digits[:point] + '.' + digits[point:] - - -def _floating_decimal_text(value, single_precision): if not math.isfinite(value): return java_floating_string(value) if value == 0: @@ -123,9 +81,6 @@ def _floating_decimal_text(value, single_precision): else: significant = 53 mantissa |= 1 << 52 - if single_precision: - bits = struct.unpack('>I', struct.pack('>f', value))[0] - significant = (bits & 0x007fffff).bit_length() if bits & 0x7f800000 == 0 else 24 trailing = (mantissa & -mantissa).bit_length() - 1 width = 53 - trailing tiny = max(0, width - exponent - 1) diff --git a/paimon-python/pypaimon/casting/schema_evolution.py b/paimon-python/pypaimon/casting/schema_evolution.py index 8b57e7988321..1116aeaacd51 100644 --- a/paimon-python/pypaimon/casting/schema_evolution.py +++ b/paimon-python/pypaimon/casting/schema_evolution.py @@ -17,14 +17,47 @@ """Java cast rules shared by old-file readers.""" +import math + import pyarrow as pa -from pypaimon.casting.numeric_cast import _narrow_integer, cast_numeric +from pypaimon.casting.decimal_cast import cast_decimal from pypaimon.casting.temporal_cast import cast_temporal from pypaimon.casting.temporal_string import temporal_to_string from pypaimon.table.row.generic_row import _parse_type_precision_scale +def _narrow_integer(value, bits): + half = 1 << (bits - 1) + return (value + half) % (half * 2) - half + + +def _numeric_to_integer(array, target_type): + bits = target_type.bit_width + floating = pa.types.is_floating(array.type) + intermediate_bits = 64 if bits == 64 else 32 + lower = -(1 << (intermediate_bits - 1)) + upper = (1 << (intermediate_bits - 1)) - 1 + values = [] + for value in array.to_pylist(): + if value is None: + values.append(None) + continue + # Number.byteValue/shortValue first convert floats to int; Java's + # float-to-int/long conversion saturates before the final narrowing. + if floating: + # Java's floating-point narrowing maps NaN to zero. + if math.isnan(value): + value = 0 + else: + value = lower if value <= lower else upper if value >= upper else int(value) + else: + # BigDecimal.longValue truncates towards zero and retains low bits. + value = int(value) + values.append(_narrow_integer(value, bits)) + return pa.array(values, type=target_type) + + def _truncate_timestamp(array, target_type, source_paimon_type, target_paimon_type): if (not pa.types.is_timestamp(array.type) or not pa.types.is_timestamp(target_type) or array.type.tz != target_type.tz @@ -105,18 +138,15 @@ def cast_array_for_schema_evolution(array, target_type, source_paimon_type=None, return timestamp if array.type == target_type: return array - if pa.types.is_signed_integer(array.type) and pa.types.is_decimal(target_type): - required = {8: 3, 16: 5, 32: 10, 64: 19}[array.type.bit_width] + target_type.scale - if target_type.precision < required: - # Preserve PyPaimon's existing ALTER TABLE capability boundary. - # Authorization CASTs separately use Java's per-value NULL overflow. - return array.cast(target_type, safe=False) - numeric = cast_numeric(array, target_type, target_paimon_type) - if numeric is not None: - return numeric + decimals = cast_decimal(array, target_type) + if decimals is not None: + return decimals if pa.types.is_timestamp(array.type) and target_type == pa.int64(): return _timestamp_to_bigint(array) if (array.type in (pa.int32(), pa.int64()) and pa.types.is_timestamp(target_type) and target_type.tz is None): return _integer_to_timestamp(array, target_type) + if (pa.types.is_signed_integer(target_type) + and (pa.types.is_floating(array.type) or pa.types.is_decimal(array.type))): + return _numeric_to_integer(array, target_type) return array.cast(target_type, safe=False) diff --git a/paimon-python/pypaimon/casting/temporal_cast.py b/paimon-python/pypaimon/casting/temporal_cast.py index c6f6d1b9fc2e..5700100446af 100644 --- a/paimon-python/pypaimon/casting/temporal_cast.py +++ b/paimon-python/pypaimon/casting/temporal_cast.py @@ -26,7 +26,7 @@ from pypaimon.table.row.generic_row import _parse_type_precision_scale -def cast_temporal(array, target, source_type=None, target_type=None, strict=False): +def cast_temporal(array, target, source_type=None, target_type=None): timestamp = pa.types.is_timestamp(array.type) source_name = str(source_type).upper() if source_type is not None else '' ltz = timestamp and (array.type.tz is not None if source_type is None else @@ -87,11 +87,6 @@ def cast_temporal(array, target, source_type=None, target_type=None, strict=Fals value = millis * 1000 + sub_milli // 1000 else: value = millis * 1000000 + sub_milli - if strict: - quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] - if (millis * 1000000 + sub_milli != value * quantum - or not -(1 << 63) <= value < (1 << 63)): - raise ValueError('Java timestamp result cannot be represented by the Arrow target') if not -(1 << 63) <= value < (1 << 63): value = None values.append(value) diff --git a/paimon-python/pypaimon/casting/temporal_string.py b/paimon-python/pypaimon/casting/temporal_string.py index 07643ec5c7e0..a47dba3a9ca4 100644 --- a/paimon-python/pypaimon/casting/temporal_string.py +++ b/paimon-python/pypaimon/casting/temporal_string.py @@ -19,7 +19,7 @@ import pyarrow as pa -from pypaimon.casting.temporal_utils import _epoch_day_to_date, _local_offset, _signed +from pypaimon.casting.temporal_utils import _epoch_day_to_date, _local_offset from pypaimon.table.row.generic_row import _parse_type_precision_scale @@ -118,30 +118,3 @@ def temporal_to_string(array, source_type=None, target_type=None): text = text.ljust(length) values.append(text) return pa.array(values, type=pa.string()) - - -def timestamp_object_to_string(array): - """Java Timestamp.toString: ISO wall time, regardless of the current LTZ zone.""" - values = [] - unit = array.type.unit - for value in array.cast(pa.int64()).to_pylist(): - if value is None: - values.append(None) - continue - millis = (_signed(value * 1000, 64) if unit == 's' else value if unit == 'ms' - else value // (1000 if unit == 'us' else 1000000)) - sub = value % (1000 if unit == 'us' else 1000000) * (1000 if unit == 'us' else 1) if unit in ('us', 'ns') else 0 - nanos = millis % 1000 * 1000000 + sub - day, second_of_day = divmod(millis // 1000, 86400) - year, month, day = _epoch_day_to_date(_signed(day, 32)) - year_text = ('%04d' % year if 0 <= year <= 9999 else '-%04d' % -year if year < 0 else '+%d' % year) - hour, second_of_day = divmod(second_of_day, 3600) - minute, second = divmod(second_of_day, 60) - text = '%s-%02d-%02dT%02d:%02d' % (year_text, month, day, hour, minute) - if second or nanos: - text += ':%02d' % second - if nanos: - precision = 3 if nanos % 1000000 == 0 else 6 if nanos % 1000 == 0 else 9 - text += '.' + ('%09d' % nanos)[:precision] - values.append(text) - return pa.array(values, type=pa.string()) diff --git a/paimon-python/pypaimon/casting/temporal_utils.py b/paimon-python/pypaimon/casting/temporal_utils.py index 8c60cdded0b2..7a923093d10d 100644 --- a/paimon-python/pypaimon/casting/temporal_utils.py +++ b/paimon-python/pypaimon/casting/temporal_utils.py @@ -68,7 +68,7 @@ def _rem(value, divisor): return value - _div(value, divisor) * divisor -def _java_date_parts(date): +def _java_date_to_epoch_day(date): j = _signed(date + 2440588 + 32044, 32) g, dg = _div(j, 146097), _rem(j, 146097) c = _div((_div(dg, 36524) + 1) * 3, 4) @@ -80,19 +80,10 @@ def _java_date_parts(date): m = _div(da * 5 + 308, 153) - 2 d = da - _div((m + 4) * 153, 5) + 122 year, month, day = y - 4800 + _div(m + 2, 12), _rem(m + 2, 12) + 1, d + 1 - return year, month, day - - -def _java_date_to_epoch_day(date): - year, month, day = _java_date_parts(date) leap = year % 400 == 0 or year % 4 == 0 and year % 100 != 0 days = 29 if month == 2 and leap else 28 if month == 2 else 30 if month in (4, 6, 9, 11) else 31 if not 1 <= month <= 12 or not 1 <= day <= days: raise ValueError('Invalid Java DATE conversion: {}-{}-{}'.format(year, month, day)) - return _ymd_to_epoch_day(year, month, day) - - -def _ymd_to_epoch_day(year, month, day): year -= month <= 2 era, yoe = divmod(year, 400) march = month + (-3 if month > 2 else 9) diff --git a/paimon-python/pypaimon/common/predicate_json_parser.py b/paimon-python/pypaimon/common/predicate_json_parser.py index 9fc06a652305..5ab57be62098 100644 --- a/paimon-python/pypaimon/common/predicate_json_parser.py +++ b/paimon-python/pypaimon/common/predicate_json_parser.py @@ -23,8 +23,6 @@ import pyarrow as pa import pyarrow.compute as pc -from pypaimon.casting.cast_executor import cast_array - # utf8_slice_codeunits needs an explicit integer stop on pyarrow 6 _MAX_STOP = 2 ** 31 - 1 @@ -156,7 +154,30 @@ def _apply_predicate_transform(transform: dict, batch: pa.RecordBatch, elif name == "CAST": col = batch.column(transform["fieldRef"]["name"]) - return cast_array(col, transform['fieldRef']['type'], transform['type']) + target = transform['type'] + width = re.fullmatch(r"\s*(CHAR|VARCHAR|BINARY|VARBINARY)(?=\s|\(|\Z)" + r"(?:\s*\(\s*([0-9]+)\s*\))?" + r"(?:\s*(?:NOT\s+)?NULL)?\s*", target, flags=re.IGNORECASE) + if width is not None: + kind, length = width.group(1).upper(), int(width.group(2) or 1) + if length < 1 or length > _INT_MAX: + raise ValueError('Cast width must be between 1 and 2147483647') + target_type = pa.string() if kind in ('CHAR', 'VARCHAR') else pa.binary() + else: + target_type = _paimon_type_to_arrow(target) + stored = _paimon_type_to_arrow(transform['fieldRef']['type']) + col = _cast_input_for_java_executor(col, stored, target_type) + result = pc.cast(col, target_type, safe=False) + # Java CastTransform enforces widths; Arrow uses unbounded arrays. + if width is not None: + pad = kind in ('CHAR', 'BINARY') + padding = ' ' if kind == 'CHAR' else b'\x00' + result = pa.array([ + None if value is None else + (value[:length] + padding * max(0, length - len(value)) if pad else value[:length]) + for value in result.to_pylist() + ], type=target_type) + return result elif name == "UPPER": input_col = _resolve_transform_input(transform["inputs"][0], batch) @@ -220,6 +241,43 @@ def _apply_predicate_transform(transform: dict, batch: pa.RecordBatch, raise ValueError(f"Unknown transform type: {name}") +def _cast_input_for_java_executor(col, stored, target): + # copyWithNewInputs retains Java's original executor. Character, Boolean + # and byte executors require their original runtime value class. + needs_class = (((pa.types.is_string(stored) or pa.types.is_large_string(stored)) and + not (pa.types.is_string(col.type) or pa.types.is_large_string(col.type))) or + (pa.types.is_boolean(stored) and not pa.types.is_boolean(col.type)) or + ((pa.types.is_binary(stored) or pa.types.is_large_binary(stored)) and + not (pa.types.is_binary(col.type) or pa.types.is_large_binary(col.type)))) + if needs_class: + if col.null_count != len(col): + raise ValueError('CAST source no longer has the runtime type its Java executor expects') + return pa.nulls(len(col), type=target) + + numeric = pa.types.is_integer(stored) or pa.types.is_floating(stored) or pa.types.is_decimal(stored) + if numeric and pa.types.is_string(target) and col.type != stored: + # NumericToString accepts Object. DATE and TIME getters return Integer, + # so this executor prints epoch days / milliseconds, not calendar text. + if pa.types.is_date(col.type): + return col.cast(pa.date32(), safe=False).cast(pa.int32()) + if pa.types.is_time(col.type): + return col.cast(pa.time32('ms'), safe=False).cast(pa.int32()) + if pa.types.is_decimal(col.type): + # Paimon Decimal.toString uses BigDecimal.toPlainString. Arrow may + # emit an exponent for a small scaled decimal, including zero. + return pa.array([None if value is None else format(value, 'f') for value in col.to_pylist()], + type=pa.string()) + if not (pa.types.is_integer(col.type) or pa.types.is_decimal(col.type) or + pa.types.is_boolean(col.type) or pa.types.is_string(col.type) or pa.types.is_large_string(col.type)): + # Timestamp.toString uses LocalDateTime text, and other objects + # have their own formatting. An Arrow cast would authorize other + # rows; refuse the unsupported rebound instead. + if col.null_count != len(col): + raise ValueError('CAST rebound source requires its original Java executor formatting') + return pa.nulls(len(col), type=target) + return col + + def _date_extract(name: str, field_ref: dict, batch: pa.RecordBatch) -> pa.Array: """Java calendar extraction on DATE days or Timestamp milliseconds. @@ -814,10 +872,9 @@ def _convert_literal(literal, target_type: pa.DataType): def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: type_str = paimon_type.strip().upper() - type_str = re.sub(r"(?<=\))\s*(?:NOT\s+)?NULL$|\s+(?:NOT\s+)?NULL$", "", type_str).strip() ltz_match = re.match( - r"^TIMESTAMP\s*\(([0-9]+)\)\s+WITH\s+LOCAL\s+TIME\s+ZONE$", type_str) + r"^TIMESTAMP\s*\((\d+)\)\s+WITH\s+LOCAL\s+TIME\s+ZONE", type_str) if ltz_match: precision = int(ltz_match.group(1)) return pa.timestamp(_timestamp_precision_to_unit(precision), tz="UTC") @@ -827,8 +884,6 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: raise ValueError(f"Cannot parse Paimon type: '{paimon_type}'") base_type = m.group(1).strip() params = m.group(2) - if params is not None and re.fullmatch(r"[0-9]+(?:\s*,\s*[0-9]+)?", params.strip()) is None: - raise ValueError("Invalid Java type parameters: %s" % paimon_type) simple_mapping = { "INT": pa.int32(), @@ -843,15 +898,13 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: "DATE": pa.date32(), } if base_type in simple_mapping: - if params is not None: - raise ValueError("Type does not take parameters: %s" % paimon_type) return simple_mapping[base_type] - if base_type in ("VARCHAR", "CHAR", "VARBINARY", "BINARY"): - length = int(params) if params is not None else 1 - if not 1 <= length <= (1 << 31) - 1: - raise ValueError("Cast width must be between 1 and 2147483647") - return pa.string() if base_type in ("VARCHAR", "CHAR") else pa.binary() + if base_type in ("VARCHAR", "CHAR"): + return pa.string() + + if base_type in ("VARBINARY", "BINARY"): + return pa.binary() if base_type == "TIMESTAMP": precision = int(params) if params else 6 @@ -864,17 +917,15 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: return pa.timestamp(unit, tz="UTC") if base_type == "TIME": - _timestamp_precision_to_unit(int(params) if params else 0) - return pa.time32("ms") + precision = int(params) if params else 6 + unit = _timestamp_precision_to_unit(precision) + return pa.time64(unit) if unit in ("us", "ns") else pa.time32(unit) if base_type == "DECIMAL": if params: parts = [x.strip() for x in params.split(",")] if len(parts) == 2: - precision, scale = int(parts[0]), int(parts[1]) - if not 1 <= precision <= 38 or not 0 <= scale <= precision: - raise ValueError("Invalid Java DECIMAL precision/scale: %s" % paimon_type) - return pa.decimal128(precision, scale) + return pa.decimal128(int(parts[0]), int(parts[1])) raise ValueError(f"DECIMAL type requires (precision, scale): '{paimon_type}'") raise ValueError( @@ -886,8 +937,6 @@ def _paimon_type_to_arrow(paimon_type: str) -> pa.DataType: def _timestamp_precision_to_unit(precision: int) -> str: - if not 0 <= precision <= 9: - raise ValueError("Timestamp precision must be between 0 and 9") if precision == 0: return "s" elif precision <= 3: diff --git a/paimon-python/pypaimon/read/reader/auth_masking_reader.py b/paimon-python/pypaimon/read/reader/auth_masking_reader.py index aee4878355f5..5c6873052afe 100644 --- a/paimon-python/pypaimon/read/reader/auth_masking_reader.py +++ b/paimon-python/pypaimon/read/reader/auth_masking_reader.py @@ -21,8 +21,6 @@ import pyarrow as pa -from pypaimon.casting.mask_output import cast_mask_output - from pypaimon.common.predicate_json_parser import ( _apply_predicate_transform, _collect_all_field_refs_from_transform, @@ -217,9 +215,8 @@ def apply_auth_masking(batch: pa.RecordBatch, parsed_rules: Dict[str, dict]): if col_name in original_batch.schema.names: col_idx = original_batch.schema.get_field_index(col_name) target_col_type = original_batch.schema.field(col_idx).type - masked_columns[col_idx] = cast_mask_output( - _apply_predicate_transform(transform, original_batch, null_type=target_col_type), - target_col_type) + masked_columns[col_idx] = _apply_predicate_transform( + transform, original_batch, null_type=target_col_type) for col_idx, masked_array in masked_columns.items(): original_field = original_batch.schema.field(col_idx) batch = batch.set_column( diff --git a/paimon-python/pypaimon/tests/auth_masking_reader_test.py b/paimon-python/pypaimon/tests/auth_masking_reader_test.py index 89ae9cb2ea83..66b837cb9712 100644 --- a/paimon-python/pypaimon/tests/auth_masking_reader_test.py +++ b/paimon-python/pypaimon/tests/auth_masking_reader_test.py @@ -125,24 +125,43 @@ def test_cast_transform(self): self.assertEqual(result.column("age").type, pa.int64()) self.assertEqual(result.column("age").to_pylist(), [25, 30, 35]) - def test_cast_mask_rejects_a_different_java_output_class(self): - batch = pa.RecordBatch.from_pydict({"id": pa.array([1, 2], type=pa.int32())}) - for target in ("BIGINT", "STRING"): - with self.subTest(target=target), self.assertRaises(ValueError): - self._apply_masking({"id": json.dumps({ - "name": "CAST", "fieldRef": {"name": "id", "type": "INT"}, "type": target, - })}, batch=batch, fields=[_FakeField("id")]) - - def test_cast_masks_preserve_the_target_columns_java_class(self): - for target, arrow_type, expected in [("BIGINT", pa.int64(), [1, 2]), ("STRING", pa.string(), ["1", "2"])]: - batch = pa.RecordBatch.from_arrays([ - pa.array([1, 2], type=pa.int32()), pa.nulls(2, type=arrow_type), - ], names=["id", "masked"]) - result = self._apply_masking({"masked": json.dumps({ - "name": "CAST", "fieldRef": {"name": "id", "type": "INT"}, "type": target, - })}, batch=batch, fields=[_FakeField("id"), _FakeField("masked")]) - self.assertEqual(result.column("masked").type, arrow_type) - self.assertEqual(result.column("masked").to_pylist(), expected) + def test_cast_transform_changes_column_type(self): + """CAST transform changes the output column type (matching Java behavior).""" + batch = pa.RecordBatch.from_pydict( + {"id": pa.array([1, 2, 3], type=pa.int32())}, + schema=pa.schema([("id", pa.int32())]), + ) + fields = [_FakeField("id")] + result = self._apply_masking( + {"id": json.dumps({ + "name": "CAST", + "fieldRef": {"index": 0, "name": "id", "type": "INT"}, + "type": "BIGINT", + })}, + batch=batch, + fields=fields, + ) + self.assertEqual(result.column("id").type, pa.int64()) + self.assertEqual(result.column("id").to_pylist(), [1, 2, 3]) + + def test_cast_transform_int_to_string(self): + """CAST INT to STRING changes column type to string (matching Java).""" + batch = pa.RecordBatch.from_pydict( + {"id": pa.array([100, 200], type=pa.int32())}, + schema=pa.schema([("id", pa.int32())]), + ) + fields = [_FakeField("id")] + result = self._apply_masking( + {"id": json.dumps({ + "name": "CAST", + "fieldRef": {"index": 0, "name": "id", "type": "INT"}, + "type": "STRING", + })}, + batch=batch, + fields=fields, + ) + self.assertEqual(result.column("id").type, pa.string()) + self.assertEqual(result.column("id").to_pylist(), ["100", "200"]) def test_concat_transform(self): result = self._apply_masking({ diff --git a/paimon-python/pypaimon/tests/authorization_cast_completion_test.py b/paimon-python/pypaimon/tests/authorization_cast_completion_test.py deleted file mode 100644 index 8c10120f9355..000000000000 --- a/paimon-python/pypaimon/tests/authorization_cast_completion_test.py +++ /dev/null @@ -1,2725 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Java scalar CAST completion vectors, in three system time zones.""" - -import json -import math -import time -from decimal import Decimal - -import pyarrow as pa -import pytest - -from pypaimon.common.predicate_json_parser import _apply_predicate_transform, _paimon_type_to_arrow - -# Actual Java CastExecutors/PredicateRemapper output on Paimon master 8de6fdbda9. -# JDK 17 and JDK 8 numeric formatting; no NaN or signed-zero vectors. -JAVA_CASES = [ - json.loads( - '{"name":"lexical STRING -> FLOAT","fields":[{"name":"v","type":"STRING"}],"rows":[["1.25"],["+' - '1.25"],[" 1.25 "],["\\t1.25\\n"],["1e3"],["1.25f"],["1.25D"],["0x1.8p2"],["0X1.8P+2f"],["1e-7"],' - '["1e400"],["\\uff11.\\uff12\\uff15"],["1_000"],["1.25junk"],[""],["bad"],[null]],"transform":{"na' - 'me":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"FLOAT"},"expected":{"UTC' - '":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"Nu' - 'mberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' - 'ror":"NumberFormatException"},{"error":"NumberFormatException"},null],"Asia/Shanghai":[1.25,1.' - '25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"NumberFormat' - 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"Numb' - 'erFormatException"},{"error":"NumberFormatException"},null],"America/New_York":[1.25,1.25,1.25' - ',1.25,1000.0,1.25,1.25,6.0,6.0,1.0000000116860974e-07,"Infinity",{"error":"NumberFormatExcepti' - 'on"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberForma' - 'tException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"lexical STRING -> DOUBLE","fields":[{"name":"v","type":"STRING"}],"rows":[["1.25"],["' - '+1.25"],[" 1.25 "],["\\t1.25\\n"],["1e3"],["1.25f"],["1.25D"],["0x1.8p2"],["0X1.8P+2f"],["1e-7"]' - ',["1e400"],["\\uff11.\\uff12\\uff15"],["1_000"],["1.25junk"],[""],["bad"],[null]],"transform":{"n' - 'ame":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"DOUBLE"},"expected":{"U' - 'TC":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1e-07,"Infinity",{"error":"NumberFormatExcep' - 'tion"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFor' - 'matException"},{"error":"NumberFormatException"},null],"Asia/Shanghai":[1.25,1.25,1.25,1.25,10' - '00.0,1.25,1.25,6.0,6.0,1e-07,"Infinity",{"error":"NumberFormatException"},{"error":"NumberForm' - 'atException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"Nu' - 'mberFormatException"},null],"America/New_York":[1.25,1.25,1.25,1.25,1000.0,1.25,1.25,6.0,6.0,1' - 'e-07,"Infinity",{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"' - 'NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},nu' - 'll]}}' - ), - json.loads( - '{"name":"format FLOAT -> STRING","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.25],[' - '0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.4028234663852886e+3' - '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"type"' - ':"STRING"},"expected":{"UTC":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","1.0E23"' - ',"1.6777216E7","0.1","3.4028235E38",null],"Asia/Shanghai":["1.0","1.25","0.001","1.0E-4","1.0E' - '-7","1.0E7","1.0E20","1.0E23","1.6777216E7","0.1","3.4028235E38",null],"America/New_York":["1.' - '0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","1.0E23","1.6777216E7","0.1","3.4028235E3' - '8",null]}}' - ), - json.loads( - '{"name":"format DOUBLE -> STRING","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1.25]' - ',[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.797693134' - '8623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DOU' - 'BLE"},"type":"STRING"},"expected":{"UTC":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E' - '20","9.999999999999999E22","9.007199254740992E15","0.1","1.7976931348623157E308",null],"Asia/S' - 'hanghai":["1.0","1.25","0.001","1.0E-4","1.0E-7","1.0E7","1.0E20","9.999999999999999E22","9.00' - '7199254740992E15","0.1","1.7976931348623157E308",null],"America/New_York":["1.0","1.25","0.001' - '","1.0E-4","1.0E-7","1.0E7","1.0E20","9.999999999999999E22","9.007199254740992E15","0.1","1.79' - '76931348623157E308",null]}}' - ), - json.loads( - '{"name":"format FLOAT -> CHAR(3)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.25],' - '[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.4028234663852886e+' - '38],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"type' - '":"CHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3' - '.4",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.4",n' - 'ull],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.4",nul' - 'l]}}' - ), - json.loads( - '{"name":"format DOUBLE -> CHAR(3)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1.25' - '],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.79769313' - '48623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DO' - 'UBLE"},"type":"CHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9' - '.0","0.1","1.7",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.0","' - '0.1","1.7",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.0","0.' - '1","1.7",null]}}' - ), - json.loads( - '{"name":"format FLOAT -> VARCHAR(3)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.0],[1.2' - '5],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[16777216.0],[0.1],[3.402823466385288' - '6e+38],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"FLOAT"},"t' - 'ype":"VARCHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0' - '.1","3.4",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","' - '3.4",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","1.0","1.6","0.1","3.' - '4",null]}}' - ), - json.loads( - '{"name":"format DOUBLE -> VARCHAR(3)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.0],[1' - '.25],[0.001],[0.0001],[1e-07],[10000000.0],[1e+20],[1e+23],[9007199254740992.0],[0.1],[1.79769' - '31348623157e+308],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":' - '"DOUBLE"},"type":"VARCHAR(3)"},"expected":{"UTC":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9' - '.9","9.0","0.1","1.7",null],"Asia/Shanghai":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","' - '9.0","0.1","1.7",null],"America/New_York":["1.0","1.2","0.0","1.0","1.0","1.0","1.0","9.9","9.' - '0","0.1","1.7",null]}}' - ), - json.loads( - '{"name":"bytes-width BINARY(8) -> STRING","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[[' - '[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[' - '195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIN' - 'ARY(8)"},"type":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd' - '\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\uff' - 'fd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b",' - '"\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width BINARY(8) -> CHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[' - '[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[' - '[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BI' - 'NARY(8)"},"type":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\uff' - 'fd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\u' - 'fffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b' - '","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width BINARY(8) -> VARCHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows' - '":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]' - '],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":' - '"BINARY(8)"},"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd"' - ',"\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufff' - 'd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9' - '\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width VARBINARY(32) -> STRING","fields":[{"name":"v","type":"VARBINARY(32)"}],"' - 'rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,' - '128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","ty' - 'pe":"VARBINARY(32)"},"type":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\uf' - 'ffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\' - 'ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u' - '00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width VARBINARY(32) -> CHAR(3)","fields":[{"name":"v","type":"VARBINARY(32)"}],' - '"rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128' - ',128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","t' - 'ype":"VARBINARY(32)"},"type":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\' - 'ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b",' - '"\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","' - '\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width VARBINARY(32) -> VARCHAR(3)","fields":[{"name":"v","type":"VARBINARY(32)"' - '}],"rows":[[[97,98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,' - '128,128]],[[195,40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v"' - ',"type":"VARBINARY(32)"},"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\uff' - 'fd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u' - '732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abc' - 'def","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width BYTES -> STRING","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,98,9' - '9,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,40]]' - ',[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"},"ty' - 'pe":"STRING"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\ufffd' - '\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\' - 'ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\ufffd","\\u' - 'fffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width BYTES -> CHAR(3)","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,98,' - '99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,40]' - '],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"},"t' - 'ype":"CHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\ufffd\\uff' - 'fd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufff' - 'd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\ufffd","' - '\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"bytes-width BYTES -> VARCHAR(3)","fields":[{"name":"v","type":"BYTES"}],"rows":[[[97,' - '98,99,100,101,102]],[[195,169,231,140,171]],[[255]],[[237,160,128]],[[240,128,128,128]],[[195,' - '40]],[[]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BYTES"}' - ',"type":"VARCHAR(3)"},"expected":{"UTC":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd","\\ufffd\\uff' - 'fd\\ufffd\\ufffd","\\ufffd(","",null],"Asia/Shanghai":["abcdef","\\u00e9\\u732b","\\ufffd","\\ufffd",' - '"\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null],"America/New_York":["abcdef","\\u00e9\\u732b","\\uf' - 'ffd","\\ufffd","\\ufffd\\ufffd\\ufffd\\ufffd","\\ufffd(","",null]}}' - ), - json.loads( - '{"name":"text-time STRING -> DATE","fields":[{"name":"v","type":"STRING"}],"rows":[["1970-01-0' - '2"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 03:04:05.' - '006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-29"],["20' - '01-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1"],["-1"' - '],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST","field' - 'Ref":{"index":99,"name":"v","type":"STRING"},"type":"DATE"},"expected":{"UTC":[1,1,{"error":"D' - 'ateTimeException"},1,1,-1,11016,{"error":"DateTimeException"},{"error":"DateTimeException"},1,' - '1,1970,31,0,1,-1,1001,-1001,{"error":"NumberFormatException"},{"error":"DateTimeException"},nu' - 'll],"Asia/Shanghai":[1,1,{"error":"DateTimeException"},1,1,-1,11016,{"error":"DateTimeExceptio' - 'n"},{"error":"DateTimeException"},1,1,1970,31,0,1,-1,1001,-1001,{"error":"NumberFormatExceptio' - 'n"},{"error":"DateTimeException"},null],"America/New_York":[1,1,{"error":"DateTimeException"},' - '1,1,-1,11016,{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1970,31,0,1,-1,10' - '01,-1001,{"error":"NumberFormatException"},{"error":"DateTimeException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(0)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(0)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1000,"nanos":0},' - '{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExc' - 'eption"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970000,"n' - 'anos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{' - '"millis":-1000,"nanos":0},{"millis":1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis"' - ':-1000,"nanos":0},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":86400000' - ',"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimePars' - 'eException"},{"error":"DateTimeParseException"},{"millis":-1000,"nanos":0},{"millis":951782400' - '000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":' - '86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970000,"nanos":0},{"error":"' - 'DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":-1000,"nan' - 'os":0},{"millis":1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{' - '"error":"DateTimeParseException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"mi' - 'llis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"e' - 'rror":"DateTimeParseException"},{"millis":-1000,"nanos":0},{"millis":951782400000,"nanos":0},{' - '"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos"' - ':0},{"error":"DateTimeParseException"},{"millis":1970000,"nanos":0},{"error":"DateTimeParseExc' - 'eption"},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis"' - ':1001000,"nanos":0},{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"error":"DateTim' - 'eParseException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(1)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(1)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{' - '"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExce' - 'ption"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeExce' - 'ption"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeExcep' - 'tion"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},' - '{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"milli' - 's":86400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"error":"D' - 'ateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{"millis"' - ':951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},' - '{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},' - '{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{' - '"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error"' - ':"RuntimeException"},{"error":"DateTimeParseException"},null],"America/New_York":[{"millis":86' - '400000,"nanos":0},{"millis":97445100,"nanos":0},{"millis":97445100,"nanos":0},{"error":"DateTi' - 'meParseException"},{"error":"DateTimeParseException"},{"millis":-100,"nanos":0},{"millis":9517' - '82400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"mil' - 'lis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"err' - 'or":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"erro' - 'r":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Run' - 'timeException"},{"error":"DateTimeParseException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(2)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(2)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"' - 'millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExcep' - 'tion"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeExcep' - 'tion"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeExcept' - 'ion"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{' - '"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis' - '":86400000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"error":"Da' - 'teTimeParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"millis":9' - '51782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"' - 'millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"' - 'error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"e' - 'rror":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"' - 'RuntimeException"},{"error":"DateTimeParseException"},null],"America/New_York":[{"millis":8640' - '0000,"nanos":0},{"millis":97445120,"nanos":0},{"millis":97445120,"nanos":0},{"error":"DateTime' - 'ParseException"},{"error":"DateTimeParseException"},{"millis":-10,"nanos":0},{"millis":9517824' - '00000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' - '":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error"' - ':"DateTimeParseException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":' - '"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Runtim' - 'eException"},{"error":"DateTimeParseException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":0},{"millis":97445123,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"m' - 'illis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseExcept' - 'ion"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970,"nanos":' - '0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":' - '-1,"nanos":0},{"millis":1001,"nanos":0},{"millis":-1001,"nanos":0},{"millis":92233720368547758' - '07,"nanos":0},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":86400000,"na' - 'nos":0},{"millis":97445123,"nanos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseExc' - 'eption"},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"na' - 'nos":0},{"millis":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":8640000' - '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":1970,"nanos":0},{"error":"DateTimePa' - 'rseException"},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":-1,"nanos":0},{"millis"' - ':1001,"nanos":0},{"millis":-1001,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"error":' - '"DateTimeParseException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"millis":97' - '445123,"nanos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' - 'ateTimeParseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"nanos":0},{"millis":98' - '3318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error' - '":"DateTimeParseException"},{"millis":1970,"nanos":0},{"error":"DateTimeParseException"},{"mil' - 'lis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":-1,"nanos":0},{"millis":1001,"nanos":0},{"m' - 'illis":-1001,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"error":"DateTimeParseExcept' - 'ion"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(4)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(4)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445123,"nanos":4' - '00000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' - 'os":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"error"' - ':"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"error":' - '"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"Runtim' - 'eException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Asia/Shang' - 'hai":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445123,"nan' - 'os":400000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1' - ',"nanos":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":' - '"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"e' - 'rror":"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeException"},{"er' - 'ror":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"R' - 'untimeException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null],"Ameri' - 'ca/New_York":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":400000},{"millis":97445' - '123,"nanos":400000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mi' - 'llis":-1,"nanos":900000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{' - '"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseExcepti' - 'on"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},{"error":"RuntimeExceptio' - 'n"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"e' - 'rror":"RuntimeException"},{"error":"RuntimeException"},{"error":"DateTimeParseException"},null' - ']}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":97445123,"nanos":4' - '56000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' - 'os":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' - '":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nan' - 'os":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"nanos":999000},' - '{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},null],"Asia/Shan' - 'ghai":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":97445123,"na' - 'nos":456000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-' - '1,"nanos":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error"' - ':"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"' - 'millis":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":' - '0,"nanos":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"nanos":99' - '9000},{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},null],"Ame' - 'rica/New_York":[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456000},{"millis":974' - '45123,"nanos":456000},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"' - 'millis":-1,"nanos":999000},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0}' - ',{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseExcep' - 'tion"},{"millis":1,"nanos":970000},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{' - '"millis":0,"nanos":1000},{"millis":-1,"nanos":999000},{"millis":1,"nanos":1000},{"millis":-2,"' - 'nanos":999000},{"millis":9223372036854775,"nanos":807000},{"error":"DateTimeParseException"},n' - 'ull]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(9)","fields":[{"name":"v","type":"STRING"}],"rows":[["1' - '970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.123456789"],["1970-01-02 0' - '3:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.999999999"],["2000-02-2' - '9"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],["1970-02"],["0"],["1' - '"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"transform":{"name":"CAST' - '","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(9)"},"expected":{"UTC":' - '[{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":4' - '56789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nan' - 'os":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis' - '":0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos' - '":1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"mil' - 'lis":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{' - '"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":456' - '789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nanos' - '":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateTi' - 'meParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":' - '0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos":' - '1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"milli' - 's":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null],"America/New_York":[' - '{"millis":86400000,"nanos":0},{"millis":97445123,"nanos":456789},{"millis":97445123,"nanos":45' - '6789},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-1,"nano' - 's":999999},{"millis":951782400000,"nanos":0},{"millis":983318400000,"nanos":0},{"error":"DateT' - 'imeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis"' - ':0,"nanos":1970},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":0,"nanos"' - ':1},{"millis":-1,"nanos":999999},{"millis":0,"nanos":1001},{"millis":-1,"nanos":998999},{"mill' - 'is":9223372036854,"nanos":775807},{"error":"DateTimeParseException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"' - 'STRING"}],"rows":[["1970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.12345' - '6789"],["1970-01-02 03:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.99' - '9999999"],["2000-02-29"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],' - '["1970-02"],["0"],["1"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"tra' - 'nsform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)' - ' WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":97445123,"n' - 'anos":0},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimePa' - 'rseException"},{"millis":-1,"nanos":0},{"millis":951782400000,"nanos":0},{"millis":98331840000' - '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{"error":"DateTi' - 'meParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"err' - 'or":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcept' - 'ion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTime' - 'ParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000,' - '"nanos":0},{"millis":68645123,"nanos":0},{"millis":68645123,"nanos":0},{"error":"DateTimeParse' - 'Exception"},{"error":"DateTimeParseException"},{"millis":-28800001,"nanos":0},{"millis":951753' - '600000,"nanos":0},{"millis":983289600000,"nanos":0},{"error":"DateTimeParseException"},{"milli' - 's":57600000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{' - '"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' - 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' - 'TimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nul' - 'l],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":115445123,"nanos":0},{"millis"' - ':115445123,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"' - 'millis":17999999,"nanos":0},{"millis":951800400000,"nanos":0},{"millis":983336400000,"nanos":0' - '},{"error":"DateTimeParseException"},{"millis":104400000,"nanos":0},{"error":"DateTimeParseExc' - 'eption"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateT' - 'imeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"er' - 'ror":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcep' - 'tion"},{"error":"DateTimeParseException"},null]}}' - ), - json.loads( - '{"name":"text-time STRING -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"' - 'STRING"}],"rows":[["1970-01-02"],["1970-01-02 03:04:05.123456789"],["1970-01-02T03:04:05.12345' - '6789"],["1970-01-02 03:04:05.006+00:00"],["1970-01-02 03:04:05.006Z"],["1969-12-31 23:59:59.99' - '9999999"],["2000-02-29"],["2001-02-29"],["2024-13-01"],["1970-1-2"],[" 1970-01-02 "],["1970"],' - '["1970-02"],["0"],["1"],["-1"],["1001"],["-1001"],["9223372036854775807"],["bad"],[null]],"tra' - 'nsform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)' - ' WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":97445123,"n' - 'anos":456000},{"millis":97445123,"nanos":456000},{"error":"DateTimeParseException"},{"error":"' - 'DateTimeParseException"},{"millis":-1,"nanos":999000},{"millis":951782400000,"nanos":0},{"mill' - 'is":983318400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":86400000,"nanos":0},{' - '"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' - 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' - 'TimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"e' - 'rror":"DateTimeParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"mi' - 'llis":57600000,"nanos":0},{"millis":68645123,"nanos":456000},{"millis":68645123,"nanos":456000' - '},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-28800001,"n' - 'anos":999000},{"millis":951753600000,"nanos":0},{"millis":983289600000,"nanos":0},{"error":"Da' - 'teTimeParseException"},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"erro' - 'r":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcepti' - 'on"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeP' - 'arseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error"' - ':"DateTimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":' - '115445123,"nanos":456000},{"millis":115445123,"nanos":456000},{"error":"DateTimeParseException' - '"},{"error":"DateTimeParseException"},{"millis":17999999,"nanos":999000},{"millis":95180040000' - '0,"nanos":0},{"millis":983336400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":10' - '4400000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"err' - 'or":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseExcept' - 'ion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTime' - 'ParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},null]}}' - ), - json.loads( - '{"name":"date DATE -> STRING","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1],[0]' - ',[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"index"' - ':99,"name":"v","type":"DATE"},"type":"STRING"},"expected":{"UTC":["0000-01-01","1969-12-31","1' - '970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(",")*,0-0+-0)",null],"Asia/Shanghai":["0000-01' - '-01","1969-12-31","1970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(",")*,0-0+-0)",null],"Amer' - 'ica/New_York":["0000-01-01","1969-12-31","1970-01-01","1970-01-02","2000-02-29",")*,0-0+-0(","' - ')*,0-0+-0)",null]}}' - ), - json.loads( - '{"name":"date DATE -> CHAR(5)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1],[0' - '],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"index' - '":99,"name":"v","type":"DATE"},"type":"CHAR(5)"},"expected":{"UTC":["0000-","1969-","1970-","1' - '970-","2000-",")*,0-",")*,0-",null],"Asia/Shanghai":["0000-","1969-","1970-","1970-","2000-","' - ')*,0-",")*,0-",null],"America/New_York":["0000-","1969-","1970-","1970-","2000-",")*,0-",")*,0' - '-",null]}}' - ), - json.loads( - '{"name":"date DATE -> VARCHAR(5)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-1]' - ',[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"in' - 'dex":99,"name":"v","type":"DATE"},"type":"VARCHAR(5)"},"expected":{"UTC":["0000-","1969-","197' - '0-","1970-","2000-",")*,0-",")*,0-",null],"Asia/Shanghai":["0000-","1969-","1970-","1970-","20' - '00-",")*,0-",")*,0-",null],"America/New_York":["0000-","1969-","1970-","1970-","2000-",")*,0-"' - ',")*,0-",null]}}' - ), - json.loads( - '{"name":"date DATE -> TIMESTAMP(3)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-' - '1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"' - 'index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-62167' - '219200000,"nanos":0},{"millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,' - '"nanos":0},{"millis":951782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis"' - ':-185542587187200000,"nanos":0},null],"Asia/Shanghai":[{"millis":-62167219200000,"nanos":0},{"' - 'millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":95' - '1782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"n' - 'anos":0},null],"America/New_York":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"n' - 'anos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0' - '},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"date DATE -> TIMESTAMP(6)","fields":[{"name":"v","type":"DATE"}],"rows":[[-719528],[-' - '1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name":"CAST","fieldRef":{"' - 'index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-62167' - '219200000,"nanos":0},{"millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,' - '"nanos":0},{"millis":951782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis"' - ':-185542587187200000,"nanos":0},null],"Asia/Shanghai":[{"millis":-62167219200000,"nanos":0},{"' - 'millis":-86400000,"nanos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":95' - '1782400000,"nanos":0},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"n' - 'anos":0},null],"America/New_York":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"n' - 'anos":0},{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0' - '},{"millis":185542587100800000,"nanos":0},{"millis":-185542587187200000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"date DATE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"DATE"}]' - ',"rows":[[-719528],[-1],[0],[1],[11016],[2147483647],[-2147483648],[null]],"transform":{"name"' - ':"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type":"TIMESTAMP(3) WITH LOCAL TIME ' - 'ZONE"},"expected":{"UTC":[{"millis":-62167219200000,"nanos":0},{"millis":-86400000,"nanos":0},' - '{"millis":0,"nanos":0},{"millis":86400000,"nanos":0},{"millis":951782400000,"nanos":0},{"error' - '":"DateTimeException"},{"error":"DateTimeException"},null],"Asia/Shanghai":[{"millis":-6216724' - '8343000,"nanos":0},{"millis":-115200000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":57' - '600000,"nanos":0},{"millis":951753600000,"nanos":0},{"error":"DateTimeException"},{"error":"Da' - 'teTimeException"},null],"America/New_York":[{"millis":-62167201438000,"nanos":0},{"millis":-68' - '400000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":104400000,"nanos":0},{"millis":95180' - '0400000,"nanos":0},{"error":"DateTimeException"},{"error":"DateTimeException"},null]}}' - ), - json.loads( - '{"name":"time-text TIME(0) -> STRING","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0],[10' - '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' - '"index":99,"name":"v","type":"TIME(0)"},"type":"STRING"},"expected":{"UTC":["00:00:00","00:00:' - '00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"Asia/Shanghai":["00:00:00","' - '00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"America/New_York":["00' - ':00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null]}}' - ), - json.loads( - '{"name":"time-text TIME(0) -> CHAR(12)","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0],[' - '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIME(0)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00 "' - ',"00:00:00 ","00:00:00 ","03:04:05 ","23:59:59 ","23:59:59 ","24:00:00 ",nul' - 'l],"Asia/Shanghai":["00:00:00 ","00:00:00 ","00:00:00 ","03:04:05 ","23:59:59 "' - ',"23:59:59 ","24:00:00 ",null],"America/New_York":["00:00:00 ","00:00:00 ","00:00:' - '00 ","03:04:05 ","23:59:59 ","23:59:59 ","24:00:00 ",null]}}' - ), - json.loads( - '{"name":"time-text TIME(0) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(0)"}],"rows":[[0' - '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"TIME(0)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' - '0","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"Asia/Shanghai":["0' - '0:00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null],"America/New_' - 'York":["00:00:00","00:00:00","00:00:00","03:04:05","23:59:59","23:59:59","24:00:00",null]}}' - ), - json.loads( - '{"name":"time-text TIME(1) -> STRING","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0],[10' - '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' - '"index":99,"name":"v","type":"TIME(1)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' - '0:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",null],"Asia/Shanghai"' - ':["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",n' - 'ull],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:' - '59:59.9","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"time-text TIME(1) -> CHAR(12)","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0],[' - '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIME(1)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' - ',"00:00:00.1 ","00:00:00.1 ","03:04:05.0 ","23:59:59.9 ","23:59:59.9 ","24:00:00.0 ",nul' - 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.1 ","03:04:05.0 ","23:59:59.9 "' - ',"23:59:59.9 ","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' - '00.1 ","03:04:05.0 ","23:59:59.9 ","23:59:59.9 ","24:00:00.0 ",null]}}' - ), - json.loads( - '{"name":"time-text TIME(1) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(1)"}],"rows":[[0' - '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"TIME(1)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' - '0.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:00:00.0",null],"Asia' - '/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:59.9","23:59:59.9","24:' - '00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.1","03:04:05.0","23:59:' - '59.9","23:59:59.9","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"time-text TIME(3) -> STRING","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[10' - '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' - '"index":99,"name":"v","type":"TIME(3)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' - '0:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null],"Asia/S' - 'hanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999' - '","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.00' - '6","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"time-text TIME(3) -> CHAR(12)","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[' - '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIME(3)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' - ',"00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",nul' - 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999"' - ',"23:59:59.999","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' - '00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",null]}}' - ), - json.loads( - '{"name":"time-text TIME(3) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0' - '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"TIME(3)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' - '0.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",nul' - 'l],"Asia/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23' - ':59:59.999","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","0' - '3:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"time-text TIME(6) -> STRING","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0],[10' - '0],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef":{' - '"index":99,"name":"v","type":"TIME(6)"},"type":"STRING"},"expected":{"UTC":["00:00:00.0","00:0' - '0:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null],"Asia/S' - 'hanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999' - '","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.00' - '6","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"time-text TIME(6) -> CHAR(12)","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0],[' - '100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIME(6)"},"type":"CHAR(12)"},"expected":{"UTC":["00:00:00.0 "' - ',"00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",nul' - 'l],"Asia/Shanghai":["00:00:00.0 ","00:00:00.1 ","00:00:00.101","03:04:05.006","23:59:59.999"' - ',"23:59:59.999","24:00:00.0 ",null],"America/New_York":["00:00:00.0 ","00:00:00.1 ","00:00:' - '00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0 ",null]}}' - ), - json.loads( - '{"name":"time-text TIME(6) -> VARCHAR(12)","fields":[{"name":"v","type":"TIME(6)"}],"rows":[[0' - '],[100],[101],[11045006],[86399999],[-1],[86400000],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"TIME(6)"},"type":"VARCHAR(12)"},"expected":{"UTC":["00:00:0' - '0.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",nul' - 'l],"Asia/Shanghai":["00:00:00.0","00:00:00.1","00:00:00.101","03:04:05.006","23:59:59.999","23' - ':59:59.999","24:00:00.0",null],"America/New_York":["00:00:00.0","00:00:00.1","00:00:00.101","0' - '3:04:05.006","23:59:59.999","23:59:59.999","24:00:00.0",null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(0)","fields":[{"name":"v","type":"BIGINT"}],"rows":' - '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(0)"},"e' - 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' - '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' - 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' - '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' - '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' - '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(3)","fields":[{"name":"v","type":"BIGINT"}],"rows":' - '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(3)"},"e' - 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' - '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' - 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' - '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' - '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' - '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(6)","fields":[{"name":"v","type":"BIGINT"}],"rows":' - '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(6)"},"e' - 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' - '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' - 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' - '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' - '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' - '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(9)","fields":[{"name":"v","type":"BIGINT"}],"rows":' - '[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-9223372036854775808],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type":"TIMESTAMP(9)"},"e' - 'xpected":{"UTC":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":' - '0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' - 'is":0,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001000,"nanos":0},{"millis":-1000,"nanos":' - '0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"nanos":0},{"millis":' - '-1000,"nanos":0},{"millis":0,"nanos":0},null],"America/New_York":[{"millis":-1001000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":123456' - '7000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","typ' - 'e":"BIGINT"}],"rows":[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-92233720368547758' - '08],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' - 'e":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001000,"nanos":0},{"mil' - 'lis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"n' - 'anos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null],"Asia/Shanghai":[{"millis":27' - '799000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":288010' - '00,"nanos":0},{"millis":1263367000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000' - ',"nanos":0},null],"America/New_York":[{"millis":-19001000,"nanos":0},{"millis":-18001000,"nano' - 's":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1216567000,"nano' - 's":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"epoch-seconds BIGINT -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","typ' - 'e":"BIGINT"}],"rows":[[-1001],[-1],[0],[1],[1234567],[9223372036854775807],[-92233720368547758' - '08],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' - 'e":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001000,"nanos":0},{"mil' - 'lis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1234567000,"n' - 'anos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},null],"Asia/Shanghai":[{"millis":27' - '799000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":288010' - '00,"nanos":0},{"millis":1263367000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28800000' - ',"nanos":0},null],"America/New_York":[{"millis":-19001000,"nanos":0},{"millis":-18001000,"nano' - 's":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1216567000,"nano' - 's":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,' - '-1,0,0,1,1710037800,1730597400,1710055800,1730615400,9223372036854775,-9223372036854776,null],' - '"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,9223372036854775,-' - '9223372036854776,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,173' - '0615400,9223372036854775,-9223372036854776,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows":' - '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' - '00123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0' - ',0,0,19792,20030,19792,20030,-622191233,622191232,null],"Asia/Shanghai":[-1,-1,-1,0,0,0,19792,' - '20030,19792,20030,-622191233,622191232,null],"America/New_York":[-1,-1,-1,0,0,0,19792,20030,19' - '792,20030,-622191233,622191232,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIME(0)"},"expected":{"UTC":[8639' - '8999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60424192,null],"Asi' - 'a/Shanghai":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60' - '424192,null],"America/New_York":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,' - '23400123,25975807,60424192,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIME(3)"},"expected":{"UTC":[8639' - '8999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60424192,null],"Asi' - 'a/Shanghai":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,25975807,60' - '424192,null],"America/New_York":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,' - '23400123,25975807,60424192,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"STRING"},"expected":{"UTC":["1969-' - '12-31 23:59:58.999","1969-12-31 23:59:59.000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.0' - '00","1970-01-01 00:00:00.001","1970-01-01 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 ' - '01:30:00.123","2024-03-10 07:30:00.123","2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5' - '471-09-26 16:47:04.192",null],"Asia/Shanghai":["1969-12-31 23:59:58.999","1969-12-31 23:59:59.' - '000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.000","1970-01-01 00:00:00.001","1970-01-01' - ' 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 01:30:00.123","2024-03-10 07:30:00.123","' - '2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5471-09-26 16:47:04.192",null],"America/Ne' - 'w_York":["1969-12-31 23:59:58.999","1969-12-31 23:59:59.000","1969-12-31 23:59:59.999","1970-0' - '1-01 00:00:00.000","1970-01-01 00:00:00.001","1970-01-01 00:00:01.001","2024-03-10 02:30:00.12' - '3","2024-11-03 01:30:00.123","2024-03-10 07:30:00.123","2024-11-03 06:30:00.123","/+-.-04-06 0' - '7:12:55.807","5471-09-26 16:47:04.192",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],' - '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' - '730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST",' - '"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"VARCHAR(12)"},"expected":{"UT' - 'C":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0",' - '"2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","5471-09-26 1",null' - '],"Asia/Shanghai":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0",' - '"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","547' - '1-09-26 1",null],"America/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 ' - '0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","' - '/+-.-04-06 0","5471-09-26 1",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' - ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(0)"},"expected":{"' - 'UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"milli' - 's":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nano' - 's":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":17306154' - '00000,"nanos":0},{"millis":9223372036854775000,"nanos":0},{"millis":9223372036854775616,"nanos' - '":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1' - '000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"milli' - 's":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos"' - ':0},{"millis":1730615400000,"nanos":0},{"millis":9223372036854775000,"nanos":0},{"millis":9223' - '372036854775616,"nanos":0},null],"America/New_York":[{"millis":-2000,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' - '":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"mill' - 'is":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":9223372036854775000,' - '"nanos":0},{"millis":9223372036854775616,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' - ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(1)"},"expected":{"' - 'UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis' - '":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos' - '":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":173061540' - '0100,"nanos":0},{"millis":9223372036854775800,"nanos":0},{"millis":9223372036854775716,"nanos"' - ':0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-10' - '0,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis"' - ':1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0' - '},{"millis":1730615400100,"nanos":0},{"millis":9223372036854775800,"nanos":0},{"millis":922337' - '2036854775716,"nanos":0},null],"America/New_York":[{"millis":-1100,"nanos":0},{"millis":-1000,' - '"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1' - '000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis"' - ':1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":9223372036854775800,"na' - 'nos":0},{"millis":9223372036854775716,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' - ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(3)"},"expected":{"' - 'UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":' - '0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":' - '0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":17306154001' - '23,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":' - '0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"' - 'nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17' - '10037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{' - '"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720' - '36854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"n' - 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,' - '"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":171' - '0055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos"' - ':0},{"millis":-9223372036854775808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(3)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"transform":{"name":"CAST"' - ',"fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTAMP(6)"},"expected":{"' - 'UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":' - '0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":' - '0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":17306154001' - '23,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":' - '0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"' - 'nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17' - '10037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{' - '"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720' - '36854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"n' - 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,' - '"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":171' - '0055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos"' - ':0},{"millis":-9223372036854775808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"tran' - 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTA' - 'MP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"na' - 'nos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"' - 'nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710' - '055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-53757322505224193,"nanos":0' - '},{"millis":53757322505224192,"nanos":0},null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0}' - ',{"millis":-28801000,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},' - '{"millis":-28799999,"nanos":0},{"millis":-28798999,"nanos":0},{"millis":1710009000123,"nanos":' - '0},{"millis":1730568600123,"nanos":0},{"millis":1710027000123,"nanos":0},{"millis":17305866001' - '23,"nanos":0},{"millis":-53757322534367193,"nanos":0},{"millis":53757322476424192,"nanos":0},n' - 'ull],"America/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis"' - ':17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":180' - '01001,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"milli' - 's":1710070200123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":-53757322487462193,"n' - 'anos":0},{"millis":53757322519624192,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],[null]],"tran' - 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3)"},"type":"TIMESTA' - 'MP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"na' - 'nos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"' - 'nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710' - '055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-53757322505224193,"nanos":0' - '},{"millis":53757322505224192,"nanos":0},null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0}' - ',{"millis":-28801000,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},' - '{"millis":-28799999,"nanos":0},{"millis":-28798999,"nanos":0},{"millis":1710009000123,"nanos":' - '0},{"millis":1730568600123,"nanos":0},{"millis":1710027000123,"nanos":0},{"millis":17305866001' - '23,"nanos":0},{"millis":-53757322534367193,"nanos":0},{"millis":53757322476424192,"nanos":0},n' - 'ull],"America/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis"' - ':17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":180' - '01001,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"milli' - 's":1710070200123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":-53757322487462193,"n' - 'anos":0},{"millis":53757322519624192,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":' - '1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' - '6)"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,17306' - '15400,-1,0,1,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400' - ',-1,0,1,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-' - '1,0,1,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows":' - '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' - '00123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":10' - '00}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6)' - '"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia' - '/Shanghai":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"America/New_York":[-1,-1,-1,0' - ',0,0,19792,20030,19792,20030,-1,0,0,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos"' - ':1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(6)"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123' - ',27000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,' - '9000123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,' - '86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos"' - ':1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(6)"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123' - ',27000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,' - '9000123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,' - '86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":' - '1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' - '6)"},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999000","1969-12-31 23:59:59.000' - '000","1969-12-31 23:59:59.999000","1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1' - '970-01-01 00:00:01.001000","2024-03-10 02:30:00.123000","2024-11-03 01:30:00.123000","2024-03-' - '10 07:30:00.123000","2024-11-03 06:30:00.123000","1969-12-31 23:59:59.999999","1970-01-01 00:0' - '0:00.000123","1970-01-01 00:00:01.000001",null],"Asia/Shanghai":["1969-12-31 23:59:58.999000",' - '"1969-12-31 23:59:59.000000","1969-12-31 23:59:59.999000","1970-01-01 00:00:00.000000","1970-0' - '1-01 00:00:00.001000","1970-01-01 00:00:01.001000","2024-03-10 02:30:00.123000","2024-11-03 01' - ':30:00.123000","2024-03-10 07:30:00.123000","2024-11-03 06:30:00.123000","1969-12-31 23:59:59.' - '999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:01.000001",null],"America/New_York":["1' - '969-12-31 23:59:58.999000","1969-12-31 23:59:59.000000","1969-12-31 23:59:59.999000","1970-01-' - '01 00:00:00.000000","1970-01-01 00:00:00.001000","1970-01-01 00:00:01.001000","2024-03-10 02:3' - '0:00.123000","2024-11-03 01:30:00.123000","2024-03-10 07:30:00.123000","2024-11-03 06:30:00.12' - '3000","1969-12-31 23:59:59.999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:01.000001",n' - 'ull]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],' - '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' - '730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"na' - 'nos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMES' - 'TAMP(6)"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2' - '","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2' - '024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1969-12-31 2' - '","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2' - '024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],' - '"America/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0"' - ',"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","19' - '70-01-01 0","1970-01-01 0",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' - 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' - 'STAMP(6)"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' - '":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"mill' - 'is":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"m' - 'illis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"na' - 'nos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"' - 'nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"mill' - 'is":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos"' - ':0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"mill' - 'is":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos' - '":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' - 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' - 'STAMP(6)"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis"' - ':1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"milli' - 's":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"mil' - 'lis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},' - '{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos' - '":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nan' - 'os":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"n' - 'anos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":' - '-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{' - '"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1' - '730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},' - '{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' - 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' - 'STAMP(6)"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1' - '001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis"' - ':1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis"' - ':0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"mi' - 'llis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{' - '"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0}' - ',{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0}' - ',{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-1001,"n' - 'anos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1' - ',"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":17305974001' - '23,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":' - '-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(6)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"n' - 'anos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME' - 'STAMP(6)"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-100' - '0,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1' - '001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis"' - ':1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"mi' - 'llis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"Asia/Shanghai":[{"millis":-1001,"n' - 'anos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1' - ',"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":17305974001' - '23,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":' - '-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"America/New' - '_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis' - '":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos' - '":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":173061540' - '0123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos' - '":1000},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000' - '}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"n' - 'ame":"v","type":"TIMESTAMP(6)"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":' - '[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"na' - 'nos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"' - 'millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"n' - 'anos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/' - 'Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-28800001,"' - 'nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-28798999,"n' - 'anos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis":17100' - '27000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":0},{"millis' - '":-28800000,"nanos":0},{"millis":-28799000,"nanos":0},null],"America/New_York":[{"millis":1799' - '8999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000' - ',"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"millis":171005580012' - '3,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nanos":0},{"millis":1' - '730633400123,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":' - '18001000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"nanos":123000' - '}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"n' - 'ame":"v","type":"TIMESTAMP(6)"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":' - '[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"na' - 'nos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"' - 'millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"n' - 'anos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000}' - ',null],"Asia/Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis' - '":-28800001,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis"' - ':-28798999,"nanos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"' - 'millis":1710027000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos' - '":999000},{"millis":-28800000,"nanos":123000},{"millis":-28799000,"nanos":1000},null],"America' - '/New_York":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"na' - 'nos":0},{"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos"' - ':0},{"millis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200' - '123,"nanos":0},{"millis":1730633400123,"nanos":0},{"millis":17999999,"nanos":999000},{"millis"' - ':18000000,"nanos":123000},{"millis":18001000,"nanos":1000},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> BIGINT","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":' - '1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"' - '},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,17306154' - '00,-1,0,1,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1' - ',0,1,null],"America/New_York":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0' - ',1,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> DATE","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows":' - '[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306154' - '00123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":1}' - '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"},' - '"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia/Sh' - 'anghai":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"America/New_York":[-1,-1,-1,0,0,' - '0,19792,20030,19792,20030,-1,0,0,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIME(0)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos"' - ':1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)' - '"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27' - '000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,900' - '0123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,863' - '99999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIME(3)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"row' - 's":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[17306' - '15400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos"' - ':1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)' - '"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27' - '000123,23400123,86399999,0,1000,null],"Asia/Shanghai":[86398999,86399000,86399999,0,1,1001,900' - '0123,5400123,27000123,23400123,86399999,0,1000,null],"America/New_York":[86398999,86399000,863' - '99999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"rows' - '":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[173061' - '5400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"nanos":' - '1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(9)"' - '},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999000000","1969-12-31 23:59:59.000' - '000000","1969-12-31 23:59:59.999000000","1970-01-01 00:00:00.000000000","1970-01-01 00:00:00.0' - '01000000","1970-01-01 00:00:01.001000000","2024-03-10 02:30:00.123000000","2024-11-03 01:30:00' - '.123000000","2024-03-10 07:30:00.123000000","2024-11-03 06:30:00.123000000","1969-12-31 23:59:' - '59.999999999","1970-01-01 00:00:00.000123456","1970-01-01 00:00:01.000000001",null],"Asia/Shan' - 'ghai":["1969-12-31 23:59:58.999000000","1969-12-31 23:59:59.000000000","1969-12-31 23:59:59.99' - '9000000","1970-01-01 00:00:00.000000000","1970-01-01 00:00:00.001000000","1970-01-01 00:00:01.' - '001000000","2024-03-10 02:30:00.123000000","2024-11-03 01:30:00.123000000","2024-03-10 07:30:0' - '0.123000000","2024-11-03 06:30:00.123000000","1969-12-31 23:59:59.999999999","1970-01-01 00:00' - ':00.000123456","1970-01-01 00:00:01.000000001",null],"America/New_York":["1969-12-31 23:59:58.' - '999000000","1969-12-31 23:59:59.000000000","1969-12-31 23:59:59.999000000","1970-01-01 00:00:0' - '0.000000000","1970-01-01 00:00:00.001000000","1970-01-01 00:00:01.001000000","2024-03-10 02:30' - ':00.123000000","2024-11-03 01:30:00.123000000","2024-03-10 07:30:00.123000000","2024-11-03 06:' - '30:00.123000000","1969-12-31 23:59:59.999999999","1970-01-01 00:00:00.000123456","1970-01-01 0' - '0:00:01.000000001",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> VARCHAR(12)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],' - '"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1' - '730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"na' - 'nos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAM' - 'P(9)"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2","' - '1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024' - '-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1969-12-31 2","' - '1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024' - '-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-01-01 0","1970-01-01 0",null],"Am' - 'erica/New_York":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1' - '970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","1970-' - '01-01 0","1970-01-01 0",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(0)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' - 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' - 'MP(9)"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"' - 'nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1' - '000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis"' - ':1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"mill' - 'is":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-2000,"nanos":0},{' - '"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos' - '":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nan' - 'os":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":-1000,"' - 'nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis"' - ':-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0}' - ',{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis"' - ':1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(1)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' - 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' - 'MP(9)"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"' - 'nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":10' - '00,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":' - '1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"millis' - '":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1100,"nanos":0},{"m' - 'illis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0' - '},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"nanos"' - ':0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":-100,"nano' - 's":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-11' - '00,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"mi' - 'llis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730' - '597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"m' - 'illis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(3)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' - 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' - 'MP(9)"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"' - 'nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001' - ',"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":17' - '10055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,' - '"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"milli' - 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' - 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' - 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"' - 'millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"millis":-1001,"nano' - 's":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"n' - 'anos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,' - '"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,' - '"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(6)","fields":[{"name":"v","type":"TIMESTAMP(9)"}]' - ',"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[' - '1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456}],[{"millis":1000,"n' - 'anos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTA' - 'MP(9)"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"' - 'nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001' - ',"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":17' - '10055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"milli' - 's":0,"nanos":123000},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":' - '0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nano' - 's":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"na' - 'nos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"na' - 'nos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null],"America/New_York":[{' - '"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nano' - 's":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mi' - 'llis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nan' - 'os":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null' - ']}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(9)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456' - '}],[{"millis":1000,"nanos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name' - '":"v","type":"TIMESTAMP(9)"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"' - 'millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos' - '":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mil' - 'lis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nano' - 's":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Sha' - 'nghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-28800001,"nan' - 'os":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-28798999,"nano' - 's":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis":17100270' - '00123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":0},{"millis":-' - '28800000,"nanos":0},{"millis":-28799000,"nanos":0},null],"America/New_York":[{"millis":1799899' - '9,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"n' - 'anos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"millis":1710055800123,"' - 'nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nanos":0},{"millis":1730' - '633400123,"nanos":0},{"millis":17999999,"nanos":0},{"millis":18000000,"nanos":0},{"millis":180' - '01000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(9) -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(9)"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123],[17305974001' - '23],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999999}],[{"millis":0,"nanos":123456' - '}],[{"millis":1000,"nanos":1}],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name' - '":"v","type":"TIMESTAMP(9)"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"' - 'millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos' - '":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"mil' - 'lis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nano' - 's":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":0},null]' - ',"Asia/Shanghai":[{"millis":-28801001,"nanos":0},{"millis":-28801000,"nanos":0},{"millis":-288' - '00001,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":-28799999,"nanos":0},{"millis":-2879' - '8999,"nanos":0},{"millis":1710009000123,"nanos":0},{"millis":1730568600123,"nanos":0},{"millis' - '":1710027000123,"nanos":0},{"millis":1730586600123,"nanos":0},{"millis":-28800001,"nanos":9990' - '00},{"millis":-28800000,"nanos":123000},{"millis":-28799000,"nanos":0},null],"America/New_York' - '":[{"millis":17998999,"nanos":0},{"millis":17999000,"nanos":0},{"millis":17999999,"nanos":0},{' - '"millis":18000000,"nanos":0},{"millis":18000001,"nanos":0},{"millis":18001001,"nanos":0},{"mil' - 'lis":1710055800123,"nanos":0},{"millis":1730611800123,"nanos":0},{"millis":1710070200123,"nano' - 's":0},{"millis":1730633400123,"nanos":0},{"millis":17999999,"nanos":999000},{"millis":18000000' - ',"nanos":123000},{"millis":18001000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> BIGINT","fields":[{"name":"v","type":"' - 'TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' - '3],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808' - '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WI' - 'TH LOCAL TIME ZONE"},"type":"BIGINT"},"expected":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,' - '1710055800,1730615400,-53757322505225,53757322505224,null],"Asia/Shanghai":[-2,-1,-1,0,0,1,171' - '0037800,1730597400,1710055800,1730615400,-53757322505225,53757322505224,null],"America/New_Yor' - 'k":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-53757322505225,53757322505224,' - 'null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> DATE","fields":[{"name":"v","type":"TI' - 'MESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123]' - ',[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808],' - '[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WITH' - ' LOCAL TIME ZONE"},"type":"DATE"},"expected":{"UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-6' - '22191233,622191233,null],"Asia/Shanghai":[0,0,0,0,0,0,19792,20030,19792,20030,-622191233,62219' - '1234,null],"America/New_York":[-1,-1,-1,-1,-1,-1,19791,20029,19792,20030,-622191233,622191233,' - 'null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIME(0)","fields":[{"name":"v","type":' - '"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' - '23],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-922337203685477580' - '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) W' - 'ITH LOCAL TIME ZONE"},"type":"TIME(0)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001' - ',9000123,5400123,27000123,23400123,25975807,60424192,null],"Asia/Shanghai":[28798999,28799000,' - '28799999,28800000,28800001,28801001,37800123,34200123,55800123,52200123,54775807,3167192,null]' - ',"America/New_York":[68398999,68399000,68399999,68400000,68400001,68401001,77400123,77400123,1' - '2600123,5400123,11575807,42662192,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIME(3)","fields":[{"name":"v","type":' - '"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' - '23],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-922337203685477580' - '8],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) W' - 'ITH LOCAL TIME ZONE"},"type":"TIME(3)"},"expected":{"UTC":[86398999,86399000,86399999,0,1,1001' - ',9000123,5400123,27000123,23400123,25975807,60424192,null],"Asia/Shanghai":[28798999,28799000,' - '28799999,28800000,28800001,28801001,37800123,34200123,55800123,52200123,54775807,3167192,null]' - ',"America/New_York":[68398999,68399000,68399999,68400000,68400001,68401001,77400123,77400123,1' - '2600123,5400123,11575807,42662192,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"' - 'TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' - '3],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854775808' - '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(3) WI' - 'TH LOCAL TIME ZONE"},"type":"STRING"},"expected":{"UTC":["1969-12-31 23:59:58.999","1969-12-31' - ' 23:59:59.000","1969-12-31 23:59:59.999","1970-01-01 00:00:00.000","1970-01-01 00:00:00.001","' - '1970-01-01 00:00:01.001","2024-03-10 02:30:00.123","2024-11-03 01:30:00.123","2024-03-10 07:30' - ':00.123","2024-11-03 06:30:00.123","/+-.-04-06 07:12:55.807","5471-09-26 16:47:04.192",null],"' - 'Asia/Shanghai":["1970-01-01 07:59:58.999","1970-01-01 07:59:59.000","1970-01-01 07:59:59.999",' - '"1970-01-01 08:00:00.000","1970-01-01 08:00:00.001","1970-01-01 08:00:01.001","2024-03-10 10:3' - '0:00.123","2024-11-03 09:30:00.123","2024-03-10 15:30:00.123","2024-11-03 14:30:00.123","5471-' - '09-27 00:47:04.191","5471-09-27 00:52:47.192",null],"America/New_York":["1969-12-31 18:59:58.9' - '99","1969-12-31 18:59:59.000","1969-12-31 18:59:59.999","1969-12-31 19:00:00.000","1969-12-31 ' - '19:00:00.001","1969-12-31 19:00:01.001","2024-03-09 21:30:00.123","2024-11-02 21:30:00.123","2' - '024-03-10 03:30:00.123","2024-11-03 01:30:00.123","/+-.-04-06 03:12:55.807","/+-.-04-06 02:16:' - '53.808",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> VARCHAR(12)","fields":[{"name":"v","ty' - 'pe":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037' - '800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-92233720368547' - '75808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(' - '3) WITH LOCAL TIME ZONE"},"type":"VARCHAR(12)"},"expected":{"UTC":["1969-12-31 2","1969-12-31 ' - '2","1969-12-31 2","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 0","2024-11-03 0","' - '2024-03-10 0","2024-11-03 0","/+-.-04-06 0","5471-09-26 1",null],"Asia/Shanghai":["1970-01-01 ' - '0","1970-01-01 0","1970-01-01 0","1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 1","' - '2024-11-03 0","2024-03-10 1","2024-11-03 1","5471-09-27 0","5471-09-27 0",null],"America/New_Y' - 'ork":["1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1' - '","2024-03-09 2","2024-11-02 2","2024-03-10 0","2024-11-03 0","/+-.-04-06 0","/+-.-04-06 0",nu' - 'll]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(0)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' - '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(0)"},"expected":{"UTC":[{"millis":-2000,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"na' - 'nos":0},{"millis":1000,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"' - 'nanos":0},{"millis":1710055800000,"nanos":0},{"millis":1730615400000,"nanos":0},{"millis":9223' - '372036854775000,"nanos":0},{"millis":9223372036854775616,"nanos":0},null],"Asia/Shanghai":[{"m' - 'illis":28798000,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799000,"nanos":0},{"milli' - 's":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},{"millis":1' - '710066600000,"nanos":0},{"millis":1730626200000,"nanos":0},{"millis":1710084600000,"nanos":0},' - '{"millis":1730644200000,"nanos":0},{"millis":-9223372036825976000,"nanos":0},{"millis":-922337' - '2036825633000,"nanos":0},null],"America/New_York":[{"millis":-18002000,"nanos":0},{"millis":-1' - '8001000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-18' - '000000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1710019800000,"nanos":0},{"millis":' - '1730583000000,"nanos":0},{"millis":1710041400000,"nanos":0},{"millis":1730597400000,"nanos":0}' - ',{"millis":9223372036840375000,"nanos":0},{"millis":9223372036837013000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(1)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' - '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(1)"},"expected":{"UTC":[{"millis":-1100,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nan' - 'os":0},{"millis":1000,"nanos":0},{"millis":1710037800100,"nanos":0},{"millis":1730597400100,"n' - 'anos":0},{"millis":1710055800100,"nanos":0},{"millis":1730615400100,"nanos":0},{"millis":92233' - '72036854775800,"nanos":0},{"millis":9223372036854775716,"nanos":0},null],"Asia/Shanghai":[{"mi' - 'llis":28798900,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799900,"nanos":0},{"millis' - '":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},{"millis":17' - '10066600100,"nanos":0},{"millis":1730626200100,"nanos":0},{"millis":1710084600100,"nanos":0},{' - '"millis":1730644200100,"nanos":0},{"millis":-9223372036825975900,"nanos":0},{"millis":-9223372' - '036825632900,"nanos":0},null],"America/New_York":[{"millis":-18001100,"nanos":0},{"millis":-18' - '001000,"nanos":0},{"millis":-18000100,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-180' - '00000,"nanos":0},{"millis":-17999000,"nanos":0},{"millis":1710019800100,"nanos":0},{"millis":1' - '730583000100,"nanos":0},{"millis":1710041400100,"nanos":0},{"millis":1730597400100,"nanos":0},' - '{"millis":9223372036840375800,"nanos":0},{"millis":9223372036837013800,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(3)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' - '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":-1001,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos' - '":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nan' - 'os":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372' - '036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null],"Asia/Shanghai":[{"mil' - 'lis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799999,"nanos":0},{"millis"' - ':28800000,"nanos":0},{"millis":28800001,"nanos":0},{"millis":28801001,"nanos":0},{"millis":171' - '0066600123,"nanos":0},{"millis":1730626200123,"nanos":0},{"millis":1710084600123,"nanos":0},{"' - 'millis":1730644200123,"nanos":0},{"millis":-9223372036825975809,"nanos":0},{"millis":-92233720' - '36825632808,"nanos":0},null],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-180' - '01000,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-1799' - '9999,"nanos":0},{"millis":-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":17' - '30583000123,"nanos":0},{"millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{' - '"millis":9223372036840375807,"nanos":0},{"millis":9223372036837013808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(6)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[9223372036854775807],[-9223372036854' - '775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP' - '(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":-1001,"nanos":0' - '},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos' - '":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nan' - 'os":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372' - '036854775807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null],"Asia/Shanghai":[{"mil' - 'lis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"millis":28799999,"nanos":0},{"millis"' - ':28800000,"nanos":0},{"millis":28800001,"nanos":0},{"millis":28801001,"nanos":0},{"millis":171' - '0066600123,"nanos":0},{"millis":1730626200123,"nanos":0},{"millis":1710084600123,"nanos":0},{"' - 'millis":1730644200123,"nanos":0},{"millis":-9223372036825975809,"nanos":0},{"millis":-92233720' - '36825632808,"nanos":0},null],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-180' - '01000,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-1799' - '9999,"nanos":0},{"millis":-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":17' - '30583000123,"nanos":0},{"millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{' - '"millis":9223372036840375807,"nanos":0},{"millis":9223372036837013808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fi' - 'elds":[{"name":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' - '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[922337203685477' - '5807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' - '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"e' - 'xpected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0}' - ',{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17100378001' - '23,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":' - '1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720368547758' - '08,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"m' - 'illis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{' - '"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"' - 'nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis' - '":-9223372036854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"milli' - 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' - 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' - 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775' - '807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(3) WITH LOCAL TIME ZONE -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fi' - 'elds":[{"name":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' - '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[922337203685477' - '5807],[-9223372036854775808],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' - '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"e' - 'xpected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0}' - ',{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":17100378001' - '23,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":' - '1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis":-92233720368547758' - '08,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"m' - 'illis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{' - '"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"' - 'nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775807,"nanos":0},{"millis' - '":-9223372036854775808,"nanos":0},null],"America/New_York":[{"millis":-1001,"nanos":0},{"milli' - 's":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"mi' - 'llis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"' - 'millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":9223372036854775' - '807,"nanos":0},{"millis":-9223372036854775808,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> BIGINT","fields":[{"name":"v","type":"' - 'TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' - '3],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0' - ',"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"BIGINT"},"expected' - '":{"UTC":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null],"Asia/Shangh' - 'ai":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null],"America/New_York' - '":[-2,-1,-1,0,0,1,1710037800,1730597400,1710055800,1730615400,-1,0,1,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> DATE","fields":[{"name":"v","type":"TI' - 'MESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037800123]' - ',[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0,"' - 'nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef":{' - '"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"DATE"},"expected":{"' - 'UTC":[-1,-1,-1,0,0,0,19792,20030,19792,20030,-1,0,0,null],"Asia/Shanghai":[0,0,0,0,0,0,19792,2' - '0030,19792,20030,0,0,0,null],"America/New_York":[-1,-1,-1,-1,-1,-1,19791,20029,19792,20030,-1,' - '-1,-1,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIME(0)","fields":[{"name":"v","type":' - '"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' - '23],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":' - '0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef' - '":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIME(0)"},"expect' - 'ed":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1' - '000,null],"Asia/Shanghai":[28798999,28799000,28799999,28800000,28800001,28801001,37800123,3420' - '0123,55800123,52200123,28799999,28800000,28801000,null],"America/New_York":[68398999,68399000,' - '68399999,68400000,68400001,68401001,77400123,77400123,12600123,5400123,68399999,68400000,68401' - '000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIME(3)","fields":[{"name":"v","type":' - '"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[17100378001' - '23],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":' - '0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef' - '":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIME(3)"},"expect' - 'ed":{"UTC":[86398999,86399000,86399999,0,1,1001,9000123,5400123,27000123,23400123,86399999,0,1' - '000,null],"Asia/Shanghai":[28798999,28799000,28799999,28800000,28800001,28801001,37800123,3420' - '0123,55800123,52200123,28799999,28800000,28801000,null],"America/New_York":[68398999,68399000,' - '68399999,68400000,68400001,68401001,77400123,77400123,12600123,5400123,68399999,68400000,68401' - '000,null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"' - 'TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003780012' - '3],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"millis":0' - ',"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"STRING"},"expected' - '":{"UTC":["1969-12-31 23:59:58.999000","1969-12-31 23:59:59.000000","1969-12-31 23:59:59.99900' - '0","1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1970-01-01 00:00:01.001000","202' - '4-03-10 02:30:00.123000","2024-11-03 01:30:00.123000","2024-03-10 07:30:00.123000","2024-11-03' - ' 06:30:00.123000","1969-12-31 23:59:59.999999","1970-01-01 00:00:00.000123","1970-01-01 00:00:' - '01.000001",null],"Asia/Shanghai":["1970-01-01 07:59:58.999000","1970-01-01 07:59:59.000000","1' - '970-01-01 07:59:59.999000","1970-01-01 08:00:00.000000","1970-01-01 08:00:00.001000","1970-01-' - '01 08:00:01.001000","2024-03-10 10:30:00.123000","2024-11-03 09:30:00.123000","2024-03-10 15:3' - '0:00.123000","2024-11-03 14:30:00.123000","1970-01-01 07:59:59.999999","1970-01-01 08:00:00.00' - '0123","1970-01-01 08:00:01.000001",null],"America/New_York":["1969-12-31 18:59:58.999000","196' - '9-12-31 18:59:59.000000","1969-12-31 18:59:59.999000","1969-12-31 19:00:00.000000","1969-12-31' - ' 19:00:00.001000","1969-12-31 19:00:01.001000","2024-03-09 21:30:00.123000","2024-11-02 21:30:' - '00.123000","2024-03-10 03:30:00.123000","2024-11-03 01:30:00.123000","1969-12-31 18:59:59.9999' - '99","1969-12-31 19:00:00.000123","1969-12-31 19:00:01.000001",null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> VARCHAR(12)","fields":[{"name":"v","ty' - 'pe":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[1710037' - '800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mill' - 'is":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"VARCHAR(12)"}' - ',"expected":{"UTC":["1969-12-31 2","1969-12-31 2","1969-12-31 2","1970-01-01 0","1970-01-01 0"' - ',"1970-01-01 0","2024-03-10 0","2024-11-03 0","2024-03-10 0","2024-11-03 0","1969-12-31 2","19' - '70-01-01 0","1970-01-01 0",null],"Asia/Shanghai":["1970-01-01 0","1970-01-01 0","1970-01-01 0"' - ',"1970-01-01 0","1970-01-01 0","1970-01-01 0","2024-03-10 1","2024-11-03 0","2024-03-10 1","20' - '24-11-03 1","1970-01-01 0","1970-01-01 0","1970-01-01 0",null],"America/New_York":["1969-12-31' - ' 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","1969-12-31 1","2024-03-09 2",' - '"2024-11-02 2","2024-03-10 0","2024-11-03 0","1969-12-31 1","1969-12-31 1","1969-12-31 1",null' - ']}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(0)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' - 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(0)' - '"},"expected":{"UTC":[{"millis":-2000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1000,"n' - 'anos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":171' - '0037800000,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":1710055800000,"nanos":0},{"' - 'millis":1730615400000,"nanos":0},{"millis":-1000,"nanos":0},{"millis":0,"nanos":0},{"millis":1' - '000,"nanos":0},null],"Asia/Shanghai":[{"millis":28798000,"nanos":0},{"millis":28799000,"nanos"' - ':0},{"millis":28799000,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800000,"nanos":0},' - '{"millis":28801000,"nanos":0},{"millis":1710066600000,"nanos":0},{"millis":1730626200000,"nano' - 's":0},{"millis":1710084600000,"nanos":0},{"millis":1730644200000,"nanos":0},{"millis":28799000' - ',"nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_Yor' - 'k":[{"millis":-18002000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18001000,"nanos":' - '0},{"millis":-18000000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0' - '},{"millis":1710019800000,"nanos":0},{"millis":1730583000000,"nanos":0},{"millis":171004140000' - '0,"nanos":0},{"millis":1730597400000,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-1800' - '0000,"nanos":0},{"millis":-17999000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(1)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' - 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(1)' - '"},"expected":{"UTC":[{"millis":-1100,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-100,"na' - 'nos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis":1710' - '037800100,"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":1710055800100,"nanos":0},{"m' - 'illis":1730615400100,"nanos":0},{"millis":-100,"nanos":0},{"millis":0,"nanos":0},{"millis":100' - '0,"nanos":0},null],"Asia/Shanghai":[{"millis":28798900,"nanos":0},{"millis":28799000,"nanos":0' - '},{"millis":28799900,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800000,"nanos":0},{"' - 'millis":28801000,"nanos":0},{"millis":1710066600100,"nanos":0},{"millis":1730626200100,"nanos"' - ':0},{"millis":1710084600100,"nanos":0},{"millis":1730644200100,"nanos":0},{"millis":28799900,"' - 'nanos":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_York"' - ':[{"millis":-18001100,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000100,"nanos":0}' - ',{"millis":-18000000,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999000,"nanos":0},' - '{"millis":1710019800100,"nanos":0},{"millis":1730583000100,"nanos":0},{"millis":1710041400100,' - '"nanos":0},{"millis":1730597400100,"nanos":0},{"millis":-18000100,"nanos":0},{"millis":-180000' - '00,"nanos":0},{"millis":-17999000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(3)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' - 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(3)' - '"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nano' - 's":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003' - '7800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"mil' - 'lis":1730615400123,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"n' - 'anos":0},null],"Asia/Shanghai":[{"millis":28798999,"nanos":0},{"millis":28799000,"nanos":0},{"' - 'millis":28799999,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800001,"nanos":0},{"mill' - 'is":28801001,"nanos":0},{"millis":1710066600123,"nanos":0},{"millis":1730626200123,"nanos":0},' - '{"millis":1710084600123,"nanos":0},{"millis":1730644200123,"nanos":0},{"millis":28799999,"nano' - 's":0},{"millis":28800000,"nanos":0},{"millis":28801000,"nanos":0},null],"America/New_York":[{"' - 'millis":-18001001,"nanos":0},{"millis":-18001000,"nanos":0},{"millis":-18000001,"nanos":0},{"m' - 'illis":-18000000,"nanos":0},{"millis":-17999999,"nanos":0},{"millis":-17998999,"nanos":0},{"mi' - 'llis":1710019800123,"nanos":0},{"millis":1730583000123,"nanos":0},{"millis":1710041400123,"nan' - 'os":0},{"millis":1730597400123,"nanos":0},{"millis":-18000001,"nanos":0},{"millis":-18000000,"' - 'nanos":0},{"millis":-17999000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(6)","fields":[{"name":"v","t' - 'ype":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[0],[1],[1001],[171003' - '7800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"nanos":999000}],[{"mil' - 'lis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"type":"TIMESTAMP(6)' - '"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nano' - 's":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003' - '7800123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"mil' - 'lis":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"milli' - 's":1000,"nanos":1000},null],"Asia/Shanghai":[{"millis":28798999,"nanos":0},{"millis":28799000,' - '"nanos":0},{"millis":28799999,"nanos":0},{"millis":28800000,"nanos":0},{"millis":28800001,"nan' - 'os":0},{"millis":28801001,"nanos":0},{"millis":1710066600123,"nanos":0},{"millis":173062620012' - '3,"nanos":0},{"millis":1710084600123,"nanos":0},{"millis":1730644200123,"nanos":0},{"millis":2' - '8799999,"nanos":999000},{"millis":28800000,"nanos":123000},{"millis":28801000,"nanos":1000},nu' - 'll],"America/New_York":[{"millis":-18001001,"nanos":0},{"millis":-18001000,"nanos":0},{"millis' - '":-18000001,"nanos":0},{"millis":-18000000,"nanos":0},{"millis":-17999999,"nanos":0},{"millis"' - ':-17998999,"nanos":0},{"millis":1710019800123,"nanos":0},{"millis":1730583000123,"nanos":0},{"' - 'millis":1710041400123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":-18000001,"nanos' - '":999000},{"millis":-18000000,"nanos":123000},{"millis":-17999000,"nanos":1000},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fi' - 'elds":[{"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' - '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"n' - 'anos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform' - '":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}' - ',"type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"m' - 'illis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},' - '{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0' - '},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":0' - '},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"Asia/Shanghai":[{"millis":-1001,"nan' - 'os":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"' - 'nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123' - ',"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1' - ',"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null],"America/New_York":[{"milli' - 's":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},' - '{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":' - '1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0}' - ',{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timestamp TIMESTAMP(6) WITH LOCAL TIME ZONE -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fi' - 'elds":[{"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}],"rows":[[-1001],[-1000],[-1],[' - '0],[1],[1001],[1710037800123],[1730597400123],[1710055800123],[1730615400123],[{"millis":-1,"n' - 'anos":999000}],[{"millis":0,"nanos":123000}],[{"millis":1000,"nanos":1000}],[null]],"transform' - '":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"}' - ',"type":"TIMESTAMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":-1001,"nanos":0},{"m' - 'illis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},' - '{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":1730597400123,"nanos":0' - '},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0},{"millis":-1,"nanos":9' - '99000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"Asia/Shanghai":[{"milli' - 's":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":0},{"millis":0,"nanos":0},' - '{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":1710037800123,"nanos":0},{"millis":' - '1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis":1730615400123,"nanos":0}' - ',{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":1000,"nanos":1000},null],"' - 'America/New_York":[{"millis":-1001,"nanos":0},{"millis":-1000,"nanos":0},{"millis":-1,"nanos":' - '0},{"millis":0,"nanos":0},{"millis":1,"nanos":0},{"millis":1001,"nanos":0},{"millis":171003780' - '0123,"nanos":0},{"millis":1730597400123,"nanos":0},{"millis":1710055800123,"nanos":0},{"millis' - '":1730615400123,"nanos":0},{"millis":-1,"nanos":999000},{"millis":0,"nanos":123000},{"millis":' - '1000,"nanos":1000},null]}}' - ), - json.loads( - '{"name":"rebound INT -> STRING","fields":[{"name":"v","type":"INT"}],"rows":[[0],[1],[-1],[nul' - 'l]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type":"STRING' - '"},"expected":{"UTC":["1970-01-01","1970-01-02","1969-12-31",null],"Asia/Shanghai":["1970-01-0' - '1","1970-01-02","1969-12-31",null],"America/New_York":["1970-01-01","1970-01-02","1969-12-31",' - 'null]}}' - ), - json.loads( - '{"name":"rebound DATE -> STRING","fields":[{"name":"v","type":"DATE"}],"rows":[[0],[1],[-1],[n' - 'ull]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIME(3)"},"type":"S' - 'TRING"},"expected":{"UTC":["00:00:00.0","00:00:00.001","23:59:59.999",null],"Asia/Shanghai":["' - '00:00:00.0","00:00:00.001","23:59:59.999",null],"America/New_York":["00:00:00.0","00:00:00.001' - '","23:59:59.999",null]}}' - ), - json.loads( - '{"name":"rebound TIME(3) -> STRING","fields":[{"name":"v","type":"TIME(3)"}],"rows":[[0],[1],[' - '-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DATE"},"type"' - ':"STRING"},"expected":{"UTC":["1970-01-01","1970-01-02","1969-12-31",null],"Asia/Shanghai":["1' - '970-01-01","1970-01-02","1969-12-31",null],"America/New_York":["1970-01-01","1970-01-02","1969' - '-12-31",null]}}' - ), - json.loads( - '{"name":"rebound DATE -> TIMESTAMP(3)","fields":[{"name":"v","type":"DATE"}],"rows":[[0],[1],[' - '-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"typ' - 'e":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"milli' - 's":-1000,"nanos":0},null],"Asia/Shanghai":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"' - 'millis":-1000,"nanos":0},null],"America/New_York":[{"millis":0,"nanos":0},{"millis":1000,"nano' - 's":0},{"millis":-1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"rebound INT -> TIMESTAMP(3)","fields":[{"name":"v","type":"INT"}],"rows":[[0],[1],[-1' - '],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"type"' - ':"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"millis"' - ':-1000,"nanos":0},null],"Asia/Shanghai":[{"millis":0,"nanos":0},{"millis":1000,"nanos":0},{"mi' - 'llis":-1000,"nanos":0},null],"America/New_York":[{"millis":0,"nanos":0},{"millis":1000,"nanos"' - ':0},{"millis":-1000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"rebound TIMESTAMP(3) WITH LOCAL TIME ZONE -> STRING","fields":[{"name":"v","type":"TI' - 'MESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[0],[1],[-1],[null]],"transform":{"name":"CAST","fi' - 'eldRef":{"index":99,"name":"v","type":"TIMESTAMP(6)"},"type":"STRING"},"expected":{"UTC":["197' - '0-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969-12-31 23:59:59.999000",null],"Asia' - '/Shanghai":["1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969-12-31 23:59:59.999' - '000",null],"America/New_York":["1970-01-01 00:00:00.000000","1970-01-01 00:00:00.001000","1969' - '-12-31 23:59:59.999000",null]}}' - ), - json.loads( - '{"name":"rebound TIMESTAMP(6) -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"rows":' - '[[0],[1],[-1],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"TIM' - 'ESTAMP(3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01 00:00:00.000","1970-01-01 00:00:00' - '.001","1969-12-31 23:59:59.999",null],"Asia/Shanghai":["1970-01-01 00:00:00.000","1970-01-01 0' - '0:00:00.001","1969-12-31 23:59:59.999",null],"America/New_York":["1970-01-01 00:00:00.000","19' - '70-01-01 00:00:00.001","1969-12-31 23:59:59.999",null]}}' - ), - json.loads( - '{"name":"rebound STRING -> VARCHAR(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["abcde' - 'f"],["\\u00e9\\u732b"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","typ' - 'e":"BINARY(8)"},"type":"VARCHAR(3)"},"expected":{"UTC":[{"error":"ClassCastException"},{"error' - '":"ClassCastException"},null],"Asia/Shanghai":[{"error":"ClassCastException"},{"error":"ClassC' - 'astException"},null],"America/New_York":[{"error":"ClassCastException"},{"error":"ClassCastExc' - 'eption"},null]}}' - ), - json.loads( - '{"name":"rebound BINARY(8) -> VARCHAR(3)","fields":[{"name":"v","type":"BINARY(8)"}],"rows":[[' - '[97,98,99,100,101,102]],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","' - 'type":"STRING"},"type":"VARCHAR(3)"},"expected":{"UTC":[{"error":"ClassCastException"},null],"' - 'Asia/Shanghai":[{"error":"ClassCastException"},null],"America/New_York":[{"error":"ClassCastEx' - 'ception"},null]}}' - ), - json.loads( - '{"name":"grammar STRING -> DATE","fields":[{"name":"v","type":"STRING"}],"rows":[["1970-011-02' - '2"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01-02 0303' - ':0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"],["1970' - '-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03:04:05T0' - '6:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.124"],["' - '1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24:00:00.0' - '01"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01"],["000' - '1-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["+1"],["-' - '1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":{"index"' - ':99,"name":"v","type":"STRING"},"type":"DATE"},"expected":{"UTC":[325,{"error":"DateTimeExcept' - 'ion"},355,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeExcept' - 'ion"},1,1,1,1,{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1,1,1,{"error":"' - 'DateTimeException"},1,1,1,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error"' - ':"DateTimeException"},-719528,-719162,{"error":"DateTimeException"},{"error":"DateTimeExceptio' - 'n"},{"error":"DateTimeException"},1,{"error":"DateTimeException"},-1,{"error":"DateTimeExcepti' - 'on"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null],"Asia/Shanghai"' - ':[325,{"error":"DateTimeException"},355,{"error":"DateTimeException"},{"error":"DateTimeExcept' - 'ion"},{"error":"DateTimeException"},1,1,1,1,{"error":"DateTimeException"},{"error":"DateTimeEx' - 'ception"},1,1,1,1,1,{"error":"DateTimeException"},1,1,1,{"error":"DateTimeException"},{"error"' - ':"DateTimeException"},{"error":"DateTimeException"},-719528,-719162,{"error":"DateTimeExceptio' - 'n"},{"error":"DateTimeException"},{"error":"DateTimeException"},1,{"error":"DateTimeException"' - '},-1,{"error":"DateTimeException"},{"error":"NumberFormatException"},{"error":"NumberFormatExc' - 'eption"},null],"America/New_York":[325,{"error":"DateTimeException"},355,{"error":"DateTimeExc' - 'eption"},{"error":"DateTimeException"},{"error":"DateTimeException"},1,1,1,1,{"error":"DateTim' - 'eException"},{"error":"DateTimeException"},1,1,1,1,1,{"error":"DateTimeException"},1,1,1,{"err' - 'or":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeException"},-719528,-' - '719162,{"error":"DateTimeException"},{"error":"DateTimeException"},{"error":"DateTimeException' - '"},1,{"error":"DateTimeException"},-1,{"error":"DateTimeException"},{"error":"NumberFormatExce' - 'ption"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"grammar STRING -> TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["197' - '0-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01' - '-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"' - '],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03' - ':04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.' - '124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24' - ':00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01' - '"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["' - '+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":' - '{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{"UTC":[{"millis":86' - '400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0' - ',"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nano' - 's":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParse' - 'Exception"},{"millis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":9744500' - '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTi' - 'meParseException"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172' - '800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mill' - 'is":983318400000,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException' - '"},{"error":"DateTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeP' - 'arseException"},{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"mill' - 'is":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"error":"D' - 'ateTimeParseException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},nu' - 'll],"Asia/Shanghai":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"Dat' - 'eTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"n' - 'anos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseEx' - 'ception"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"DateTimeP' - 'arseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":974' - '45123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"millis":1' - '72800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"},{"error"' - ':"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"nanos":0}' - ',{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621355968000' - '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0},{"error"' - ':"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"' - 'millis":-1,"nanos":0},{"error":"DateTimeParseException"},{"error":"NumberFormatException"},{"e' - 'rror":"NumberFormatException"},null],"America/New_York":[{"millis":86400000,"nanos":0},{"milli' - 's":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"Dat' - 'eTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,' - '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":974' - '40000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"Da' - 'teTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"mill' - 'is":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error' - '":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":' - '0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimePars' - 'eException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis"' - ':253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{' - '"error":"DateTimeParseException"},{"millis":-1,"nanos":0},{"error":"DateTimeParseException"},{' - '"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"grammar STRING -> TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["197' - '0-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],["1970-01-"],["1970-01' - '-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"],["1970-01-02 03:04"' - '],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04:05"],["1970-01-02 03' - ':04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 03:04:05.123T03:04:05.' - '124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.000"],["1970-01-02 24' - ':00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001-04-32"],["0000-01-01' - '"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970-01-02 03:04:05."],["' - '+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"name":"CAST","fieldRef":' - '{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{"UTC":[{"millis":86' - '400000,"nanos":0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0' - ',"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nano' - 's":0},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParse' - 'Exception"},{"millis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":9744500' - '0,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTi' - 'meParseException"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172' - '800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mill' - 'is":983318400000,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException' - '"},{"error":"DateTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeP' - 'arseException"},{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"mill' - 'is":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":999000},{"erro' - 'r":"DateTimeParseException"},{"error":"NumberFormatException"},{"error":"NumberFormatException' - '"},null],"Asia/Shanghai":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"error"' - ':"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"millis"' - ':0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTimePa' - 'rseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"millis' - '":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"mill' - 'is":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"},{"e' - 'rror":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"nano' - 's":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-6213559' - '6800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException' - '"},{"millis":-1,"nanos":999000},{"error":"DateTimeParseException"},{"error":"NumberFormatExcep' - 'tion"},{"error":"NumberFormatException"},null],"America/New_York":[{"millis":86400000,"nanos":' - '0},{"millis":86400000,"nanos":0},{"error":"DateTimeParseException"},{"millis":0,"nanos":0},{"e' - 'rror":"DateTimeParseException"},{"millis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis"' - ':97445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"m' - 'illis":97440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"' - 'error":"DateTimeParseException"},{"millis":97445123,"nanos":0},{"error":"DateTimeParseExceptio' - 'n"},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"millis":172800000,"nanos":' - '0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":98331840000' - '0,"nanos":0},{"millis":988588800000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Da' - 'teTimeParseException"},{"millis":-62135596800000,"nanos":0},{"error":"DateTimeParseException"}' - ',{"millis":253402300800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":97445000,"n' - 'anos":0},{"error":"DateTimeParseException"},{"millis":-1,"nanos":999000},{"error":"DateTimePar' - 'seException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"grammar STRING -> TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"ST' - 'RING"}],"rows":[["1970-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],[' - '"1970-01-"],["1970-01-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"' - '],["1970-01-02 03:04"],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04' - ':05"],["1970-01-02 03:04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 0' - '3:04:05.123T03:04:05.124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.' - '000"],["1970-01-02 24:00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001' - '-04-32"],["0000-01-01"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970' - '-01-02 03:04:05."],["+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"nam' - 'e":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3) WITH LOCAL T' - 'IME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"er' - 'ror":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"mil' - 'lis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTi' - 'meParseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"' - 'DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"mi' - 'llis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"' - 'millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"}' - ',{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"' - 'nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621' - '35596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0}' - ',{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseExcep' - 'tion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTim' - 'eParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000' - ',"nanos":0},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-288000' - '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":-28800000,"nanos":0},{"millis":6864' - '5000,"nanos":0},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Dat' - 'eTimeParseException"},{"millis":68640000,"nanos":0},{"error":"DateTimeParseException"},{"milli' - 's":68645000,"nanos":0},{"error":"DateTimeParseException"},{"millis":68645123,"nanos":0},{"erro' - 'r":"DateTimeParseException"},{"millis":144000000,"nanos":0},{"millis":144000000,"nanos":0},{"m' - 'illis":144000000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseExceptio' - 'n"},{"millis":983289600000,"nanos":0},{"millis":988560000000,"nanos":0},{"error":"DateTimePars' - 'eException"},{"error":"DateTimeParseException"},{"millis":-62135625943000,"nanos":0},{"error":' - '"DateTimeParseException"},{"millis":253402272000000,"nanos":0},{"error":"DateTimeParseExceptio' - 'n"},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' - 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' - 'TimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":104400' - '000,"nanos":0},{"error":"DateTimeParseException"},{"millis":18000000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":18000000,"nanos":0},{"millis":115445000,"nanos":0},{"millis":11' - '5445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mil' - 'lis":115440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,"nanos":0},{"' - 'error":"DateTimeParseException"},{"millis":115445123,"nanos":0},{"error":"DateTimeParseExcepti' - 'on"},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos"' - ':0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":9833364000' - '00,"nanos":0},{"millis":988603200000,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' - 'ateTimeParseException"},{"millis":-62135579038000,"nanos":0},{"error":"DateTimeParseException"' - '},{"millis":253402318800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,' - '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Dat' - 'eTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nu' - 'll]}}' - ), - json.loads( - '{"name":"grammar STRING -> TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"ST' - 'RING"}],"rows":[["1970-011-022"],["1970-0101-0202"],["1970-012-022"],["1970--"],["1970--02"],[' - '"1970-01-"],["1970-01-02 0303:0404:0505"],["1970-01-02 033:044:055"],["1970-01-02 030:044:055"' - '],["1970-01-02 03:04"],["1970-01-02T03:04"],["1970-01-02T03:04.1"],["1970-01-02 03:04:05T03:04' - ':05"],["1970-01-02 03:04:05T06:04:05"],["1970-01-02 03:04:05.123T03:04:05.123"],["1970-01-02 0' - '3:04:05.123T03:04:05.124"],["1970-01-02 24:00:00"],["1970-01-02T24:00"],["1970-01-02 24:00:00.' - '000"],["1970-01-02 24:00:00.001"],["1970-01-02 23:59:60"],["2001-02-30"],["2001-04-31"],["2001' - '-04-32"],["0000-01-01"],["0001-01-01"],["-0001-01-01"],["+10000-01-01"],["10000-01-01"],["1970' - '-01-02 03:04:05."],["+1"],["-1"],["1.0"],["\\u0661"],["\\uff11\\uff12"],[null]],"transform":{"nam' - 'e":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6) WITH LOCAL T' - 'IME ZONE"},"expected":{"UTC":[{"millis":86400000,"nanos":0},{"millis":86400000,"nanos":0},{"er' - 'ror":"DateTimeParseException"},{"millis":0,"nanos":0},{"error":"DateTimeParseException"},{"mil' - 'lis":0,"nanos":0},{"millis":97445000,"nanos":0},{"millis":97445000,"nanos":0},{"error":"DateTi' - 'meParseException"},{"error":"DateTimeParseException"},{"millis":97440000,"nanos":0},{"error":"' - 'DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseException"},{"mi' - 'llis":97445123,"nanos":0},{"error":"DateTimeParseException"},{"millis":172800000,"nanos":0},{"' - 'millis":172800000,"nanos":0},{"millis":172800000,"nanos":0},{"error":"DateTimeParseException"}' - ',{"error":"DateTimeParseException"},{"millis":983318400000,"nanos":0},{"millis":988588800000,"' - 'nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":-621' - '35596800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":253402300800000,"nanos":0}' - ',{"error":"DateTimeParseException"},{"millis":97445000,"nanos":0},{"error":"DateTimeParseExcep' - 'tion"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTim' - 'eParseException"},{"error":"DateTimeParseException"},null],"Asia/Shanghai":[{"millis":57600000' - ',"nanos":0},{"millis":57600000,"nanos":0},{"error":"DateTimeParseException"},{"millis":-288000' - '00,"nanos":0},{"error":"DateTimeParseException"},{"millis":-28800000,"nanos":0},{"millis":6864' - '5000,"nanos":0},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"Dat' - 'eTimeParseException"},{"millis":68640000,"nanos":0},{"error":"DateTimeParseException"},{"milli' - 's":68645000,"nanos":0},{"error":"DateTimeParseException"},{"millis":68645123,"nanos":0},{"erro' - 'r":"DateTimeParseException"},{"millis":144000000,"nanos":0},{"millis":144000000,"nanos":0},{"m' - 'illis":144000000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseExceptio' - 'n"},{"millis":983289600000,"nanos":0},{"millis":988560000000,"nanos":0},{"error":"DateTimePars' - 'eException"},{"error":"DateTimeParseException"},{"millis":-62135625943000,"nanos":0},{"error":' - '"DateTimeParseException"},{"millis":253402272000000,"nanos":0},{"error":"DateTimeParseExceptio' - 'n"},{"millis":68645000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseEx' - 'ception"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Date' - 'TimeParseException"},null],"America/New_York":[{"millis":104400000,"nanos":0},{"millis":104400' - '000,"nanos":0},{"error":"DateTimeParseException"},{"millis":18000000,"nanos":0},{"error":"Date' - 'TimeParseException"},{"millis":18000000,"nanos":0},{"millis":115445000,"nanos":0},{"millis":11' - '5445000,"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"mil' - 'lis":115440000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,"nanos":0},{"' - 'error":"DateTimeParseException"},{"millis":115445123,"nanos":0},{"error":"DateTimeParseExcepti' - 'on"},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos":0},{"millis":190800000,"nanos"' - ':0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"millis":9833364000' - '00,"nanos":0},{"millis":988603200000,"nanos":0},{"error":"DateTimeParseException"},{"error":"D' - 'ateTimeParseException"},{"millis":-62135579038000,"nanos":0},{"error":"DateTimeParseException"' - '},{"millis":253402318800000,"nanos":0},{"error":"DateTimeParseException"},{"millis":115445000,' - '"nanos":0},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},{"error":"Dat' - 'eTimeParseException"},{"error":"DateTimeParseException"},{"error":"DateTimeParseException"},nu' - 'll]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"ro' - 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' - '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":25' - '3402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337203685477580' - '7,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"type' - '":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:' - '01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00' - ':00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:00","1' - '970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59",' - '"2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.80' - '7"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","19' - '69-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-' - '0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}],"' - 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' - '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' - '253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854775' - '807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"ty' - 'pe":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' - '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T0' - '0:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00 "' - ',"1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","' - '2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"A' - 'merica/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-1' - '2-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01' - '-01T00:00 ","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854' - '775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' - '"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01' - 'T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T0' - '0:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1970-01' - '-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T' - '22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New_York"' - ':["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969' - '-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-' - '06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(3)"}],' - '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' - 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' - ':253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337203685477' - '5807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBLE"}' - ',"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' - '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01' - '-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:' - '00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:5' - '9:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12' - ':55.807"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:0' - '1","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:' - '00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036854' - '775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBLE' - '"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-0' - '1-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-0' - '1-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:0' - '0 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:' - '59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:1' - '2"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","' - '1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0' - '001-01-01T00:00 ","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(3' - ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' - 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' - 'llis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":9223372036' - '854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' - 'BLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970' - '-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-0' - '1-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1' - '970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-' - '11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New' - '_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59."' - ',"1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-17015' - '32-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' - '(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' - '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' - 'millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":92233720' - '36854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"D' - 'ECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001' - '","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.1' - '23","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"Asia/Shanghai":["' - '1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1' - '969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-17015' - '32-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970' - '-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+1' - '0000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' - 'MP(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' - ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' - '{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922337' - '2036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":' - '"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:0' - '0:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:' - '20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"Asia/Shanghai":["1' - '970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","196' - '9-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701' - '532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' - '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-0' - '1T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' - 'STAMP(3)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' - '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' - '],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000,"nanos":0}],[{"millis":922' - '3372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' - 'e":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00' - ':00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:' - '20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"Asia/Shanghai":["1970-0' - '1-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23' - ':59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"' - '],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12' - '-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T' - '00:00","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"ro' - 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' - '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":0,' - '"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"t' - 'ype":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' - '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' - '0:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' - '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' - '0:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' - '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-0' - '1T00:00:00.000123"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}],"' - 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' - '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' - '0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' - '"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' - '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T' - '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' - '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1' - '969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT' - '"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' - '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T' - '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","' - '1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."],"Am' - 'erica/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T2' - '3:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(6)"}],' - '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' - 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' - ':0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBL' - 'E"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' - '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' - '1-01T00:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' - '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' - '1-01T00:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' - '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' - '0-01-01T00:00:00.000123"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' - 'BLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","197' - '0-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-' - '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' - '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:' - '00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' - '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(6' - ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' - 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' - 'llis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"' - 'DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1' - '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-' - '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' - ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-1' - '2-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' - '(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' - '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' - 'millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type"' - ':"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.' - '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' - '0.123","1970-01-01T00:00:00.000123"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.' - '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' - '0.123","1970-01-01T00:00:00.000123"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:' - '00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:1' - '3:20.123","1970-01-01T00:00:00.000123"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' - 'MP(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' - ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' - '{"millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' - 'e":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T0' - '0:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:' - '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00."' - ',"1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","' - '1970-01-01T00:00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970' - '-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-0' - '1-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(6) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' - 'STAMP(6)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' - '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' - '],[{"millis":0,"nanos":123000}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","' - 'type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01' - 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' - '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","19' - '70-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-0' - '1-01T00:00:00."],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:' - '00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:0' - '0."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound INT -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"ro' - 'ws":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":' - '-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":0,' - '"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},"t' - 'ype":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:' - '00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-01T0' - '0:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T' - '00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-01-0' - '1T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' - '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' - '0-01-01T00:00:00.000123456"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound INT -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}],"' - 'rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis' - '":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":' - '0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT"},' - '"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-0' - '1T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T' - '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' - '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1' - '969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound INT -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"INT' - '"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' - '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T' - '00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","' - '1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."],"Am' - 'erica/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T2' - '3:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DOUBLE -> STRING","fields":[{"name":"v","type":"TIMESTAMP(9)"}],' - '"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"milli' - 's":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"millis"' - ':0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOUBL' - 'E"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-' - '01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","1970-0' - '1-01T00:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-' - '01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","197' - '0-01-01T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.001",' - '"1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123' - '","1970-01-01T00:00:00.000123456"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9)"}' - '],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"mil' - 'lis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"milli' - 's":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"DOU' - 'BLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T00:00:00.","197' - '0-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-' - '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T0' - '0:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:' - '00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:0' - '1 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v","type":"TIMESTAMP(9' - ')"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"' - 'millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"mi' - 'llis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"' - 'DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1' - '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-' - '01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' - ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00.' - '"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-1' - '2-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> STRING","fields":[{"name":"v","type":"TIMESTAMP' - '(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}],[' - '{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[{"' - 'millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type"' - ':"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.' - '001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:2' - '0.123","1970-01-01T00:00:00.000123456"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:' - '00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:1' - '3:20.123","1970-01-01T00:00:00.000123456"],"America/New_York":["1970-01-01T00:00","1970-01-01T' - '00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-1' - '4T22:13:20.123","1970-01-01T00:00:00.000123456"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name":"v","type":"TIMESTA' - 'MP(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":0}]' - ',[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}],[' - '{"millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' - 'e":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00 ","1970-01-01T0' - '0:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:' - '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00."' - ',"1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","' - '1970-01-01T00:00:00."],"America/New_York":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970' - '-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","1970-0' - '1-01T00:00:00."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(9) rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"name":"v","type":"TIME' - 'STAMP(9)"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0}],[{"millis":1000,"nanos":' - '0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"millis":1700000000123,"nanos":0}' - '],[{"millis":0,"nanos":123456}]],"transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","' - 'type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01T00:00","1970-01-01' - 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' - '13:20.","1970-01-01T00:00:00."],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","19' - '70-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-0' - '1-01T00:00:00."],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:' - '00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","1970-01-01T00:00:0' - '0."]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> STRING","fields":[{"name":"v","type"' - ':"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos":0' - '}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"milli' - 's":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200000' - ',"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRef"' - ':{"index":0,"name":"v","type":"INT"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:00","1' - '970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59",' - '"2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.80' - '7"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-' - '12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-000' - '1-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","1970-01-' - '01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-1' - '1-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> CHAR(20)","fields":[{"name":"v","typ' - 'e":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos"' - ':0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"mil' - 'lis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552000' - '00,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldRe' - 'f":{"index":0,"name":"v","type":"INT"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01T00:00' - ' ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:5' - '9 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12' - '"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969' - '-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-' - '01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970-01-01' - 'T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T2' - '2:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound INT -> VARCHAR(20)","fields":[{"name":"v","' - 'type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nan' - 'os":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"' - 'millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552' - '00000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":0,"name":"v","type":"INT"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970-01-01' - 'T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:' - '59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"],"A' - 'sia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:' - '59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00",' - '"-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01' - '-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-0' - '1T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> STRING","fields":[{"name":"v","ty' - 'pe":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nanos' - '":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"mi' - 'llis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62198755200' - '000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":0,"name":"v","type":"DOUBLE"},"type":"STRING"},"expected":{"UTC":["1970-01-01T00:' - '00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:5' - '9:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12' - ':55.807"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01",' - '"1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00"' - ',"-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01-01T00:00","19' - '70-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","' - '2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807' - '"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> CHAR(20)","fields":[{"name":"v","' - 'type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"nan' - 'os":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],[{"' - 'millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987552' - '00000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":0,"name":"v","type":"DOUBLE"},"type":"CHAR(20)"},"expected":{"UTC":["1970-01-01' - 'T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T2' - '3:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06' - 'T07:12"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 "' - ',"1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","' - '-0001-01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00 ","1970' - '-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-1' - '1-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DOUBLE -> VARCHAR(20)","fields":[{"name":"v' - '","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1,"' - 'nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}],' - '[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-621987' - '55200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST","f' - 'ieldRef":{"index":0,"name":"v","type":"DOUBLE"},"type":"VARCHAR(20)"},"expected":{"UTC":["1970' - '-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T' - '23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:1' - '2"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-' - '31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T0' - '0:00","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01T00:00:00.","1' - '970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+1000' - '0-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> STRING","fields":[{"name":' - '"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis":1' - ',"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":0}' - '],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-6219' - '8755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST",' - '"fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"STRING"},"expected":{"UTC":["' - '1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1' - '969-12-31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-17015' - '32-04-06T07:12:55.807"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.001","1970-01' - '-01T00:00:01","1969-12-31T23:59:59.999","1969-12-31T23:59:59","2023-11-14T22:13:20.123","+1000' - '0-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12:55.807"],"America/New_York":["1970-01' - '-01T00:00","1970-01-01T00:00:00.001","1970-01-01T00:00:01","1969-12-31T23:59:59.999","1969-12-' - '31T23:59:59","2023-11-14T22:13:20.123","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-0' - '6T07:12:55.807"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> CHAR(20)","fields":[{"name' - '":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"millis"' - ':1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nanos":' - '0}],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":-62' - '198755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"CAST' - '","fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"CHAR(20)"},"expected":{"UTC' - '":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59."' - ',"1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","' - '-1701532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00 ","1970-01-01T00:00:00.","1970-01' - '-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:59:59 ","2023-11-14T22:13:20.","+10000-01' - '-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00' - ':00 ","1970-01-01T00:00:00.","1970-01-01T00:00:01 ","1969-12-31T23:59:59.","1969-12-31T23:5' - '9:59 ","2023-11-14T22:13:20.","+10000-01-01T00:00 ","-0001-01-01T00:00 ","-1701532-04-06T07' - ':12"]}}' - ), - json.loads( - '{"name":"TIMESTAMP(3) WITH LOCAL TIME ZONE rebound DECIMAL(12,3) -> VARCHAR(20)","fields":[{"n' - 'ame":"v","type":"TIMESTAMP(3) WITH LOCAL TIME ZONE"}],"rows":[[{"millis":0,"nanos":0}],[{"mill' - 'is":1,"nanos":0}],[{"millis":1000,"nanos":0}],[{"millis":-1,"nanos":0}],[{"millis":-1000,"nano' - 's":0}],[{"millis":1700000000123,"nanos":0}],[{"millis":253402300800000,"nanos":0}],[{"millis":' - '-62198755200000,"nanos":0}],[{"millis":9223372036854775807,"nanos":0}]],"transform":{"name":"C' - 'AST","fieldRef":{"index":0,"name":"v","type":"DECIMAL(12,3)"},"type":"VARCHAR(20)"},"expected"' - ':{"UTC":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.' - '","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701' - '532-04-06T07:12"],"Asia/Shanghai":["1970-01-01T00:00","1970-01-01T00:00:00.","1970-01-01T00:00' - ':01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:13:20.","+10000-01-01T00:00",' - '"-0001-01-01T00:00","-1701532-04-06T07:12"],"America/New_York":["1970-01-01T00:00","1970-01-01' - 'T00:00:00.","1970-01-01T00:00:01","1969-12-31T23:59:59.","1969-12-31T23:59:59","2023-11-14T22:' - '13:20.","+10000-01-01T00:00","-0001-01-01T00:00","-1701532-04-06T07:12"]}}' - ), - json.loads( - '{"name":"timefull_STRING_to_TIMESTAMP(3)","fields":[{"name":"v","type":"STRING"}],"rows":[["19' - '70-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["1970-01-01T24:00"],["' - '+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]],"transform":{"name"' - ':"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(3)"},"expected":{' - '"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' - '":946684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos"' - ':0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"Asia/Shanghai' - '":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":94' - '6684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},' - '{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"America/New_York"' - ':[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":946' - '684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},{' - '"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timefull_STRING_to_TIMESTAMP(6)","fields":[{"name":"v","type":"STRING"}],"rows":[["19' - '70-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["1970-01-01T24:00"],["' - '+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]],"transform":{"name"' - ':"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMESTAMP(6)"},"expected":{' - '"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis' - '":946684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos"' - ':0},{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"Asia/Shanghai' - '":[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":94' - '6684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},' - '{"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null],"America/New_York"' - ':[{"millis":28857600000,"nanos":0},{"millis":0,"nanos":0},{"millis":0,"nanos":0},{"millis":946' - '684800000,"nanos":0},{"millis":86400000,"nanos":0},{"millis":-5336598346174303232,"nanos":0},{' - '"millis":1710037800000,"nanos":0},{"millis":1730597400000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timefull_STRING_to_TIMESTAMP(3) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"S' - 'TRING"}],"rows":[["1970-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["' - '1970-01-01T24:00"],["+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]' - '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMEST' - 'AMP(3) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,' - '"nanos":0},{"millis":0,"nanos":0},{"millis":946684800000,"nanos":0},{"millis":86400000,"nanos"' - ':0},{"millis":-5336598346174303232,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":173' - '0597400000,"nanos":0},null],"Asia/Shanghai":[{"millis":28828800000,"nanos":0},{"millis":-28800' - '000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":946656000000,"nanos":0},{"millis":5760' - '0000,"nanos":0},{"millis":-5336598346203103232,"nanos":0},{"millis":1710009000000,"nanos":0},{' - '"millis":1730568600000,"nanos":0},null],"America/New_York":[{"millis":28875600000,"nanos":0},{' - '"millis":18000000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":946702800000,"nanos":0},{' - '"millis":104400000,"nanos":0},{"millis":-5336598346156303232,"nanos":0},{"millis":171005580000' - '0,"nanos":0},{"millis":1730611800000,"nanos":0},null]}}' - ), - json.loads( - '{"name":"timefull_STRING_to_TIMESTAMP(6) WITH LOCAL TIME ZONE","fields":[{"name":"v","type":"S' - 'TRING"}],"rows":[["1970-12-T24:00"],["1970-01- 24:00:00"],["1970--T24:00"],["2000--T24:00"],["' - '1970-01-01T24:00"],["+999999999-01-01"],["2024-03-10 02:30:00"],["2024-11-03 01:30:00"],[null]' - '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TIMEST' - 'AMP(6) WITH LOCAL TIME ZONE"},"expected":{"UTC":[{"millis":28857600000,"nanos":0},{"millis":0,' - '"nanos":0},{"millis":0,"nanos":0},{"millis":946684800000,"nanos":0},{"millis":86400000,"nanos"' - ':0},{"millis":-5336598346174303232,"nanos":0},{"millis":1710037800000,"nanos":0},{"millis":173' - '0597400000,"nanos":0},null],"Asia/Shanghai":[{"millis":28828800000,"nanos":0},{"millis":-28800' - '000,"nanos":0},{"millis":-28800000,"nanos":0},{"millis":946656000000,"nanos":0},{"millis":5760' - '0000,"nanos":0},{"millis":-5336598346203103232,"nanos":0},{"millis":1710009000000,"nanos":0},{' - '"millis":1730568600000,"nanos":0},null],"America/New_York":[{"millis":28875600000,"nanos":0},{' - '"millis":18000000,"nanos":0},{"millis":18000000,"nanos":0},{"millis":946702800000,"nanos":0},{' - '"millis":104400000,"nanos":0},{"millis":-5336598346156303232,"nanos":0},{"millis":171005580000' - '0,"nanos":0},{"millis":1730611800000,"nanos":0},null]}}' - ), -] - - -def source_array(values, type_): - if pa.types.is_floating(type_): - values = [None if v is None else float(v) for v in values] - elif pa.types.is_binary(type_): - values = [None if v is None else bytes(v) for v in values] - elif pa.types.is_decimal(type_): - values = [None if v is None else Decimal(v) for v in values] - elif pa.types.is_timestamp(type_): - quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[type_.unit] - converted = [] - for v in values: - if v is None: - converted.append(None) - continue - millis = v['millis'] if isinstance(v, dict) else v - nanos = v.get('nanos', 0) if isinstance(v, dict) else 0 - full = millis * 1000000 + nanos - if full % quantum or not -(1 << 63) <= full // quantum < (1 << 63): - raise OverflowError('Java timestamp cannot be stored in the Arrow source') - converted.append(full // quantum) - values = converted - return pa.array(values, type=type_) - - -def external(array): - type_ = array.type - if pa.types.is_timestamp(type_): - value = array.cast(pa.int64()).to_pylist()[0] - if value is None: - return None - full = value * {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[type_.unit] - return {'millis': full // 1000000, 'nanos': full % 1000000} - if pa.types.is_date(type_) or pa.types.is_time(type_): - return array.cast(pa.int32()).to_pylist()[0] - value = array.to_pylist()[0] - if isinstance(value, Decimal): - return format(value, 'f') - if isinstance(value, float) and math.isinf(value): - return 'Infinity' if value > 0 else '-Infinity' - return list(value) if isinstance(value, bytes) else value - - -def unrepresentable(expected, target): - if not pa.types.is_timestamp(target) or not isinstance(expected, dict) or 'millis' not in expected: - return False - full = expected['millis'] * 1000000 + expected['nanos'] - quantum = {'s': 1000000000, 'ms': 1000000, 'us': 1000, 'ns': 1}[target.unit] - return bool(full % quantum) or not -(1 << 63) <= full // quantum < (1 << 63) - - -def invalid_utf8(value, source): - if value is None or not pa.types.is_binary(source): - return False - try: - bytes(value).decode('utf8') - except UnicodeDecodeError: - return True - return False - - -@pytest.mark.parametrize('zone', ['UTC', 'Asia/Shanghai', 'America/New_York']) -@pytest.mark.parametrize('case', JAVA_CASES, ids=lambda case: case['name']) -def test_scalar_cast_completion_matches_actual_java(case, zone, monkeypatch): - monkeypatch.setenv('TZ', zone) - time.tzset() - try: - source = _paimon_type_to_arrow(case['fields'][0]['type']) - target = _paimon_type_to_arrow(case['transform']['type']) - for row, expected in zip(case['rows'], case['expected'][zone]): - try: - array = source_array([row[0]], source) - except OverflowError: - continue - batch = pa.RecordBatch.from_pydict({'v': array}) - error = (isinstance(expected, dict) and 'error' in expected - or unrepresentable(expected, target) or invalid_utf8(row[0], source)) - if error: - with pytest.raises((ValueError, TypeError, OverflowError, pa.ArrowException)): - _apply_predicate_transform(case['transform'], batch) - else: - assert external(_apply_predicate_transform(case['transform'], batch)) == expected, row - finally: - monkeypatch.undo() - time.tzset() - - -@pytest.mark.parametrize('type_', ['VARCHAR(0)', 'CHAR(2147483648)', 'BINARY(0)', 'VARBINARY(2147483648)']) -@pytest.mark.parametrize('values', [[], [None]]) -def test_invalid_cast_width_is_validated_before_null_short_circuit(type_, values): - batch = pa.RecordBatch.from_pydict({'v': pa.array(values, type=pa.string())}) - rule = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': type_} - with pytest.raises(ValueError, match='Cast width'): - _apply_predicate_transform(rule, batch) - - -@pytest.mark.parametrize('suffix', [' 24::00', 'T24::00', 'T24::00.', ' 24:00:.', 'T24:00:.000']) -def test_smart_timestamp_rejects_partial_24_hour_time(suffix): - batch = pa.RecordBatch.from_pydict({'v': ['1970-01-02' + suffix]}) - rule = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'TIMESTAMP(3)'} - with pytest.raises(ValueError): - _apply_predicate_transform(rule, batch) - - -def test_existing_python_java_capability_matrix_is_complete(): - # Independent 20 by 20 matrix from the old Python path and actual Java. - from pypaimon.casting.cast_executor import supports_cast - types = [ - 'BOOLEAN', - 'TINYINT', - 'SMALLINT', - 'INT', - 'BIGINT', - 'FLOAT', - 'DOUBLE', - 'DECIMAL(12,3)', - 'STRING', - 'CHAR(8)', - 'VARCHAR(8)', - 'BINARY(8)', - 'VARBINARY(32)', - 'BYTES', - 'DATE', - 'TIME(3)', - 'TIMESTAMP(3)', - 'TIMESTAMP(6)', - 'TIMESTAMP(3) WITH LOCAL TIME ZONE', - 'TIMESTAMP(6) WITH LOCAL TIME ZONE', - ] - supported = [ - '01111110111000000000', - '11111111111000000000', - '11111111111000000000', - '11111111111000000000', - '11111111111000001111', - '01111111111000000000', - '01111111111000000000', - '01111111111000000000', - '11111111111111101111', - '11111111111111101111', - '11111111111111101111', - '00000000111111000000', - '00000000111111000000', - '00000000111111000000', - '00000000111000001111', - '00000000111000000000', - '00001000111000111111', - '00001000111000111111', - '00001000111000111111', - '00001000111000111111', - ] - for source, expected in zip(types, supported): - for target, expected in zip(types, expected): - actual = supports_cast(_paimon_type_to_arrow(source), _paimon_type_to_arrow(target)) - assert actual == (expected == '1'), (source, target) - - -@pytest.mark.parametrize('type_', ['DECIMAL(4,-1)', 'DECIMAL(4,5)', 'DECIMAL(39,0)', - 'TIMESTAMP(10)', 'TIMESTAMP(3) WITH LOCAL TIME ZONE GARBAGE', - 'CHAR(+1)', 'CHAR(١)', 'CHAR(1_0)', 'TIMESTAMP(١)', 'DECIMAL(٤,٢)']) -def test_invalid_java_cast_types_are_rejected_for_null_input(type_): - batch = pa.RecordBatch.from_pydict({'v': pa.array([None], type=pa.string())}) - with pytest.raises(ValueError): - _apply_predicate_transform({'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': type_}, - batch) diff --git a/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py b/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py deleted file mode 100644 index 6ee506bd02e3..000000000000 --- a/paimon-python/pypaimon/tests/authorization_numeric_cast_test.py +++ /dev/null @@ -1,569 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Java numeric REST CAST semantics for authorization and masking.""" - -import json -from decimal import Decimal - -import pyarrow as pa -import pytest - -from pypaimon.common.predicate_json_parser import ( - _apply_predicate_transform, _paimon_type_to_arrow, parse_predicate_to_batch_filter, -) - - -def _cast(source_type, target_type, array): - return _apply_predicate_transform({ - 'name': 'CAST', 'fieldRef': {'name': 'source', 'type': source_type}, 'type': target_type, - }, pa.RecordBatch.from_pydict({'source': array})) - - -def test_floating_narrowing_saturates_before_byte_conversion(): - source = pa.array([128.9, -129.9, 1e30, -1e30, None], type=pa.float64()) - assert _cast('DOUBLE', 'TINYINT', source).to_pylist() == [-128, 127, -1, 0, None] - - -def test_numeric_decimal_rounds_half_up_and_returns_null_on_precision_overflow(): - source = pa.array([1.005, -1.005, 2.675, 999.995, None], type=pa.float64()) - assert _cast('DOUBLE', 'DECIMAL(5,2)', source).to_pylist() == [ - Decimal('1.01'), Decimal('-1.01'), Decimal('2.68'), None, None] - - -# Generated with Java CastExecutors / PredicateRemapper on Paimon master -# 8de6fdbda9. Includes the decimal compact/wide and original-executor paths; -# the Double-to-Decimal text was additionally verified on Java 8. -JAVA_CASES = [ - json.loads( - '{"name":"BIGINT_to_TINYINT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[922337' - '2036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[42949672' - '97],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT' - '"},"type":"TINYINT"},"expected":{"name":"BIGINT_to_TINYINT","results":[0,-1,-128,-1,0,127,-1,0,-1,0,0,0,1,' - '1,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_SMALLINT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[92233' - '72036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967' - '297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGIN' - 'T"},"type":"SMALLINT"},"expected":{"name":"BIGINT_to_SMALLINT","results":[0,-1,128,255,256,-129,-257,-3276' - '8,-1,0,0,0,1,1,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_INT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9223372036' - '854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967297],' - '[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"},"' - 'type":"INT"},"expected":{"name":"BIGINT_to_INT","results":[0,-1,128,255,256,-129,-257,32768,65535,65536,-2' - '147483648,0,1,536870913,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_FLOAT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[92233720' - '36854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[4294967297' - '],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"}' - ',"type":"FLOAT"},"expected":{"name":"BIGINT_to_FLOAT","results":[-9.223372036854776e+18,9.223372036854776e' - '+18,128.0,255.0,256.0,-129.0,-257.0,32768.0,65535.0,65536.0,2147483648.0,4294967296.0,4294967296.0,9007200' - '328482816.0,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_DOUBLE","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9223372' - '036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429496729' - '7],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BIGINT"' - '},"type":"DOUBLE"},"expected":{"name":"BIGINT_to_DOUBLE","results":[-9.223372036854776e+18,9.2233720368547' - '76e+18,128.0,255.0,256.0,-129.0,-257.0,32768.0,65535.0,65536.0,2147483648.0,4294967296.0,4294967297.0,9007' - '199791611904.0,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_DECIMAL(5,0)","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9' - '223372036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429' - '4967297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"B' - 'IGINT"},"type":"DECIMAL(5,0)"},"expected":{"name":"BIGINT_to_DECIMAL(5,0)","results":[null,null,"128","255' - '","256","-129","-257","32768","65535","65536",null,null,null,null,null]}}' - ), - json.loads( - '{"name":"BIGINT_to_DECIMAL(4,2)","fields":[{"name":"v","type":"BIGINT"}],"rows":[[-9223372036854775808],[9' - '223372036854775807],[128],[255],[256],[-129],[-257],[32768],[65535],[65536],[2147483648],[4294967296],[429' - '4967297],[9007199791611905],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"B' - 'IGINT"},"type":"DECIMAL(4,2)"},"expected":{"name":"BIGINT_to_DECIMAL(4,2)","results":[null,null,null,null,' - 'null,null,null,null,null,null,null,null,null,null,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_TINYINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-1' - '29.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fi' - 'eldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"TINYINT"},"expected":{"name":"FLOAT_to_TINYINT","re' - 'sults":[1,-1,127,-128,127,-1,-1,-1,-1,0,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_SMALLINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-' - '129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","f' - 'ieldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"SMALLINT"},"expected":{"name":"FLOAT_to_SMALLINT",' - '"results":[1,-1,127,128,-129,-1,-1,-1,-1,0,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_INT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-129.9' - '],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fieldR' - 'ef":{"index":99,"name":"v","type":"FLOAT"},"type":"INT"},"expected":{"name":"FLOAT_to_INT","results":[1,-1' - ',127,128,-129,2147483647,2147483647,2147483647,2147483647,-2147483648,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_BIGINT","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-12' - '9.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fie' - 'ldRef":{"index":99,"name":"v","type":"FLOAT"},"type":"BIGINT"},"expected":{"name":"FLOAT_to_BIGINT","resul' - 'ts":[1,-1,127,128,-129,2147483648,2147483648,4294967296,9223372036854775807,-9223372036854775808,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_DECIMAL(4,2)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],[-' - '2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":99' - ',"name":"v","type":"FLOAT"},"type":"DECIMAL(4,2)"},"expected":{"name":"FLOAT_to_DECIMAL(4,2)","results":["' - '1.00","-1.00","2.67","-2.67","99.99",null,null,null,null,null]}}' - ), - json.loads( - '{"name":"FLOAT_to_DECIMAL(38,0)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],[' - '-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":9' - '9,"name":"v","type":"FLOAT"},"type":"DECIMAL(38,0)"},"expected":{"name":"FLOAT_to_DECIMAL(38,0)","results"' - ':["1","-1","3","-3","100","100","100000002004087730000","99999997781963080000000","10000000150474662000000' - '00000000",null]}}' - ), - json.loads( - '{"name":"FLOAT_to_DECIMAL(38,18)","fields":[{"name":"v","type":"FLOAT"}],"rows":[[1.005],[-1.005],[2.675],' - '[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":' - '99,"name":"v","type":"FLOAT"},"type":"DECIMAL(38,18)"},"expected":{"name":"FLOAT_to_DECIMAL(38,18)","resul' - 'ts":["1.004999995231628400","-1.004999995231628400","2.674999952316284000","-2.674999952316284000","99.994' - '003295898440000","99.995002746582030000",null,null,null,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_TINYINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[' - '-129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","' - 'fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"TINYINT"},"expected":{"name":"DOUBLE_to_TINYINT"' - ',"results":[1,-1,127,-128,127,-1,-1,-1,-1,0,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_SMALLINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],' - '[-129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST",' - '"fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"SMALLINT"},"expected":{"name":"DOUBLE_to_SMALLI' - 'NT","results":[1,-1,127,128,-129,-1,-1,-1,-1,0,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_INT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-129' - '.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","fiel' - 'dRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"INT"},"expected":{"name":"DOUBLE_to_INT","results":[' - '1,-1,127,128,-129,2147483647,2147483647,2147483647,2147483647,-2147483648,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_BIGINT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[-1.9],[127.9],[128.1],[-' - '129.9],[2147483647.0],[2147483648.5],[4294967297.0],[1e+30],[-1e+30],[null]],"transform":{"name":"CAST","f' - 'ieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"BIGINT"},"expected":{"name":"DOUBLE_to_BIGINT","r' - 'esults":[1,-1,127,128,-129,2147483647,2147483648,4294967297,9223372036854775807,-9223372036854775808,null]' - '}}' - ), - json.loads( - '{"name":"DOUBLE_to_DECIMAL(4,2)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675],' - '[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index":' - '99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(4,2)"},"expected":{"name":"DOUBLE_to_DECIMAL(4,2)","results' - '":["1.01","-1.01","2.68","-2.68","99.99",null,null,null,null,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_DECIMAL(38,0)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675]' - ',[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index"' - ':99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(38,0)"},"expected":{"name":"DOUBLE_to_DECIMAL(38,0)","resu' - 'lts":["1","-1","3","-3","100","100","100000000000000000000","99999999999999990000000","1000000000000000000' - '000000000000",null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_DECIMAL(38,18)","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.005],[-1.005],[2.675' - '],[-2.675],[99.994],[99.995],[1e+20],[1e+23],[1e+30],[null]],"transform":{"name":"CAST","fieldRef":{"index' - '":99,"name":"v","type":"DOUBLE"},"type":"DECIMAL(38,18)"},"expected":{"name":"DOUBLE_to_DECIMAL(38,18)","r' - 'esults":["1.005000000000000000","-1.005000000000000000","2.675000000000000000","-2.675000000000000000","99' - '.994000000000000000","99.995000000000000000",null,null,null,null]}}' - ), - json.loads( - '{"name":"INT_to_DOUBLE","fields":[{"name":"v","type":"INT"}],"rows":[[-2147483648],[2147483647],[1],[null]' - '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"DOUBLE"},"expected":{' - '"name":"INT_to_DOUBLE","results":[-2147483648.0,2147483647.0,1.0,null]}}' - ), - json.loads( - '{"name":"INT_to_FLOAT","fields":[{"name":"v","type":"INT"}],"rows":[[-2147483648],[2147483647],[16777217],' - '[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"FLOAT"},"expect' - 'ed":{"name":"INT_to_FLOAT","results":[-2147483648.0,2147483648.0,16777216.0,null]}}' - ), - json.loads( - '{"name":"BOOLEAN_to_TINYINT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"tran' - 'sform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"TINYINT"},"expected":{"n' - 'ame":"BOOLEAN_to_TINYINT","results":[1,0,null]}}' - ), - json.loads( - '{"name":"BOOLEAN_to_INT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"INT"},"expected":{"name":"BO' - 'OLEAN_to_INT","results":[1,0,null]}}' - ), - json.loads( - '{"name":"BOOLEAN_to_BIGINT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"trans' - 'form":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"BIGINT"},"expected":{"nam' - 'e":"BOOLEAN_to_BIGINT","results":[1,0,null]}}' - ), - json.loads( - '{"name":"BOOLEAN_to_FLOAT","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"transf' - 'orm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"FLOAT"},"expected":{"name"' - ':"BOOLEAN_to_FLOAT","results":[1.0,0.0,null]}}' - ), - json.loads( - '{"name":"BOOLEAN_to_DOUBLE","fields":[{"name":"v","type":"BOOLEAN"}],"rows":[[true],[false],[null]],"trans' - 'form":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"DOUBLE"},"expected":{"nam' - 'e":"BOOLEAN_to_DOUBLE","results":[1.0,0.0,null]}}' - ), - json.loads( - '{"name":"STRING_to_TINYINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],' - '["1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],[' - '"128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-92233720368' - '54775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[nu' - 'll]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"TINYINT"},"expe' - 'cted":{"name":"STRING_to_TINYINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatExcep' - 'tion"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberFo' - 'rmatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormat' - 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExce' - 'ption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' - 'n"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},' - '{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' - 'ror":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error"' - ':"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_SMALLINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"]' - ',["1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],' - '["128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-9223372036' - '854775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[n' - 'ull]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"SMALLINT"},"ex' - 'pected":{"name":"STRING_to_SMALLINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatEx' - 'ception"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"Numbe' - 'rFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFor' - 'matException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatE' - 'xception"},{"error":"NumberFormatException"},128,-129,{"error":"NumberFormatException"},{"error":"NumberFo' - 'rmatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormat' - 'Exception"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExce' - 'ption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_INT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],["1.' - '"],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],["128' - '"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-922337203685477' - '5809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[null]]' - ',"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"INT"},"expected":{"' - 'name":"STRING_to_INT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"err' - 'or":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' - 'n"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},' - '{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"er' - 'ror":"NumberFormatException"},128,-129,32768,-32769,{"error":"NumberFormatException"},{"error":"NumberForm' - 'atException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},2147483647,-2147483648,{' - '"error":"NumberFormatException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_BIGINT","fields":[{"name":"v","type":"STRING"}],"rows":[[""],["+"],["-"],["."],[".5"],[' - '"1."],["1.99"],["+1.99"],["-1.99"],[" 1"],["1 "],["1e3"],["1.2.3"],["1.a"],["1"],["٢"],["1_0"],["0x10"],["' - '128"],["-129"],["32768"],["-32769"],["2147483648"],["-2147483649"],["9223372036854775808"],["-922337203685' - '4775809"],["2147483647.99"],["-2147483648.99"],["9223372036854775807.99"],["-9223372036854775808.99"],[nul' - 'l]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"BIGINT"},"expect' - 'ed":{"name":"STRING_to_BIGINT","results":[{"error":"NumberFormatException"},{"error":"NumberFormatExceptio' - 'n"},{"error":"NumberFormatException"},0,0,1,1,1,-1,{"error":"NumberFormatException"},{"error":"NumberForma' - 'tException"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExc' - 'eption"},{"error":"NumberFormatException"},{"error":"NumberFormatException"},{"error":"NumberFormatExcepti' - 'on"},{"error":"NumberFormatException"},128,-129,32768,-32769,2147483648,-2147483649,{"error":"NumberFormat' - 'Exception"},{"error":"NumberFormatException"},2147483647,-2147483648,9223372036854775807,-9223372036854775' - '808,null]}}' - ), - json.loads( - '{"name":"STRING_to_BOOLEAN","fields":[{"name":"v","type":"STRING"}],"rows":[["t"],["TRUE"],["TrUe"],["y"],' - '["YeS"],["1"],["f"],["FALSE"],["FaLsE"],["n"],["No"],["0"],[" true"],["true "],["\\ttrue"],["on"],["off"],' - '["2"],[""],["1.0"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"' - 'type":"BOOLEAN"},"expected":{"name":"STRING_to_BOOLEAN","results":[true,true,true,true,true,true,false,fal' - 'se,false,false,false,false,{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeExce' - 'ption"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"RuntimeException"},{"error":"R' - 'untimeException"},{"error":"RuntimeException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_DECIMAL(4,2)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["99' - '.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005 "' - '],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","t' - 'ype":"STRING"},"type":"DECIMAL(4,2)"},"expected":{"name":"STRING_to_DECIMAL(4,2)","results":["1.01","-1.01' - '","99.99",null,null,null,null,"0.00","0.50","1.00","1.01",{"error":"NumberFormatException"},{"error":"Numb' - 'erFormatException"},{"error":"NumberFormatException"},"12.34","12.34",{"error":"NumberFormatException"},{"' - 'error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_DECIMAL(38,0)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["9' - '9.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005 ' - '"],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","' - 'type":"STRING"},"type":"DECIMAL(38,0)"},"expected":{"name":"STRING_to_DECIMAL(38,0)","results":["1","-1","' - '100","100","9999","1000","1000","0","1","1","1",{"error":"NumberFormatException"},{"error":"NumberFormatEx' - 'ception"},{"error":"NumberFormatException"},"12","12",{"error":"NumberFormatException"},{"error":"NumberFo' - 'rmatException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_DECIMAL(38,18)","fields":[{"name":"v","type":"STRING"}],"rows":[["1.005"],["-1.005"],["' - '99.994"],["99.995"],["9999"],["1e3"],["1E+3"],["1E-3"],[".5"],["1."],["+1.005"],["1_0"],[" 1.005"],["1.005' - ' "],["12.34"],["١٢.٣٤"],["bad"],[""],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v",' - '"type":"STRING"},"type":"DECIMAL(38,18)"},"expected":{"name":"STRING_to_DECIMAL(38,18)","results":["1.0050' - '00000000000000","-1.005000000000000000","99.994000000000000000","99.995000000000000000","9999.000000000000' - '000000","1000.000000000000000000","1000.000000000000000000","0.001000000000000000","0.500000000000000000",' - '"1.000000000000000000","1.005000000000000000",{"error":"NumberFormatException"},{"error":"NumberFormatExce' - 'ption"},{"error":"NumberFormatException"},"12.340000000000000000","12.340000000000000000",{"error":"Number' - 'FormatException"},{"error":"NumberFormatException"},null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_TINYINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.9' - '99"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["18446744073709' - '551617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"i' - 'ndex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"TINYINT"},"expected":{"name":"DECIMAL(38,3)_to_TINYINT' - '","results":[1,-1,127,-128,0,0,0,1,-1,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_SMALLINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.' - '999"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["1844674407370' - '9551617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"' - 'index":99,"name":"v","type":"DECIMAL(38,3)"},"type":"SMALLINT"},"expected":{"name":"DECIMAL(38,3)_to_SMALL' - 'INT","results":[1,-1,127,128,-32768,0,0,1,-1,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_INT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.999"]' - ',["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095516' - '17.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"index' - '":99,"name":"v","type":"DECIMAL(38,3)"},"type":"INT"},"expected":{"name":"DECIMAL(38,3)_to_INT","results":' - '[1,-1,127,128,32768,-2147483648,0,1,-1,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_BIGINT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.99' - '9"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095' - '51617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"in' - 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"BIGINT"},"expected":{"name":"DECIMAL(38,3)_to_BIGINT","' - 'results":[1,-1,127,128,32768,2147483648,-9223372036854775808,1,3136633892082024447,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_FLOAT","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.999' - '"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["1844674407370955' - '1617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"ind' - 'ex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(38,3)_to_FLOAT","res' - 'ults":[1.9989999532699585,-1.9989999532699585,127.9990005493164,128.99899291992188,32769.0,2147483648.0,9.' - '223372036854776e+18,1.8446744073709552e+19,1.0000000409184788e+35,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_DOUBLE","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.999"],["-1.99' - '9"],["127.999"],["128.999"],["32768.999"],["2147483648.999"],["9223372036854775808.999"],["184467440737095' - '51617.999"],["99999999999999999999999999999999999.999"],[null]],"transform":{"name":"CAST","fieldRef":{"in' - 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(38,3)_to_DOUBLE","' - 'results":[1.999,-1.999,127.999,128.999,32768.999,2147483648.999,9.223372036854776e+18,1.8446744073709552e+' - '19,1e+35,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_DECIMAL(4,2)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"],[' - '"-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"in' - 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(4,2)"},"expected":{"name":"DECIMAL(38,3)_to_DEC' - 'IMAL(4,2)","results":["1.01","-1.01","99.99",null,null,null,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_DECIMAL(3,0)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"],[' - '"-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"in' - 'dex":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(3,0)"},"expected":{"name":"DECIMAL(38,3)_to_DEC' - 'IMAL(3,0)","results":["1","-1","100","100","999",null,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,3)_to_DECIMAL(38,10)","fields":[{"name":"v","type":"DECIMAL(38,3)"}],"rows":[["1.005"]' - ',["-1.005"],["99.994"],["99.995"],["999.499"],["999.500"],[null]],"transform":{"name":"CAST","fieldRef":{"' - 'index":99,"name":"v","type":"DECIMAL(38,3)"},"type":"DECIMAL(38,10)"},"expected":{"name":"DECIMAL(38,3)_to' - '_DECIMAL(38,10)","results":["1.0050000000","-1.0050000000","99.9940000000","99.9950000000","999.4990000000' - '","999.5000000000",null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,10)_to_STRING","fields":[{"name":"v","type":"DECIMAL(38,10)"}],"rows":[["0.0000000123"' - '],["-0.0000000123"],["0.0000000000"],["10000000000000000000000.0000000000"],[null]],"transform":{"name":"C' - 'AST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(38,10)"},"type":"STRING"},"expected":{"name":"DECIM' - 'AL(38,10)_to_STRING","results":["0.0000000123","-0.0000000123","0.0000000000","10000000000000000000000.000' - '0000000",null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,10)_to_VARCHAR(3)","fields":[{"name":"v","type":"DECIMAL(38,10)"}],"rows":[["0.0000000' - '123"],["-0.0000000123"],["0.0000000000"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":' - '"v","type":"DECIMAL(38,10)"},"type":"VARCHAR(3)"},"expected":{"name":"DECIMAL(38,10)_to_VARCHAR(3)","resul' - 'ts":["0.0","-0.","0.0",null]}}' - ), - json.loads( - '{"name":"BIGINT_to_TINYINT_stored_INT","fields":[{"name":"v","type":"BIGINT"}],"rows":[[4294967297],[null]' - '],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"TINYINT"},"expected":' - '{"name":"BIGINT_to_TINYINT_stored_INT","results":[1,null]}}' - ), - json.loads( - '{"name":"DOUBLE_to_DECIMAL(4,2)_stored_INT","fields":[{"name":"v","type":"DOUBLE"}],"rows":[[1.9],[null]],' - '"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"DECIMAL(4,2)"},"expecte' - 'd":{"name":"DOUBLE_to_DECIMAL(4,2)_stored_INT","results":["1.00",null]}}' - ), - json.loads( - '{"name":"BIGINT_to_DECIMAL(38,0)_stored_DOUBLE","fields":[{"name":"v","type":"BIGINT"}],"rows":[[900719925' - '4740993],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DOUBLE"},"type":"DEC' - 'IMAL(38,0)"},"expected":{"name":"BIGINT_to_DECIMAL(38,0)_stored_DOUBLE","results":["9007199254740992",null' - ']}}' - ), - json.loads( - '{"name":"DECIMAL(12,3)_to_INT_stored_INT","fields":[{"name":"v","type":"DECIMAL(12,3)"}],"rows":[["1.999"]' - ',[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"INT"},"expecte' - 'd":{"name":"DECIMAL(12,3)_to_INT_stored_INT","results":[{"error":"ClassCastException"},null]}}' - ), - json.loads( - '{"name":"INT_to_INT_stored_DECIMAL(12,3)","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transf' - 'orm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(12,3)"},"type":"INT"},"expected":{"n' - 'ame":"INT_to_INT_stored_DECIMAL(12,3)","results":[{"error":"ClassCastException"},null]}}' - ), - json.loads( - '{"name":"INT_to_INT_stored_BOOLEAN","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transform":{' - '"name":"CAST","fieldRef":{"index":99,"name":"v","type":"BOOLEAN"},"type":"INT"},"expected":{"name":"INT_to' - '_INT_stored_BOOLEAN","results":[{"error":"ClassCastException"},null]}}' - ), - json.loads( - '{"name":"INT_to_INT_stored_STRING","fields":[{"name":"v","type":"INT"}],"rows":[[1],[null]],"transform":{"' - 'name":"CAST","fieldRef":{"index":99,"name":"v","type":"STRING"},"type":"INT"},"expected":{"name":"INT_to_I' - 'NT_stored_STRING","results":[{"error":"ClassCastException"},null]}}' - ), - json.loads( - '{"name":"STRING_to_INT_stored_INT","fields":[{"name":"v","type":"STRING"}],"rows":[["1"],[null]],"transfor' - 'm":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"INT"},"type":"INT"},"expected":{"name":"STRING' - '_to_INT_stored_INT","results":[{"error":"ClassCastException"},null]}}' - ), - json.loads( - '{"name":"DECIMAL(18,4)_to_DECIMAL(4,2)_stored_DECIMAL(12,3)","fields":[{"name":"v","type":"DECIMAL(18,4)"}' - '],"rows":[["1.0050"],[null]],"transform":{"name":"CAST","fieldRef":{"index":99,"name":"v","type":"DECIMAL(' - '12,3)"},"type":"DECIMAL(4,2)"},"expected":{"name":"DECIMAL(18,4)_to_DECIMAL(4,2)_stored_DECIMAL(12,3)","re' - 'sults":["1.01",null]}}' - ), - json.loads( - '{"name":"short_circuit_string_int_AND","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],' - '"rows":[[0,"bad"],[1,"1.9"],[2,null]],"predicate":{"kind":"COMPOUND","function":"AND","children":[{"kind":' - '"LEAF","transform":{"name":"FIELD_REF","fieldRef":{"index":0,"name":"id","type":"INT"}},"function":"EQUAL"' - ',"literals":[1]},{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING' - '"},"type":"INT"},"function":"EQUAL","literals":[1]}]},"expected":{"name":"short_circuit_string_int_AND","r' - 'esults":[false,true,false]}}' - ), - json.loads( - '{"name":"short_circuit_string_int_OR","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],"' - 'rows":[[0,"bad"],[1,"1.9"],[2,null]],"predicate":{"kind":"COMPOUND","function":"OR","children":[{"kind":"L' - 'EAF","transform":{"name":"FIELD_REF","fieldRef":{"index":0,"name":"id","type":"INT"}},"function":"EQUAL","' - 'literals":[1]},{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING"}' - ',"type":"INT"},"function":"EQUAL","literals":[1]}]},"expected":{"name":"short_circuit_string_int_OR","resu' - 'lts":[{"error":"NumberFormatException"},true,false]}}' - ), - json.loads( - '{"name":"separate_string_int_filters","fields":[{"name":"id","type":"INT"},{"name":"v","type":"STRING"}],"' - 'rows":[[0,"bad"],[1,"1.9"],[2,null]],"filters":[{"kind":"LEAF","transform":{"name":"FIELD_REF","fieldRef":' - '{"index":0,"name":"id","type":"INT"}},"function":"EQUAL","literals":[1]},{"kind":"LEAF","transform":{"name' - '":"CAST","fieldRef":{"index":1,"name":"v","type":"STRING"},"type":"INT"},"function":"EQUAL","literals":[1]' - '}],"expected":{"name":"separate_string_int_filters","results":[false,true,false]}}' - ), - json.loads( - '{"name":"bad_cast_before_function_TRUE","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[n' - 'ull]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRIN' - 'G"},"type":"INT"},"function":"TRUE","literals":[]},"expected":{"name":"bad_cast_before_function_TRUE","res' - 'ults":[{"error":"NumberFormatException"},true,true]}}' - ), - json.loads( - '{"name":"bad_cast_before_function_FALSE","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[' - 'null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRI' - 'NG"},"type":"INT"},"function":"FALSE","literals":[]},"expected":{"name":"bad_cast_before_function_FALSE","' - 'results":[{"error":"NumberFormatException"},false,false]}}' - ), - json.loads( - '{"name":"bad_cast_before_function_EQUAL","fields":[{"name":"v","type":"STRING"}],"rows":[["bad"],["1.9"],[' - 'null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","type":"STRI' - 'NG"},"type":"INT"},"function":"EQUAL","literals":[null]},"expected":{"name":"bad_cast_before_function_EQUA' - 'L","results":[{"error":"NumberFormatException"},false,false]}}' - ), - json.loads( - '{"name":"decimal_overflow_IS_NULL","fields":[{"name":"v","type":"STRING"}],"rows":[["99.994"],["99.995"],[' - '"bad"],[null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v","typ' - 'e":"STRING"},"type":"DECIMAL(4,2)"},"function":"IS_NULL","literals":[]},"expected":{"name":"decimal_overfl' - 'ow_IS_NULL","results":[false,true,{"error":"NumberFormatException"},true]}}' - ), - json.loads( - '{"name":"decimal_overflow_IS_NOT_NULL","fields":[{"name":"v","type":"STRING"}],"rows":[["99.994"],["99.995' - '"],["bad"],[null]],"predicate":{"kind":"LEAF","transform":{"name":"CAST","fieldRef":{"index":0,"name":"v",' - '"type":"STRING"},"type":"DECIMAL(4,2)"},"function":"IS_NOT_NULL","literals":[]},"expected":{"name":"decima' - 'l_overflow_IS_NOT_NULL","results":[true,false,{"error":"NumberFormatException"},false]}}' - ), - json.loads( - '{"name":"DECIMAL(18,1)_compact_double_DOUBLE","fields":[{"name":"v","type":"DECIMAL(18,1)"}],"rows":[["900' - '719925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef' - '":{"index":99,"name":"v","type":"DECIMAL(18,1)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(18,1)_compac' - 't_double_DOUBLE","results":[900719925474099.2,900719925474099.6,-900719925474099.2,null]}}' - ), - json.loads( - '{"name":"DECIMAL(18,1)_compact_double_FLOAT","fields":[{"name":"v","type":"DECIMAL(18,1)"}],"rows":[["9007' - '19925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"DECIMAL(18,1)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(18,1)_compact_' - 'double_FLOAT","results":[900719938895872.0,900719938895872.0,-900719938895872.0,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,1)_compact_double_DOUBLE","fields":[{"name":"v","type":"DECIMAL(38,1)"}],"rows":[["900' - '719925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef' - '":{"index":99,"name":"v","type":"DECIMAL(38,1)"},"type":"DOUBLE"},"expected":{"name":"DECIMAL(38,1)_compac' - 't_double_DOUBLE","results":[900719925474099.2,900719925474099.5,-900719925474099.2,null]}}' - ), - json.loads( - '{"name":"DECIMAL(38,1)_compact_double_FLOAT","fields":[{"name":"v","type":"DECIMAL(38,1)"}],"rows":[["9007' - '19925474099.3"],["900719925474099.5"],["-900719925474099.3"],[null]],"transform":{"name":"CAST","fieldRef"' - ':{"index":99,"name":"v","type":"DECIMAL(38,1)"},"type":"FLOAT"},"expected":{"name":"DECIMAL(38,1)_compact_' - 'double_FLOAT","results":[900719938895872.0,900719938895872.0,-900719938895872.0,null]}}' - ), -] - - -def source_array(values, type_): - if pa.types.is_decimal(type_): - values = [None if v is None else Decimal(v) for v in values] - return pa.array(values, type=type_) - - -@pytest.mark.parametrize('case', JAVA_CASES, ids=lambda case: case['name']) -def test_existing_numeric_casts_match_java_golden(case): - schema = pa.schema([(f['name'], _paimon_type_to_arrow(f['type'])) for f in case['fields']]) - cols = [source_array([row[i] for row in case['rows']], field.type) for i, field in enumerate(schema)] - batch = pa.RecordBatch.from_arrays(cols, schema=schema) - if 'transform' in case: - def execute(rows): - return _apply_predicate_transform(case['transform'], rows) - else: - rule = case.get('predicate') or {'kind': 'COMPOUND', 'function': 'AND', 'children': case['filters']} - execute = parse_predicate_to_batch_filter(json.dumps(rule)) - if 'parseError' in case['expected']: - with pytest.raises((ValueError, TypeError, pa.ArrowInvalid)): - execute(batch.slice(0, 0)) - return - execute(batch.slice(0, 0)) - for i, expected in enumerate(case['expected']['results']): - if isinstance(expected, dict) and 'error' in expected: - with pytest.raises((ValueError, TypeError, pa.ArrowInvalid)): - execute(batch.slice(i, 1)) - else: - value = execute(batch.slice(i, 1)).to_pylist()[0] - if isinstance(value, Decimal): - value = format(value, 'f') - assert value == expected, (case['name'], i) - - -def test_boolean_to_decimal_remains_outside_existing_python_support(): - with pytest.raises(pa.ArrowNotImplementedError): - _cast('BOOLEAN', 'DECIMAL(4,2)', pa.array([True, False, None])) - - -def test_rebound_integer_to_boolean_keeps_number_long_value(): - array = pa.array([0.5, 1.9, -0.5, -1.9, 1e30, None], type=pa.float64()) - assert _cast('INT', 'BOOLEAN', array).to_pylist() == [False, True, False, True, True, None] - with pytest.raises(ValueError): - _cast('DOUBLE', 'BOOLEAN', array) diff --git a/paimon-python/pypaimon/tests/mask_output_test.py b/paimon-python/pypaimon/tests/mask_output_test.py deleted file mode 100644 index 78f47e666d32..000000000000 --- a/paimon-python/pypaimon/tests/mask_output_test.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Authorization outputs preserve Java object values in canonical Arrow storage.""" - -from decimal import Decimal - -import pyarrow as pa -import pytest - -from pypaimon.casting.mask_output import cast_mask_output -from pypaimon.read.reader.auth_masking_reader import apply_auth_masking - - -@pytest.mark.parametrize('source', [pa.int32(), pa.date32(), pa.time32('ms')]) -@pytest.mark.parametrize('target', [pa.int32(), pa.date32(), pa.time32('ms')]) -def test_integer_class_masks_preserve_raw_values(source, target): - values = pa.array([-1, 123, None], type=source) - actual = cast_mask_output(values, target) - assert actual.cast(pa.int32()).to_pylist() == [-1, 123, None] - - -@pytest.mark.parametrize('type_name,target,values', [ - ('large_string', pa.string(), ['a', None]), ('string_view', pa.string(), ['a', None]), - ('large_binary', pa.binary(), [b'a', None]), ('binary_view', pa.binary(), [b'a', None]), -]) -def test_equivalent_arrow_string_and_byte_encodings_are_normalized(type_name, target, values): - factory = getattr(pa, type_name, None) - if factory is None: - pytest.skip('Physical view encoding is unavailable in this PyArrow version') - actual = cast_mask_output(pa.array(values, type=factory()), target) - assert actual.type == target and actual.to_pylist() == values - - -def test_decimal_mask_output_never_rounds_or_overflows(): - target = pa.decimal128(4, 2) - actual = cast_mask_output(pa.array([Decimal('2.670'), None], type=pa.decimal128(7, 3)), target) - assert actual.to_pylist() == [Decimal('2.67'), None] - for value in ('2.675', '-2.675', '1000.000'): - with pytest.raises(pa.ArrowInvalid): - cast_mask_output(pa.array([Decimal(value)], type=pa.decimal128(7, 3)), target) - - -def test_timestamp_mask_output_never_truncates_or_overflows(): - target = pa.timestamp('ms') - actual = cast_mask_output(pa.array([1000, None], type=pa.timestamp('us')), target) - assert actual.cast(pa.int64()).to_pylist() == [1, None] - for value in (1001, -1001): - with pytest.raises(pa.ArrowInvalid): - cast_mask_output(pa.array([value], type=pa.timestamp('us')), target) - with pytest.raises(pa.ArrowInvalid): - cast_mask_output(pa.array([(1 << 63) - 1], type=target), pa.timestamp('ns')) - - -def test_masking_preserves_field_and_schema_metadata(): - schema = pa.schema([pa.field('v', pa.string(), nullable=False, metadata={b'field': b'id'})], - metadata={b'table': b'contract'}) - batch = pa.RecordBatch.from_arrays([pa.array(['secret'])], schema=schema) - output = apply_auth_masking(batch, {'v': {'name': 'NULL'}}) - assert output.column(0).to_pylist() == [None] - assert output.schema.field(0).nullable - assert output.schema.field(0).metadata == schema.field(0).metadata - assert output.schema.metadata == schema.metadata - assert not batch.schema.field(0).nullable - - -@pytest.mark.parametrize('values', [[], [None, None]]) -def test_null_and_empty_masks_skip_runtime_class_check(values): - output = cast_mask_output(pa.array(values, type=pa.string()), pa.int32()) - assert output.type == pa.int32() and output.to_pylist() == values - with pytest.raises(ValueError): - cast_mask_output(pa.array(['bad', None]), pa.int32()) diff --git a/paimon-python/pypaimon/tests/native_cast_completion_test.py b/paimon-python/pypaimon/tests/native_cast_completion_test.py index 28921c0bccfe..5ab527fb3271 100644 --- a/paimon-python/pypaimon/tests/native_cast_completion_test.py +++ b/paimon-python/pypaimon/tests/native_cast_completion_test.py @@ -15,11 +15,17 @@ # specific language governing permissions and limitations # under the License. -"""Java CAST completion through real REST plans and strict Native readers.""" +"""REST authorization is executed by Rust; Python only adapts result schemas. + +These are representative Java results for the Python-to-Rust bridge. The full +CAST capability matrix and generated Java vectors live in paimon-rust. +""" import json import time +from contextlib import contextmanager from decimal import Decimal +from unittest.mock import patch import pyarrow as pa import pytest @@ -27,87 +33,148 @@ from pypaimon import Schema from pypaimon.api.api_response import AuthTableQueryResponse from pypaimon.common.predicate_builder import PredicateBuilder -from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow -from pypaimon.schema.data_types import DataTypeParser -from pypaimon.tests import native_numeric_cast_test -from pypaimon.tests.authorization_cast_completion_test import ( - JAVA_CASES, invalid_utf8, source_array, unrepresentable, -) - -rest_catalog = native_numeric_cast_test.rest_catalog -table_mode = native_numeric_cast_test.table_mode -_read = native_numeric_cast_test._read -_create_table = native_numeric_cast_test._create_table -pytestmark = native_numeric_cast_test.pytestmark - - -def _native_cases(): - cases = [] - for case in JAVA_CASES: - source = _paimon_type_to_arrow(case['fields'][0]['type']) - target = _paimon_type_to_arrow(case['transform']['type']) - pairs = [] - for row, value in zip(case['rows'], case['expected']['UTC']): - if (isinstance(value, dict) and 'error' in value or unrepresentable(value, target) - or invalid_utf8(row[0], source)): - continue - try: - source_array([row[0]], source) - except OverflowError: - continue - pairs.append((row, value)) - if any(value is not None for _, value in pairs): - cases.append(dict(case, rows=[row for row, _ in pairs], values=[v for _, v in pairs])) - return cases - - -def _definition(schema, table_mode, case): - mode, options = table_mode - definition = Schema.from_pyarrow_schema( - schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options) - definition.fields[1].type = DataTypeParser.parse_data_type(case['fields'][0]['type']) - definition.fields[2].type = DataTypeParser.parse_data_type(case['transform']['type']) - return definition +from pypaimon.schema.data_types import DataTypeParser, PyarrowFieldParser +from pypaimon.schema.schema_change import SchemaChange +from pypaimon.tests import native_query_auth_test +rest_catalog = native_query_auth_test.rest_catalog +pytestmark = native_query_auth_test.pytestmark -@pytest.mark.parametrize('case', _native_cases(), ids=lambda case: case['name']) -def test_all_scalar_cast_families_mask_hidden_fields_natively(rest_catalog, table_mode, case, monkeypatch): + +@pytest.fixture(params=[ + ('append', {}), ('primary-key', {'bucket': '1'}), + ('data-evolution', {'row-tracking.enabled': 'true', 'data-evolution.enabled': 'true'}), +], ids=lambda mode: mode[0]) +def table_mode(request): + return request.param + + +@pytest.fixture(autouse=True) +def utc_zone(monkeypatch): monkeypatch.setenv('TZ', 'UTC') time.tzset() + yield + monkeypatch.undo() + time.tzset() + + +@contextmanager +def native_only(): + with patch('pypaimon.read.table_read.TableRead._create_split_read', + side_effect=AssertionError('Native read fell back')), \ + patch('pypaimon.common.predicate_json_parser._apply_predicate_transform', + side_effect=AssertionError('Python executed an authorization transform')), \ + patch('pypaimon.read.reader.auth_masking_reader._apply_predicate_transform', + side_effect=AssertionError('Python executed an authorization mask')): + yield + + +def _read(table, projection=None, predicate=None, limit=None): + with native_only(): + return native_query_auth_test._read(table, True, projection, predicate, limit) + + +def _create_table(rest_catalog, table_mode, schema, data, logical_types=None): + catalog, server = rest_catalog + mode, options = table_mode + definition = Schema.from_pyarrow_schema( + schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options) + for field in definition.fields: + if logical_types and field.name in logical_types: + field.type = DataTypeParser.parse_data_type(logical_types[field.name]) + catalog.create_table('default.cast', definition, False) + table = catalog.get_table('default.cast') + builder = table.new_batch_write_builder() + writer, commit = builder.new_write(), builder.new_commit() try: - source = _paimon_type_to_arrow(case['fields'][0]['type']) - target = _paimon_type_to_arrow(case['transform']['type']) - count = len(case['rows']) - schema = pa.schema([('id', pa.int32()), ('v', source), ('masked', target)]) - data = pa.Table.from_arrays([ - pa.array(range(count), type=pa.int32()), - source_array([row[0] for row in case['rows']], source), pa.nulls(count, type=target), - ], schema=schema) - definition = _definition(schema, table_mode, case) - table, server = _create_table(rest_catalog, table_mode, schema, data, definition) - grant_key = table.identifier.get_full_name() - server.table_query_auth_store[grant_key] = AuthTableQueryResponse( - column_masking={'masked': json.dumps(case['transform'])}) - expected = source_array(case['values'], target) - for native in [False, True]: - result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) - assert result.column('masked').combine_chunks().equals(expected) - predicate = PredicateBuilder(table.fields).is_not_null('masked') - first = next(i for i, value in enumerate(case['values']) if value is not None) - assert _read(table, native, ['id'], predicate, limit=1).to_pylist() == [{'id': first}] - # A transformed authorization predicate also needs its hidden source. - rule = {'kind': 'LEAF', 'transform': case['transform'], 'function': 'IS_NOT_NULL', 'literals': []} - server.table_query_auth_store[grant_key] = AuthTableQueryResponse(filter=[json.dumps(rule)]) - expected_ids = [{'id': i} for i, v in enumerate(case['values']) if v is not None] - for native in [False, True]: - assert _read(table, native, ['id']).sort_by([('id', 'ascending')]).to_pylist() == expected_ids + writer.write_arrow(data) + commit.commit(writer.prepare_commit()) finally: - monkeypatch.undo() - time.tzset() + writer.close() + commit.close() + catalog.alter_table(table.identifier, [SchemaChange.set_option('query-auth.enabled', 'true')]) + return catalog.get_table('default.cast'), server + + +def _case(source, target, values, expected, original=None): + return source, target, values, expected, original or source + + +# Cover each executor family and original-rule rebinding through actual REST +# plans and Parquet reads. No Python CAST implementation computes expectations. +_CASES = [ + _case('BIGINT', 'TINYINT', [128, -129, 4294967297, None], [-128, 127, 1, None]), + _case('DOUBLE', 'TINYINT', [-129.9, 1e30, None], [127, -1, None]), + _case('FLOAT', 'INT', [1.9, -1.9, 1e30, None], [1, -1, 2147483647, None]), + _case('DOUBLE', 'BIGINT', [1e30, -1e30, None], [(1 << 63) - 1, -(1 << 63), None]), + _case('BOOLEAN', 'INT', [True, False, None], [1, 0, None]), + _case('INT', 'BOOLEAN', [0, -1, None], [False, True, None]), + _case('STRING', 'BOOLEAN', ['yes', 'FALSE', None], [True, False, None]), + _case('BOOLEAN', 'STRING', [True, False, None], ['true', 'false', None]), + _case('STRING', 'INT', ['1.9', '-2.5', None], [1, -2, None]), + _case('STRING', 'FLOAT', ['0x1.8p1', '1.25f', None], [3.0, 1.25, None]), + _case('STRING', 'DOUBLE', ['0x1.8p1', ' 2.5D ', None], [3.0, 2.5, None]), + _case('FLOAT', 'STRING', [1e23, 0.0001, None], ['1.0E23', '1.0E-4', None]), + _case('DOUBLE', 'STRING', [1e23, None], ['9.999999999999999E22', None]), + _case('FLOAT', 'DECIMAL(4,2)', [1.005, 99.995, None], [Decimal('1.00'), None, None]), + _case('DOUBLE', 'DECIMAL(4,2)', [1.005, 99.995, None], [Decimal('1.01'), None, None]), + _case('STRING', 'DECIMAL(4,2)', ['1.005', '99.995', None], [Decimal('1.01'), None, None]), + _case('DECIMAL(18,1)', 'DOUBLE', [Decimal('900719925474099.3'), None], [900719925474099.2, None]), + _case('DECIMAL(38,1)', 'DOUBLE', [Decimal('900719925474099.5'), None], [900719925474099.5, None]), + _case('DECIMAL(38,1)', 'BIGINT', [Decimal('9223372036854775808.9'), None], [-(1 << 63), None]), + _case('DECIMAL(38,10)', 'STRING', [Decimal('0.0000000001'), None], ['0.0000000001', None]), + _case('STRING', 'CHAR(3)', ['🙂中', 'a', None], ['🙂中 ', 'a ', None]), + _case('STRING', 'BINARY(3)', ['ab', None], [b'ab\x00', None]), + _case('STRING', 'VARBINARY(1)', ['🙂', None], [b'\xf0', None]), + _case('BYTES', 'VARCHAR(3)', [b'abcdef', None], ['abcdef', None]), + _case('DATE', 'STRING', [0, -1, None], ['1970-01-01', '1969-12-31', None]), + _case('STRING', 'DATE', ['1970-01-02', '-1', None], [1, -1, None]), + _case('TIME(1)', 'STRING', [101, -1, None], ['00:00:00.1', '23:59:59.9', None]), + _case('DATE', 'TIMESTAMP(3)', [0, -1, None], [0, -86400000, None]), + _case('BIGINT', 'TIMESTAMP(3)', [1, -1, None], [1000, -1000, None]), + _case('STRING', 'TIMESTAMP(1)', ['1970-01-01 00:00:00.123456', None], [100, None]), + _case('STRING', 'TIMESTAMP_LTZ(3)', ['1970-01-01 00:00:00.001', None], [1, None]), + _case('TIMESTAMP(3)', 'DATE', [-1, 86400000, None], [-1, 1, None]), + _case('TIMESTAMP(3)', 'TIME(0)', [123, -1, None], [123, 86399999, None]), + _case('TIMESTAMP(3)', 'BIGINT', [1999, -1999, None], [1, -2, None]), + _case('TIMESTAMP_LTZ(3)', 'BIGINT', [1999, -1999, None], [1, -2, None]), + _case('TIMESTAMP(3)', 'TIMESTAMP_LTZ(6)', [1, -1, None], [1000, -1000, None]), + _case('TIMESTAMP_LTZ(6)', 'TIMESTAMP(1)', [123456, -1, None], [100, -100, None]), + _case('DOUBLE', 'DECIMAL(4,2)', [1.9, -1.9, None], [Decimal('1.00'), Decimal('-1.00'), None], 'INT'), + _case('DOUBLE', 'STRING', [1.0, None], ['1.0', None], 'INT'), + _case('TIMESTAMP(3)', 'STRING', [0, -1, None], + ['1970-01-01T00:00', '1969-12-31T23:59:59.999', None], 'INT'), + _case('TIMESTAMP_LTZ(3)', 'STRING', [1, None], ['1970-01-01 00:00:00.001000', None], 'TIMESTAMP(6)'), +] + + +@pytest.mark.parametrize('case', _CASES, ids=lambda case: '%s_to_%s_from_%s' % (case[0], case[1], case[4])) +def test_authorization_casts_execute_in_rust(rest_catalog, table_mode, case): + source, target, values, expected, original = case + schema = pa.schema([ + ('id', pa.int32()), + ('v', PyarrowFieldParser.from_paimon_type(DataTypeParser.parse_data_type(source))), + ('masked', PyarrowFieldParser.from_paimon_type(DataTypeParser.parse_data_type(target))), + ]) + count = len(values) + data = pa.Table.from_arrays([pa.array(range(count), type=pa.int32()), pa.array(values, type=schema.field('v').type), + pa.nulls(count, type=schema.field('masked').type)], schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data, {'v': source, 'masked': target}) + transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'index': 99, 'type': original}, 'type': target} + grant_key = table.identifier.get_full_name() + server.table_query_auth_store[grant_key] = AuthTableQueryResponse(column_masking={'masked': json.dumps(transform)}) + result = _read(table, ['id', 'masked']).sort_by([('id', 'ascending')]) + assert result.column('masked').combine_chunks().equals(pa.array(expected, type=schema.field('masked').type)) + non_null = [i for i, value in enumerate(expected) if value is not None] + predicate = PredicateBuilder(table.fields).is_not_null('masked') + assert _read(table, ['id'], predicate, limit=1).to_pylist() == [{'id': non_null[0]}] + rule = {'kind': 'LEAF', 'transform': transform, 'function': 'IS_NOT_NULL', 'literals': []} + server.table_query_auth_store[grant_key] = AuthTableQueryResponse(filter=[json.dumps(rule)]) + assert _read(table, ['id']).sort_by([('id', 'ascending')]).to_pylist() == [{'id': i} for i in non_null] @pytest.mark.parametrize('mask', ['null', 'overflow']) -def test_not_null_mask_outputs_remain_nullable_and_physical_type_is_unchanged(rest_catalog, table_mode, mask): +def test_not_null_mask_adapts_only_output_schema(rest_catalog, table_mode, mask): target = pa.string() if mask == 'null' else pa.decimal128(4, 2) schema = pa.schema([pa.field('id', pa.int32(), nullable=False), pa.field('v', pa.int32()), pa.field('masked', target, nullable=False)]) @@ -120,42 +187,40 @@ def test_not_null_mask_outputs_remain_nullable_and_physical_type_is_unchanged(re server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( column_masking={'masked': json.dumps(transform)}) expected = [None, None] if mask == 'null' else [Decimal('1.00'), None] - for native in [False, True]: - result = _read(table, native, ['masked', 'id']).sort_by([('id', 'ascending')]) - assert result.column('masked').to_pylist() == expected - assert result.schema.field('masked').nullable - assert not result.schema.field('id').nullable - empty = _read(table, native, ['masked'], limit=0) - assert empty.num_rows == 0 and empty.schema.field('masked').nullable - builder = table.copy({'read.native.enabled': str(native).lower(), - 'scan.native-plan.enabled': str(native).lower()}).new_read_builder() - builder.with_projection(['masked', 'id']) - splits = builder.new_scan().plan().splits() - reader = builder.new_read() - assert not reader.read_type[0].type.nullable - with reader.to_arrow_batch_reader(splits) as batches: - assert batches.schema.field('masked').nullable - assert batches.read_all().column('masked').to_pylist() == expected - if not native: - # A captured split enforces its grant even if this handle has no - # live authorization option. The output schema follows that split. - captured = table.copy({'query-auth.enabled': 'false', 'read.native.enabled': 'false', - 'scan.native-plan.enabled': 'false'}).new_read_builder() - captured.with_projection(['masked', 'id']) - with captured.new_read().to_arrow_batch_reader(splits) as batches: - batch = batches.read_next_batch() - assert batches.schema.equals(batch.schema, check_metadata=True) - assert batch.column('masked').to_pylist() == expected - assert batch.schema.field('masked').nullable - assert not batch.schema.field('id').nullable + result = _read(table, ['masked', 'id']).sort_by([('id', 'ascending')]) + assert result.column('masked').to_pylist() == expected + assert result.schema.field('masked').nullable and not result.schema.field('id').nullable + assert _read(table, ['masked'], limit=0).schema.field('masked').nullable + projection = {'first': 'masked', 'second': 'masked', 'id': 'id'} + result = _read(table, projection).sort_by([('id', 'ascending')]) + assert result.column('first').to_pylist() == expected == result.column('second').to_pylist() + assert result.schema.field('first').nullable and result.schema.field('second').nullable + builder = table.copy({'read.native.enabled': 'true', 'scan.native-plan.enabled': 'true'}).new_read_builder() + builder.with_projection(['masked', 'id']) + splits = builder.new_scan().plan().splits() + reader = builder.new_read() + assert not reader.read_type[0].type.nullable + with native_only(), reader.to_arrow_batch_reader(splits) as batches: + batch = batches.read_next_batch() + assert batches.schema.equals(batch.schema, check_metadata=True) + assert batch.column('masked').to_pylist() == expected + if mask == 'null': + # Captured rules must still determine output nullability on the existing + # fallback reader; no additional Python CAST implementation is needed. + fallback = table.copy({'query-auth.enabled': 'false', 'read.native.enabled': 'false', + 'scan.native-plan.enabled': 'false'}) + captured = fallback.new_read_builder().with_projection(['masked', 'id']) + with captured.new_read().to_arrow_batch_reader(splits) as batches: + batch = batches.read_next_batch() + assert batches.schema.equals(batch.schema, check_metadata=True) + assert batch.column('masked').to_pylist() == [None, None] @pytest.mark.parametrize('target,mask_type,values,expected', [ (pa.decimal128(4, 2), 'DECIMAL(6,3)', ['2.670', '1000'], [Decimal('2.67'), None]), (pa.timestamp('ms'), 'TIMESTAMP(6)', ['1000', '-1000'], [1, -1]), ]) -def test_masks_adapt_decimal_and_timestamp_storage_without_loss( - rest_catalog, table_mode, target, mask_type, values, expected): +def test_rust_adapts_mask_storage_without_loss(rest_catalog, table_mode, target, mask_type, values, expected): schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', target)]) data = pa.Table.from_arrays([pa.array([0, 1], type=pa.int32()), pa.array(values), pa.nulls(2, type=target)], schema=schema) @@ -163,9 +228,8 @@ def test_masks_adapt_decimal_and_timestamp_storage_without_loss( transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': mask_type} server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( column_masking={'masked': json.dumps(transform)}) - for native in [False, True]: - result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) - assert result.column('masked').combine_chunks().equals(pa.array(expected, type=target)) + result = _read(table, ['id', 'masked']).sort_by([('id', 'ascending')]) + assert result.column('masked').combine_chunks().equals(pa.array(expected, type=target)) @pytest.mark.parametrize('target,mask_type,value', [ @@ -173,35 +237,48 @@ def test_masks_adapt_decimal_and_timestamp_storage_without_loss( (pa.decimal128(4, 2), 'DECIMAL(7,3)', '1000'), (pa.timestamp('ms'), 'TIMESTAMP(6)', '1001'), ]) -def test_mask_output_representation_never_rounds_or_truncates( - rest_catalog, table_mode, target, mask_type, value): +def test_rust_rejects_lossy_mask_output(rest_catalog, table_mode, target, mask_type, value): schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', target)]) - data = pa.Table.from_arrays([pa.array([0], type=pa.int32()), pa.array([value]), - pa.nulls(1, type=target)], schema=schema) - table, server = _create_table(rest_catalog, table_mode, schema, data) + table, server = _create_table(rest_catalog, table_mode, schema, pa.Table.from_arrays([ + pa.array([0], type=pa.int32()), pa.array([value]), pa.nulls(1, type=target), + ], schema=schema)) transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': mask_type} server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( column_masking={'masked': json.dumps(transform)}) - for native in [False, True]: - with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): - _read(table, native, ['masked']) + with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): + _read(table, ['masked']) + + +@pytest.mark.parametrize('function', ['AND', 'OR', 'entries']) +def test_rust_short_circuits_authorization_cast_errors(rest_catalog, table_mode, function): + schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', pa.int32())]) + data = pa.table({'id': [0, 1, 2], 'v': ['bad', '1.9', None], 'masked': [0] * 3}, schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) + guard = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [0 if function == 'OR' else 1], + 'transform': {'name': 'FIELD_REF', 'fieldRef': {'name': 'id', 'type': 'INT'}}} + cast = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [1], 'transform': { + 'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'INT'}} + filters = [guard, cast] if function == 'entries' else [ + {'kind': 'COMPOUND', 'function': function, 'children': [guard, cast]}] + server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( + filter=[json.dumps(rule) for rule in filters]) + result = _read(table, ['id']).sort_by([('id', 'ascending')]).to_pylist() + assert result == ([{'id': 0}, {'id': 1}] if function == 'OR' else [{'id': 1}]) @pytest.mark.parametrize('guard', [True, False]) -def test_mask_class_checks_follow_authorization_row_filter(rest_catalog, table_mode, guard): +def test_rust_checks_mask_class_after_authorization_filter(rest_catalog, table_mode, guard): schema = pa.schema([('id', pa.int32()), ('v', pa.string()), ('masked', pa.int32())]) - table, server = _create_table( - rest_catalog, table_mode, schema, - pa.table({'id': [0, 1], 'v': [None, 'bad'], 'masked': [1, 2]}, schema=schema)) + data = pa.table({'id': [0, 1], 'v': [None, 'bad'], 'masked': [1, 2]}, schema=schema) + table, server = _create_table(rest_catalog, table_mode, schema, data) transform = {'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'STRING'} filter_ = {'kind': 'LEAF', 'function': 'IS_NULL', 'literals': [], 'transform': {'name': 'FIELD_REF', 'fieldRef': {'name': 'v', 'type': 'STRING'}}} server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( filter=[json.dumps(filter_)] if guard else None, column_masking={'masked': json.dumps(transform)}) - for native in [False, True]: - if guard: - assert _read(table, native, ['id', 'masked']).to_pylist() == [{'id': 0, 'masked': None}] - else: - with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): - _read(table, native, ['masked']) - assert _read(table, native, ['masked'], limit=0).num_rows == 0 + if guard: + assert _read(table, ['id', 'masked']).to_pylist() == [{'id': 0, 'masked': None}] + else: + with pytest.raises((RuntimeError, ValueError, pa.ArrowException)): + _read(table, ['masked']) + assert _read(table, ['masked'], limit=0).num_rows == 0 diff --git a/paimon-python/pypaimon/tests/native_numeric_cast_test.py b/paimon-python/pypaimon/tests/native_numeric_cast_test.py deleted file mode 100644 index 12b479beee2c..000000000000 --- a/paimon-python/pypaimon/tests/native_numeric_cast_test.py +++ /dev/null @@ -1,132 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Numeric REST CASTs through strict Native reads of all existing table modes.""" - -import json - -import pyarrow as pa -import pytest - -from pypaimon import Schema -from pypaimon.api.api_response import AuthTableQueryResponse -from pypaimon.common.predicate_builder import PredicateBuilder -from pypaimon.common.predicate_json_parser import _paimon_type_to_arrow -from pypaimon.read.native_plan import native_runtime_available -from pypaimon.schema.schema_change import SchemaChange -from pypaimon.tests import native_query_auth_test -from pypaimon.tests.authorization_numeric_cast_test import JAVA_CASES, source_array - -rest_catalog = native_query_auth_test.rest_catalog -_read = native_query_auth_test._read -pytestmark = [pytest.mark.native_plan, pytest.mark.skipif( - not native_runtime_available(), reason='Rust reader required')] - - -def _native_cases(): - cases = [] - for case in JAVA_CASES: - if 'transform' not in case or 'parseError' in case['expected']: - continue - if case['fields'][0]['type'] != case['transform']['fieldRef']['type']: - continue - pairs = [(row, value) for row, value in zip(case['rows'], case['expected']['results']) - if not isinstance(value, dict)] - if pairs: - cases.append(dict(case, rows=[p[0] for p in pairs], values=[p[1] for p in pairs])) - return cases - - -@pytest.fixture(params=[ - ('append', {}), ('primary-key', {'bucket': '1'}), - ('data-evolution', {'row-tracking.enabled': 'true', 'data-evolution.enabled': 'true'}), -], ids=lambda mode: mode[0]) -def table_mode(request): - return request.param - - -def _create_table(rest_catalog, table_mode, schema, data, paimon_schema=None): - catalog, server = rest_catalog - mode, options = table_mode - definition = paimon_schema or Schema.from_pyarrow_schema( - schema, primary_keys=['id'] if mode == 'primary-key' else None, options=options) - catalog.create_table('default.numeric', definition, False) - table = catalog.get_table('default.numeric') - builder = table.new_batch_write_builder() - writer, commit = builder.new_write(), builder.new_commit() - try: - writer.write_arrow(data) - commit.commit(writer.prepare_commit()) - finally: - writer.close() - commit.close() - catalog.alter_table(table.identifier, [SchemaChange.set_option('query-auth.enabled', 'true')]) - return catalog.get_table('default.numeric'), server - - -@pytest.mark.parametrize('case', _native_cases(), ids=lambda case: case['name']) -def test_existing_numeric_casts_filter_and_mask_natively(rest_catalog, table_mode, case): - source_type = _paimon_type_to_arrow(case['fields'][0]['type']) - target_type = _paimon_type_to_arrow(case['transform']['type']) - count = len(case['rows']) - ids = list(range(1, count + 1)) - schema = pa.schema([('id', pa.int32()), ('v', source_type), ('masked', target_type)]) - data = pa.Table.from_arrays([pa.array(ids, type=pa.int32()), - source_array([row[0] for row in case['rows']], source_type), - pa.nulls(count, type=target_type)], schema=schema) - table, server = _create_table(rest_catalog, table_mode, schema, data) - grant_key = table.identifier.get_full_name() - server.table_query_auth_store[grant_key] = AuthTableQueryResponse( - column_masking={'masked': json.dumps(case['transform'])}) - expected = source_array(case['values'], target_type) - non_null = [id_ for id_, value in zip(ids, case['values']) if value is not None] - for native in [False, True]: - result = _read(table, native, ['id', 'masked']).sort_by([('id', 'ascending')]) - assert result.column('masked').combine_chunks().equals(expected) - # Original masked values are all NULL: evaluating the user's predicate - # before the mask would lose every row, and LIMIT must follow filtering. - predicate = PredicateBuilder(table.fields).is_not_null('masked') - assert _read(table, native, ['id'], predicate, limit=1).to_pylist() == ( - [{'id': non_null[0]}] if non_null else []) - selected = next((value for value in case['values'] if value is not None), None) - rule = {'kind': 'LEAF', 'transform': case['transform'], - 'function': 'IS_NULL' if selected is None else 'EQUAL', - 'literals': [] if selected is None else [selected]} - server.table_query_auth_store[grant_key] = AuthTableQueryResponse(filter=[json.dumps(rule)]) - matching = [id_ for id_, value in zip(ids, case['values']) if value == selected] - for native in [False, True]: - # Only id is projected: the cast's source must be a hidden dependency. - assert _read(table, native, ['id'], limit=1).to_pylist() == ( - [{'id': matching[0]}] if matching else []) - - -@pytest.mark.parametrize('function', ['AND', 'OR', 'entries']) -def test_numeric_cast_errors_are_short_circuited_per_row(rest_catalog, table_mode, function): - schema = pa.schema([('id', pa.int32()), ('v', pa.string())]) - data = pa.table({'id': [0, 1, 2], 'v': ['bad', '1.9', None]}, schema=schema) - table, server = _create_table(rest_catalog, table_mode, schema, data) - guard = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [0 if function == 'OR' else 1], - 'transform': {'name': 'FIELD_REF', 'fieldRef': {'name': 'id', 'type': 'INT'}}} - cast = {'kind': 'LEAF', 'function': 'EQUAL', 'literals': [1], 'transform': { - 'name': 'CAST', 'fieldRef': {'name': 'v', 'type': 'STRING'}, 'type': 'INT'}} - filters = [guard, cast] if function == 'entries' else [ - {'kind': 'COMPOUND', 'function': function, 'children': [guard, cast]}] - server.table_query_auth_store[table.identifier.get_full_name()] = AuthTableQueryResponse( - filter=[json.dumps(rule) for rule in filters]) - for native in [False, True]: - result = _read(table, native, ['id']).sort_by([('id', 'ascending')]).to_pylist() - assert result == ([{'id': 0}, {'id': 1}] if function == 'OR' else [{'id': 1}]) diff --git a/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py b/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py index af6655d99bc4..55f7fe6f90ef 100644 --- a/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py +++ b/paimon-python/pypaimon/tests/native_schema_evolution_cast_test.py @@ -109,14 +109,11 @@ def test_large_utf8_old_parquet_reads_as_integer_without_native_fallback(rest_ca pq.write_table(physical, path) meta.file_size = os.stat(path).st_size assert pq.read_schema(path).field('v').type == pa.large_string() - for native in (False, True): - reader = table.copy({'read.native.enabled': str(native).lower()}).new_read_builder().new_read() - with ExitStack() as stack: - if native: - stack.enter_context(patch('pypaimon.read.table_read.TableRead._create_split_read', - side_effect=AssertionError('Native read fell back'))) - result = reader.to_arrow(splits).sort_by([('id', 'ascending')]) - assert result.column('v').to_pylist() == [1, -2, None] + reader = table.copy({'read.native.enabled': 'true'}).new_read_builder().new_read() + with patch('pypaimon.read.table_read.TableRead._create_split_read', + side_effect=AssertionError('Native read fell back')): + result = reader.to_arrow(splits).sort_by([('id', 'ascending')]) + assert result.column('v').to_pylist() == [1, -2, None] _TEMPORAL_STRING_CASES = [ diff --git a/paimon-python/pypaimon/tests/predicate_json_parser_test.py b/paimon-python/pypaimon/tests/predicate_json_parser_test.py index 048dbd538faa..7dc1991d664a 100644 --- a/paimon-python/pypaimon/tests/predicate_json_parser_test.py +++ b/paimon-python/pypaimon/tests/predicate_json_parser_test.py @@ -420,17 +420,13 @@ def test_rebound_numeric_to_string_uses_decimal_plain_text(self): def test_rebound_numeric_to_string_refuses_other_object_formatting(self): transform = {'name': 'CAST', 'fieldRef': {'name': 's', 'type': 'INT'}, 'type': 'STRING'} - for array in [pa.array([b'a', None])]: + for array in [pa.array([0, None], type=pa.timestamp('ms')), pa.array([b'a', None]), + pa.array([1.0, None], type=pa.float64())]: with self.subTest(type=array.type), self.assertRaises(ValueError): _apply_predicate_transform(transform, pa.RecordBatch.from_pydict({'s': array})) nulls = pa.RecordBatch.from_pydict({'s': pa.nulls(2, type=array.type)}) self.assertEqual(_apply_predicate_transform(transform, nulls).to_pylist(), [None, None]) - def test_rebound_numeric_to_string_formats_float_runtime_values(self): - transform = {'name': 'CAST', 'fieldRef': {'name': 's', 'type': 'INT'}, 'type': 'STRING'} - batch = pa.RecordBatch.from_pydict({'s': pa.array([1.0, None], type=pa.float64())}) - self.assertEqual(_apply_predicate_transform(transform, batch).to_pylist(), ['1.0', None]) - def test_empty_concat_is_the_empty_string(self): self.assertEqual(_apply_predicate_transform({'name': 'CONCAT', 'inputs': []}, self.batch).to_pylist(), [''] * len(self.batch)) From bfa5cf4ab951b2459dff752cf1bc3bf1eb968b19 Mon Sep 17 00:00:00 2001 From: JingsongLi Date: Wed, 14 Oct 2026 22:41:45 +0800 Subject: [PATCH 4/4] Verify native authorization casts in process local time zones --- .github/workflows/ci-python.yml | 17 ++++++++++- .../tests/native_cast_completion_test.py | 30 +++++++++++-------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 56e6cbe546e0..c28becd9f552 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -183,7 +183,7 @@ jobs: - name: Install system dependencies run: | apt-get update && apt-get install -y --no-install-recommends \ - build-essential git curl cmake pkg-config libssl-dev libclang-dev \ + build-essential git curl cmake pkg-config libssl-dev libclang-dev tzdata \ && rm -rf /var/lib/apt/lists/* - name: Install Rust toolchain @@ -227,6 +227,21 @@ jobs: run: | bash paimon-python/dev/lint-python.sh -i pytest + - name: Verify native temporal casts in non-UTC system zones + shell: bash + env: + PYPAIMON_TEST_NATIVE_PLAN: '1' + PYPAIMON_TEST_NATIVE_READ: '1' + PYPAIMON_TEST_NATIVE_WRITE: '1' + PYPAIMON_TEST_NATIVE_COMMIT: '1' + run: | + for zone in Asia/Shanghai America/New_York; do + TZ="$zone" python -m pytest -q \ + paimon-python/pypaimon/tests/native_cast_completion_test.py \ + paimon-python/pypaimon/tests/native_temporal_zone_cast_test.py \ + -k 'TIMESTAMP_LTZ or temporal' + done + torch: name: PyTorch / Python 3.10 timeout-minutes: 60 diff --git a/paimon-python/pypaimon/tests/native_cast_completion_test.py b/paimon-python/pypaimon/tests/native_cast_completion_test.py index 5ab527fb3271..f047c7993777 100644 --- a/paimon-python/pypaimon/tests/native_cast_completion_test.py +++ b/paimon-python/pypaimon/tests/native_cast_completion_test.py @@ -22,8 +22,8 @@ """ import json -import time from contextlib import contextmanager +from datetime import datetime, timezone from decimal import Decimal from unittest.mock import patch @@ -49,15 +49,6 @@ def table_mode(request): return request.param -@pytest.fixture(autouse=True) -def utc_zone(monkeypatch): - monkeypatch.setenv('TZ', 'UTC') - time.tzset() - yield - monkeypatch.undo() - time.tzset() - - @contextmanager def native_only(): with patch('pypaimon.read.table_read.TableRead._create_split_read', @@ -102,6 +93,12 @@ def _case(source, target, values, expected, original=None): # Cover each executor family and original-rule rebinding through actual REST # plans and Parquet reads. No Python CAST implementation computes expectations. +# Keep the process zone unchanged: Rust caches its system-zone lookup, while +# Python's tzset() would only change libc. These epoch cases have no DST gap or +# overlap; expectations use the system offset rather than assuming UTC. +_EPOCH_OFFSET_MS = int(datetime.fromtimestamp(0).astimezone().utcoffset().total_seconds()) * 1000 +_LTZ_INSTANTS = [datetime(2024, 1, 1, tzinfo=timezone.utc), datetime(2024, 7, 1, tzinfo=timezone.utc)] + _CASES = [ _case('BIGINT', 'TINYINT', [128, -129, 4294967297, None], [-128, 127, 1, None]), _case('DOUBLE', 'TINYINT', [-129.9, 1e30, None], [127, -1, None]), @@ -133,13 +130,20 @@ def _case(source, target, values, expected, original=None): _case('DATE', 'TIMESTAMP(3)', [0, -1, None], [0, -86400000, None]), _case('BIGINT', 'TIMESTAMP(3)', [1, -1, None], [1000, -1000, None]), _case('STRING', 'TIMESTAMP(1)', ['1970-01-01 00:00:00.123456', None], [100, None]), - _case('STRING', 'TIMESTAMP_LTZ(3)', ['1970-01-01 00:00:00.001', None], [1, None]), + _case('STRING', 'TIMESTAMP_LTZ(3)', ['1970-01-01 00:00:00.001', None], [1 - _EPOCH_OFFSET_MS, None]), + _case('DATE', 'TIMESTAMP_LTZ(3)', [0, -1, None], [-_EPOCH_OFFSET_MS, -86400000 - _EPOCH_OFFSET_MS, None]), + _case('BIGINT', 'TIMESTAMP_LTZ(3)', [0, 1, -1, None], + [_EPOCH_OFFSET_MS, 1000 + _EPOCH_OFFSET_MS, -1000 + _EPOCH_OFFSET_MS, None]), + _case('TIMESTAMP_LTZ(3)', 'STRING', [int(value.timestamp()) * 1000 for value in _LTZ_INSTANTS] + [None], + [value.astimezone().strftime('%Y-%m-%d %H:%M:%S') + '.000' for value in _LTZ_INSTANTS] + [None]), _case('TIMESTAMP(3)', 'DATE', [-1, 86400000, None], [-1, 1, None]), _case('TIMESTAMP(3)', 'TIME(0)', [123, -1, None], [123, 86399999, None]), _case('TIMESTAMP(3)', 'BIGINT', [1999, -1999, None], [1, -2, None]), _case('TIMESTAMP_LTZ(3)', 'BIGINT', [1999, -1999, None], [1, -2, None]), - _case('TIMESTAMP(3)', 'TIMESTAMP_LTZ(6)', [1, -1, None], [1000, -1000, None]), - _case('TIMESTAMP_LTZ(6)', 'TIMESTAMP(1)', [123456, -1, None], [100, -100, None]), + _case('TIMESTAMP(3)', 'TIMESTAMP_LTZ(6)', [1, -1, None], + [(1 - _EPOCH_OFFSET_MS) * 1000, (-1 - _EPOCH_OFFSET_MS) * 1000, None]), + _case('TIMESTAMP_LTZ(6)', 'TIMESTAMP(1)', [123456, -1, None], + [100 + _EPOCH_OFFSET_MS, -100 + _EPOCH_OFFSET_MS, None]), _case('DOUBLE', 'DECIMAL(4,2)', [1.9, -1.9, None], [Decimal('1.00'), Decimal('-1.00'), None], 'INT'), _case('DOUBLE', 'STRING', [1.0, None], ['1.0', None], 'INT'), _case('TIMESTAMP(3)', 'STRING', [0, -1, None],