laskoviymishka commented on code in PR #1463:
URL: https://github.com/apache/iceberg-go/pull/1463#discussion_r3577774200


##########
transforms.go:
##########
@@ -77,7 +84,9 @@ func ParseTransform(s string) (Transform, error) {
                return HourTransform{}, nil
        }
 
-       return nil, fmt.Errorf("%w: %s", ErrInvalidTransform, s)
+       // Unknown transform: v3 readers must load these and ignore them when
+       // filtering instead of failing. Keep the original string so it 
round-trips.
+       return UnknownTransform{name: s}, nil

Review Comment:
   Since `ParseTransform` now keeps the original casing here and `Equals` 
compares `name` byte-for-byte, `"Custom_V2[3]"` and `"custom_v2[3]"` become two 
distinct `UnknownTransform`s — the new test even pins that behavior. On a 
partition spec that'd let two effectively-identical unknown fields coexist. 
Probably fine in practice, but I'd either normalize the stored name or leave a 
comment noting the case-sensitivity is intentional for round-trip fidelity.



##########
table/sorting_test.go:
##########
@@ -262,6 +280,33 @@ func TestUnmarshalInvalidSortTransform(t *testing.T) {
                ]
        }`
 
+       var order table.SortOrder
+       err := json.Unmarshal([]byte(j), &order)
+       require.NoError(t, err)
+       require.Equal(t, 3, order.Len())
+
+       var first table.SortField
+       for i, f := range order.Fields() {

Review Comment:
   Tiny thing — this loop only exists to grab field 0. `order.Fields()[0]` (or 
a `Field(0)` accessor if we add one) reads cleaner.



##########
partitions_test.go:
##########
@@ -191,6 +191,47 @@ func 
TestPartitionSpec_MarshalTextRejectsInvalidBucketTransform(t *testing.T) {
        require.ErrorContains(t, err, "numBuckets > 0")
 }
 
+// A v3 table may use a partition transform this implementation doesn't know.
+// Readers must load it and preserve it on write, ignoring it when filtering.
+func TestPartitionFieldUnknownTransformRoundTrip(t *testing.T) {

Review Comment:
   Nice that this proves the field round-trips. Could we add a sibling test 
that unmarshals a full table-metadata JSON — partition specs and all — with an 
unknown transform and asserts it loads clean? That's the case that actually 
matters for the read goal, and the one thing that proves loading a v3 table 
doesn't trip `validateTransform` anywhere on the metadata path. The field-level 
test doesn't exercise that.



##########
table/sorting.go:
##########
@@ -320,6 +320,10 @@ func newSortOrder(orderID int, fields []SortField, 
validateSourceIDs bool) (Sort
                                return SortOrder{}, fmt.Errorf("%w: sort field 
at index %d has invalid source IDs: %v",
                                        ErrInvalidSortSourceID, idx, err)
                        }
+                       if u, ok := field.Transform.(iceberg.UnknownTransform); 
ok {

Review Comment:
   Two things on this guard.
   
   First, it's stricter than the spec and than Java. The spec only forbids 
writing partition specs with unknown transforms, and Java's `SortOrder` builder 
doesn't reject unknown sort transforms (`canTransform` stays true). A v3 sort 
order round-tripped through `NewSortOrder` — say during `UpdateSortOrder` — 
would get wrongly rejected here. I think this ties into tanmayrauth's 
sort-order thread, so I want to make sure we actually want to reject on write 
at all, rather than tolerate it like Java does.
   
   Second, if we do keep it: it's inside the `validateSourceIDs` block, so the 
JSON unmarshal path (`validateSourceIDs=false`) skips it entirely, and 
`MetadataBuilder.AddSortOrder` bypasses it too. That's an inconsistent guard. 
I'd pull it out of the `validateSourceIDs` branch so write and load agree. wdyt?



##########
partitions.go:
##########
@@ -291,6 +291,8 @@ func validateTransform(transform Transform) error {
                return t.validateNumBuckets()
        case *BucketTransform:
                return t.validateNumBuckets()
+       case UnknownTransform:

Review Comment:
   This case is right for a direct write, but it also fires on the preserve 
path. `UpdateSpec.Apply` rebuilds the whole spec through 
`NewPartitionSpecOpts`, so every existing field — including a passthrough 
unknown-transform one we loaded from a v3 table — gets re-validated here. That 
means once a table has an unknown partition field, we can't evolve its spec at 
all: renaming or dropping an unrelated field fails with `ErrInvalidTransform` 
at commit.
   
   I'd only validate the fields being newly added, and route the preserved 
fields through a non-validating construction. Java rejects at the `UpdateSpec` 
constructor with a clear message rather than an opaque commit-time error, so an 
early guard there would be friendlier too. A test that evolves a spec on an 
unknown-transform table would lock this down. wdyt?



-- 
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]

Reply via email to