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 fa9d60da fix(transforms): fix truncate transform for negative ints 
(#608)
fa9d60da is described below

commit fa9d60da93be0e54eea4460b87aa6f519991bbea
Author: Matt Topol <[email protected]>
AuthorDate: Wed Oct 22 13:24:53 2025 -0400

    fix(transforms): fix truncate transform for negative ints (#608)
    
    fixes #603
    
    Also adds unit tests for truncate transforms of various types
---
 transforms.go      |  6 ++++--
 transforms_test.go | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/transforms.go b/transforms.go
index bd4aee4c..720e8429 100644
--- a/transforms.go
+++ b/transforms.go
@@ -413,8 +413,9 @@ func (t TruncateTransform) Transformer(src Type) (func(any) 
any, error) {
                        }
 
                        val := v.(int32)
+                       width := int32(t.Width)
 
-                       return val - (val % int32(t.Width))
+                       return val - (((val % width) + width) % width)
                }, nil
        case Int64Type:
                return func(v any) any {
@@ -423,8 +424,9 @@ func (t TruncateTransform) Transformer(src Type) (func(any) 
any, error) {
                        }
 
                        val := v.(int64)
+                       width := int64(t.Width)
 
-                       return val - (val % int64(t.Width))
+                       return val - (((val % width) + width) % width)
                }, nil
        case StringType, BinaryType:
                return func(v any) any {
diff --git a/transforms_test.go b/transforms_test.go
index 92e20513..ce6fa7af 100644
--- a/transforms_test.go
+++ b/transforms_test.go
@@ -19,12 +19,14 @@ package iceberg_test
 
 import (
        "bytes"
+       "fmt"
        "reflect"
        "strings"
        "testing"
        "time"
 
        "github.com/apache/arrow-go/v18/arrow/decimal"
+       "github.com/apache/arrow-go/v18/arrow/decimal128"
        "github.com/apache/iceberg-go"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
@@ -355,3 +357,37 @@ func TestCanTransform(t *testing.T) {
                }
        }
 }
+
+func TestTruncateTransform(t *testing.T) {
+       tests := []struct {
+               width    int
+               value    iceberg.Literal
+               expected iceberg.Literal
+       }{
+               {10, iceberg.Int32Literal(1), iceberg.Int32Literal(0)},
+               {10, iceberg.Int32Literal(-1), iceberg.Int32Literal(-10)},
+               {10, iceberg.Int64Literal(1), iceberg.Int64Literal(0)},
+               {10, iceberg.Int64Literal(-1), iceberg.Int64Literal(-10)},
+               {50, iceberg.DecimalLiteral{
+                       Val:   decimal128.FromI64(1065),
+                       Scale: 2,
+               }, iceberg.DecimalLiteral{
+                       Val:   decimal128.FromI64(1050),
+                       Scale: 2,
+               }},
+               {3, iceberg.StringLiteral("abcdef"), 
iceberg.StringLiteral("abc")},
+               {
+                       3, iceberg.BinaryLiteral([]byte{0x01, 0x02, 0x03, 0x04, 
0x05}),
+                       iceberg.BinaryLiteral([]byte{0x01, 0x02, 0x03}),
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(fmt.Sprintf("width=%d value=%v", tt.width, 
tt.value.Any()), func(t *testing.T) {
+                       transform := iceberg.TruncateTransform{Width: tt.width}
+                       result := 
transform.Apply(iceberg.Optional[iceberg.Literal]{Val: tt.value, Valid: true})
+                       require.True(t, result.Valid)
+                       assert.Equal(t, tt.expected, result.Val)
+               })
+       }
+}

Reply via email to