You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by ze...@apache.org on 2026/07/27 20:30:01 UTC

(iceberg-go) branch main updated: fix(literals): reject timestamp nanos overflow (#1533)

This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new f8cc75a45 fix(literals): reject timestamp nanos overflow (#1533)
f8cc75a45 is described below

commit f8cc75a458ddbf58c31adc906b9f90e593d87216
Author: Minh Vu <vu...@gmail.com>
AuthorDate: Mon Jul 27 22:29:49 2026 +0200

    fix(literals): reject timestamp nanos overflow (#1533)
    
    ## Summary
    
    - check microsecond timestamp bounds before converting to nanoseconds
    - return ErrBadCast instead of silently wrapping int64 values
    - cover both timestamp_ns variants and both overflow directions
    
    This follows the checked multiplication used by the Java implementation.
    
    ## Testing
    
    - go test . -count=1
    - all repository packages except io/gocloud
---
 literals.go      |  8 +++++---
 literals_test.go | 29 +++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/literals.go b/literals.go
index ec5a5fced..5a0a068de 100644
--- a/literals.go
+++ b/literals.go
@@ -824,9 +824,11 @@ func (t TimestampLiteral) To(typ Type) (Literal, error) {
 		return t, nil
 	case TimestampTzType:
 		return t, nil
-	case TimestampNsType:
-		return TimestampNsLiteral(Timestamp(t).ToNanos()), nil
-	case TimestampTzNsType:
+	case TimestampNsType, TimestampTzNsType:
+		if t > math.MaxInt64/1000 || t < math.MinInt64/1000 {
+			return nil, fmt.Errorf("%w: timestamp %d is outside the nanosecond range", ErrBadCast, t)
+		}
+
 		return TimestampNsLiteral(Timestamp(t).ToNanos()), nil
 	case DateType:
 		return DateLiteral(Timestamp(t).ToDate()), nil
diff --git a/literals_test.go b/literals_test.go
index e4715dda7..42875df10 100644
--- a/literals_test.go
+++ b/literals_test.go
@@ -235,6 +235,35 @@ func TestTimestampNanoLiteralConversions(t *testing.T) {
 	}
 }
 
+func TestTimestampLiteralToNanosRejectsOverflow(t *testing.T) {
+	targets := []iceberg.Type{
+		iceberg.PrimitiveTypes.TimestampNs,
+		iceberg.PrimitiveTypes.TimestampTzNs,
+	}
+
+	for _, target := range targets {
+		t.Run(target.String(), func(t *testing.T) {
+			for _, value := range []iceberg.TimestampLiteral{
+				iceberg.TimestampLiteral(math.MaxInt64/1000 + 1),
+				iceberg.TimestampLiteral(math.MinInt64/1000 - 1),
+			} {
+				actual, err := value.To(target)
+				assert.Nil(t, actual)
+				assert.ErrorIs(t, err, iceberg.ErrBadCast)
+			}
+
+			for _, value := range []iceberg.TimestampLiteral{
+				iceberg.TimestampLiteral(math.MaxInt64 / 1000),
+				iceberg.TimestampLiteral(math.MinInt64 / 1000),
+			} {
+				actual, err := value.To(target)
+				require.NoError(t, err)
+				assert.Equal(t, iceberg.TimestampNsLiteral(value*1000), actual)
+			}
+		})
+	}
+}
+
 func TestInt64Conversions(t *testing.T) {
 	tests := []struct {
 		from iceberg.Int64Literal