nssalian commented on code in PR #1607: URL: https://github.com/apache/iceberg-go/pull/1607#discussion_r3899681129
########## variant_cast.go: ########## @@ -0,0 +1,269 @@ +// 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. + +package iceberg + +import ( + "github.com/apache/arrow-go/v18/arrow" + "github.com/apache/arrow-go/v18/arrow/decimal" + "github.com/apache/arrow-go/v18/arrow/decimal128" + "github.com/apache/arrow-go/v18/parquet/variant" + "github.com/google/uuid" +) + +const ( + microsPerDay = int64(86_400_000_000) + nanosPerDay = int64(86_400_000_000_000) + nanosPerMicro = int64(1_000) +) + +// CastVariantLiteral casts a leaf variant value to typ and wraps it as a Literal. +func CastVariantLiteral(v variant.Value, typ PrimitiveType) (Literal, bool) { + result, ok := castVariantValue(v, typ) + if !ok { + return nil, false + } + + lit := literalFromCastValue(result) + if lit == nil { + return nil, false + } + if !lit.Type().Equals(typ) { + conv, err := lit.To(typ) + if err != nil { + return nil, false + } + + lit = conv + } + + return lit, true +} + +// castVariantValue casts a leaf variant value to the Go value backing typ. +func castVariantValue(v variant.Value, typ PrimitiveType) (any, bool) { + raw := v.Value() + if raw == nil { + return nil, false + } + + if r, ok := exactVariantMatch(v.Type(), raw, typ); ok { + return r, true + } + + switch t := typ.(type) { + case Int32Type: + switch n := raw.(type) { + case int8: + return int32(n), true + case int16: + return int32(n), true + } + case Int64Type: + switch n := raw.(type) { + case int8: + return int64(n), true + case int16: + return int64(n), true + case int32: + return int64(n), true + } + case Float64Type: + if f, ok := raw.(float32); ok { + return float64(f), true + } + case FixedType: + if b, ok := raw.([]byte); ok && len(b) == t.Len() { + return b, true + } + case DecimalType: + return castVariantDecimal(raw, t) + case BooleanType: + if b, ok := raw.(bool); ok { + return b, true + } + case TimestampType, TimestampTzType: Review Comment: This was a great catch. The nanos/date casts now gate on tz-awareness and only accept the matching physical type, so a zoneless leaf can't land in a tz target. `TestCastVariantTimestampTZ` covers each pair. Also guarded the multiply against int64 overflow while I was in there; it was silently wrapping past ~year 2262. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
