You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@iceberg.apache.org by "the-onewho-knocks (via GitHub)" <gi...@apache.org> on 2026/06/26 12:57:05 UTC

[PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

the-onewho-knocks opened a new pull request, #1321:
URL: https://github.com/apache/iceberg-go/pull/1321

   **Summary**
   
   * add `WithManifestFileFirstRowID`, a `ManifestFileOption` that sets `first_row_id` on a v3+ data manifest
   * forward variadic `ManifestFileOption` args through `WriteManifest` to `ToManifestFile`
   
   **Why**
   
   `WriteManifest` predates the v3 work in #735 and forwarded no options to `ToManifestFile`, so `ManifestFile.FirstRowID()` was always `nil` for manifests written through this public helper, even though `ManifestWriter`/`ToManifestFile` already supported setting it via `opts`. Library consumers had no way to set or observe `first_row_id` through `WriteManifest`.
   
   `WriteManifest`'s signature change is purely additive (`opts` is the last, variadic parameter), so existing call sites are unaffected.
   
   **Testing**
   
   * `go test ./... -run '^TestWriteManifestWithFirstRowIDOption$' -count=1`
   * `go test ./... -count=1`
   * `gofmt -l .`
   * `golangci-lint run`
   
   Fixes #1274


-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "laskoviymishka (via GitHub)" <gi...@apache.org>.
laskoviymishka merged PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321


-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "zeroshade (via GitHub)" <gi...@apache.org>.
zeroshade commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3493439912


##########
manifest.go:
##########
@@ -1306,6 +1306,10 @@ func (w *ManifestWriter) ToManifestFile(location string, length int64, opts ...M
 		apply(&mf)
 	}
 
+	if mf.Content == ManifestContentDeletes && mf.FirstRowIDValue != nil {

Review Comment:
   This guard is unreachable from the public API: no `ManifestFileOption` sets `FirstRowIDValue` (only `WithManifestFileContent` exists) and `ToManifestFile` inits it to nil. The PR description mentions a `WithManifestFileFirstRowID` option + variadic `WriteManifest`, but neither is in the diff — only this check landed. Either add the missing option/variadic, or drop the dead guard for now.



##########
manifest.go:
##########
@@ -1651,6 +1657,52 @@ func WriteManifest(
 	return w.ToManifestFile(filename, cnt.Count)
 }
 
+// WriteManifestV3 writes a v3 data manifest and assigns first_row_id.
+// The returned ManifestFile has FirstRowID() set to firstRowID.
+// nextFirstRowID is firstRowID + AddedRowsCount + ExistingRowsCount
+// for the caller to chain to the next manifest. Use this only for
+// reconstruction — manifests committed through a v3 list writer get
+// first_row_id from AddManifests; pre-setting collides with that allocation.
+func WriteManifestV3(
+	filename string,
+	out io.Writer,
+	firstRowID int64,
+	spec PartitionSpec,
+	schema *Schema,
+	snapshotID int64,
+	entries []ManifestEntry,
+) (mf ManifestFile, nextFirstRowID int64, err error) {
+	cnt := &internal.CountingWriter{W: out}
+
+	w, err := NewManifestWriter(3, cnt, spec, schema, snapshotID)
+	if err != nil {
+		return nil, 0, err
+	}
+	defer internal.CheckedClose(w, &err)
+
+	for _, entry := range entries {
+		if err := w.addEntry(entry.(*manifestEntry)); err != nil {
+			return nil, 0, err
+		}
+	}
+
+	if err := w.Close(); err != nil {

Review Comment:
   `w.Close()` ends up called three times on success (here, again inside `ToManifestFile`, and via the deferred `CheckedClose`). Idempotent so safe, but this explicit close is redundant — `ToManifestFile` already closes to finalize `cnt.Count`. Consider dropping it to mirror `WriteManifest`.



##########
manifest_test.go:
##########
@@ -1158,6 +1159,129 @@ func (m *ManifestTestSuite) TestV3DataManifestFirstRowIDInheritanceSkipsDeletedE
 	m.EqualValues(1000+liveCount, *read[2].DataFile().FirstRowID())
 }
 
+func (m *ManifestTestSuite) TestWriteManifestV3() {

Review Comment:
   Coverage gap: only `EntryStatusADDED` entries are exercised. Add a mixed ADDED/EXISTING/DELETED case asserting `nextFirstRowID == firstRowID + AddedRowsCount + ExistingRowsCount` (and that DELETED is excluded) to lock the documented contract.



##########
manifest.go:
##########
@@ -1651,6 +1657,52 @@ func WriteManifest(
 	return w.ToManifestFile(filename, cnt.Count)
 }
 
+// WriteManifestV3 writes a v3 data manifest and assigns first_row_id.
+// The returned ManifestFile has FirstRowID() set to firstRowID.
+// nextFirstRowID is firstRowID + AddedRowsCount + ExistingRowsCount
+// for the caller to chain to the next manifest. Use this only for
+// reconstruction — manifests committed through a v3 list writer get
+// first_row_id from AddManifests; pre-setting collides with that allocation.
+func WriteManifestV3(
+	filename string,
+	out io.Writer,
+	firstRowID int64,
+	spec PartitionSpec,
+	schema *Schema,
+	snapshotID int64,
+	entries []ManifestEntry,
+) (mf ManifestFile, nextFirstRowID int64, err error) {
+	cnt := &internal.CountingWriter{W: out}
+
+	w, err := NewManifestWriter(3, cnt, spec, schema, snapshotID)
+	if err != nil {
+		return nil, 0, err
+	}
+	defer internal.CheckedClose(w, &err)
+
+	for _, entry := range entries {
+		if err := w.addEntry(entry.(*manifestEntry)); err != nil {
+			return nil, 0, err
+		}
+	}
+
+	if err := w.Close(); err != nil {
+		return nil, 0, err
+	}
+
+	mf, err = w.ToManifestFile(filename, cnt.Count)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	raw := mf.(*manifestFile)
+	v := firstRowID
+	raw.FirstRowIDValue = &v

Review Comment:
   `FirstRowIDValue` is set post-finalize with no precondition on entry content/status, so passing delete entries yields `Content=ManifestContentData` + a `FirstRowID` anyway — bypassing the guard above. Consider asserting `Content == ManifestContentData` (or rejecting non-data entries) before assigning.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "laskoviymishka (via GitHub)" <gi...@apache.org>.
laskoviymishka commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3490780616


##########
manifest_test.go:
##########
@@ -1158,6 +1158,110 @@ func (m *ManifestTestSuite) TestV3DataManifestFirstRowIDInheritanceSkipsDeletedE
 	m.EqualValues(1000+liveCount, *read[2].DataFile().FirstRowID())
 }
 
+func (m *ManifestTestSuite) TestWriteManifestWithFirstRowIDOption() {
+	partitionSpec := NewPartitionSpecID(1,
+		PartitionField{FieldID: 1000, SourceIDs: []int{1}, Name: "x", Transform: IdentityTransform{}})
+	count := int64(10)
+	entries := []ManifestEntry{
+		&manifestEntry{
+			EntryStatus: EntryStatusADDED,
+			Snapshot:    &entrySnapshotID,
+			Data: &dataFile{
+				Content:          EntryContentData,
+				Path:             "/data/file1.parquet",
+				Format:           ParquetFile,
+				PartitionData:    map[string]any{"x": int(1)},
+				RecordCount:      count,
+				FileSize:         1000,
+				BlockSizeInBytes: 64 * 1024,
+				FirstRowIDField:  nil,
+			},
+		},
+		&manifestEntry{
+			EntryStatus: EntryStatusADDED,
+			Snapshot:    &entrySnapshotID,
+			Data: &dataFile{
+				Content:          EntryContentData,
+				Path:             "/data/file2.parquet",
+				Format:           ParquetFile,
+				PartitionData:    map[string]any{"x": int(2)},
+				RecordCount:      count,
+				FileSize:         2000,
+				BlockSizeInBytes: 64 * 1024,
+				FirstRowIDField:  nil,
+			},
+		},
+	}
+
+	// Test 1: WriteManifest with WithManifestFileFirstRowID sets the field.
+	var bufWithID bytes.Buffer
+	firstRowID := int64(500)
+	mf, err := WriteManifest("/manifest.avro", &bufWithID, 3, partitionSpec, testSchema, entrySnapshotID, entries,
+		WithManifestFileFirstRowID(firstRowID))
+	m.Require().NoError(err)
+	m.Require().NotNil(mf.FirstRowID())
+	m.Equal(firstRowID, *mf.FirstRowID())
+
+	// Reading back, entries inherit first_row_id from the manifest file.
+	read, err := ReadManifest(mf, bytes.NewReader(bufWithID.Bytes()), false)
+	m.Require().NoError(err)
+	m.Require().Len(read, 2)
+	m.Require().NotNil(read[0].DataFile().FirstRowID())
+	m.EqualValues(firstRowID, *read[0].DataFile().FirstRowID())
+	m.Require().NotNil(read[1].DataFile().FirstRowID())
+	m.EqualValues(firstRowID+count, *read[1].DataFile().FirstRowID())
+
+	// Test 2: WriteManifest without option leaves FirstRowID nil (backward compat).
+	var bufNoID bytes.Buffer
+	mf2, err := WriteManifest("/manifest.avro", &bufNoID, 3, partitionSpec, testSchema, entrySnapshotID, entries)

Review Comment:
   Once the design and the guards settle, the coverage will want to follow. Right now the two cases cover the happy path and backward-compat, but the no-op behaviors the doc promises are exactly what's untested — v1/v2 dropping the value, and a delete manifest rejecting it. I'd also add an `AddManifests` case with one pre-set and one nil-ID manifest asserting non-overlapping ranges, since that's the scenario most likely to bite.
   
   Smaller things while you're here: these read more naturally as two focused subtests than comment-delimited blocks in one method (if Test 1's `Require` aborts, Test 2 never runs), and the block mixes `m.Equal` and `m.EqualValues` on the same `int64` — neighboring tests use `EqualValues` throughout.



##########
manifest.go:
##########
@@ -1274,6 +1274,16 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 

Review Comment:
   Assuming the option survives the design question above — the doc says "v3+ data manifest" but the closure enforces neither the version nor the content. On v1/v2 we set `FirstRowIDValue` in memory and then `toV1()` silently drops it at encode time, so what you read back diverges from what's persisted, with no error. And nothing stops `WithManifestFileContent(ManifestContentDeletes)` + this producing a delete manifest with a non-null `first_row_id`, which the spec says is always null (Java's list writer asserts `content() != DATA || firstRowId() != null` rather than allowing it).
   
   `ManifestFileOption` is `func(mf *manifestFile)`, so it can't return an error or see the version at apply time — the in-closure guard (`if mf.version < 3 { return }`) is really the only place for the version check. The delete case is trickier because option order matters, so I'd validate that one in `ToManifestFile` after all opts are applied rather than in the closure.



##########
manifest.go:
##########
@@ -1274,6 +1274,16 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 
+// WithManifestFileFirstRowID sets the first_row_id on a v3+ data manifest.
+// Silently no-ops on v1/v2 manifests since the field does not exist in those formats.
+func WithManifestFileFirstRowID(firstRowID int64) ManifestFileOption {

Review Comment:
   Independent of the API-shape question — this stores the address of the by-value parameter, so applying the same option instance to two manifests shares one `*int64`. Single-call is fine, but reuse aliases the storage, and any downstream mutation through the pointer would leak across manifests.
   
   Copy into the closure so each application gets its own allocation, the way `AddManifests` does (`firstRowID := *m.nextRowID` before taking its address):
   
   ```go
   return func(mf *manifestFile) {
   	v := firstRowID
   	mf.FirstRowIDValue = &v
   }
   ```



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3491541246


##########
manifest.go:
##########
@@ -1274,6 +1274,16 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 

Review Comment:
   moving to WriteManifestV3 resolves the v1/v2 silent-drop issue structurally, since the function only exists for v3 callers, so there's no toV1() divergence to worry about. For the delete-manifest case, I'll validate in the function itself after all options are applied (inside what's currently ToManifestFile), returning an error if Content == ManifestContentDeletes and a first_row_id was requested, rather than trying to enforce it from inside a single option closure.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3491547094


##########
manifest.go:
##########
@@ -1274,6 +1274,16 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 
+// WithManifestFileFirstRowID sets the first_row_id on a v3+ data manifest.
+// Silently no-ops on v1/v2 manifests since the field does not exist in those formats.
+func WithManifestFileFirstRowID(firstRowID int64) ManifestFileOption {

Review Comment:
   Since WriteManifestV3 takes firstRowID directly as a parameter rather than going through a reusable ManifestFileOption closure, this particular aliasing pattern goes away but I'll still make sure the value is copied into its own allocation at the point it's stored on the manifestFile, same as AddManifests does, rather than taking the address of a shared variable.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3484940386


##########
manifest.go:
##########
@@ -1628,6 +1635,7 @@ func WriteManifest(
 	schema *Schema,
 	snapshotID int64,
 	entries []ManifestEntry,
+	opts ...ManifestFileOption,

Review Comment:
   Added a doc comment on WriteManifest in b6f3bbb, calling out that opts can include v3-specific options like WithManifestFileFirstRowID.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3491517768


##########
manifest.go:
##########
@@ -1274,6 +1274,16 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 

Review Comment:
   agreed I'll go with WriteManifestV3(...) (ManifestFile, int64, error). A dedicated v3 entrypoint makes the reconstruction only use case explicit at the call site, rather than relying on a doc contract for a general option that looks identical to WithManifestFileContent but carries this footgun. Neither shape changes where the actual safety boundary lives that's still AddManifests's nil-check but this makes accidental misuse much less likely.
   Will drop WithManifestFileFirstRowID and rework as described below



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3491551226


##########
manifest_test.go:
##########
@@ -1158,6 +1158,110 @@ func (m *ManifestTestSuite) TestV3DataManifestFirstRowIDInheritanceSkipsDeletedE
 	m.EqualValues(1000+liveCount, *read[2].DataFile().FirstRowID())
 }
 
+func (m *ManifestTestSuite) TestWriteManifestWithFirstRowIDOption() {
+	partitionSpec := NewPartitionSpecID(1,
+		PartitionField{FieldID: 1000, SourceIDs: []int{1}, Name: "x", Transform: IdentityTransform{}})
+	count := int64(10)
+	entries := []ManifestEntry{
+		&manifestEntry{
+			EntryStatus: EntryStatusADDED,
+			Snapshot:    &entrySnapshotID,
+			Data: &dataFile{
+				Content:          EntryContentData,
+				Path:             "/data/file1.parquet",
+				Format:           ParquetFile,
+				PartitionData:    map[string]any{"x": int(1)},
+				RecordCount:      count,
+				FileSize:         1000,
+				BlockSizeInBytes: 64 * 1024,
+				FirstRowIDField:  nil,
+			},
+		},
+		&manifestEntry{
+			EntryStatus: EntryStatusADDED,
+			Snapshot:    &entrySnapshotID,
+			Data: &dataFile{
+				Content:          EntryContentData,
+				Path:             "/data/file2.parquet",
+				Format:           ParquetFile,
+				PartitionData:    map[string]any{"x": int(2)},
+				RecordCount:      count,
+				FileSize:         2000,
+				BlockSizeInBytes: 64 * 1024,
+				FirstRowIDField:  nil,
+			},
+		},
+	}
+
+	// Test 1: WriteManifest with WithManifestFileFirstRowID sets the field.
+	var bufWithID bytes.Buffer
+	firstRowID := int64(500)
+	mf, err := WriteManifest("/manifest.avro", &bufWithID, 3, partitionSpec, testSchema, entrySnapshotID, entries,
+		WithManifestFileFirstRowID(firstRowID))
+	m.Require().NoError(err)
+	m.Require().NotNil(mf.FirstRowID())
+	m.Equal(firstRowID, *mf.FirstRowID())
+
+	// Reading back, entries inherit first_row_id from the manifest file.
+	read, err := ReadManifest(mf, bytes.NewReader(bufWithID.Bytes()), false)
+	m.Require().NoError(err)
+	m.Require().Len(read, 2)
+	m.Require().NotNil(read[0].DataFile().FirstRowID())
+	m.EqualValues(firstRowID, *read[0].DataFile().FirstRowID())
+	m.Require().NotNil(read[1].DataFile().FirstRowID())
+	m.EqualValues(firstRowID+count, *read[1].DataFile().FirstRowID())
+
+	// Test 2: WriteManifest without option leaves FirstRowID nil (backward compat).
+	var bufNoID bytes.Buffer
+	mf2, err := WriteManifest("/manifest.avro", &bufNoID, 3, partitionSpec, testSchema, entrySnapshotID, entries)

Review Comment:
   Will rework the tests once WriteManifestV3 lands splitting into focused subtests (so an early Require failure doesn't silently skip later cases), adding the delete-manifest rejection case, and an AddManifests case with one pre-set and one nil-ID manifest to assert non-overlapping ranges. Will also switch to EqualValues consistently for the int64 comparisons. Thanks for flagging the test-isolation issue too clearly worth fixing regardless of the API shape.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "zeroshade (via GitHub)" <gi...@apache.org>.
zeroshade commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3482956971


##########
manifest.go:
##########
@@ -1274,6 +1274,13 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 
+// WithManifestFileFirstRowID sets the first_row_id on a v3+ data manifest.
+func WithManifestFileFirstRowID(firstRowID int64) ManifestFileOption {
+	return func(mf *manifestFile) {
+		mf.FirstRowIDValue = &firstRowID

Review Comment:
   nit: `mf.version` is already set before options are applied, so this could self-gate to v3+ where `first_row_id` actually exists:
   
   ```go
   if mf.version >= 3 {
       mf.FirstRowIDValue = &firstRowID
   }
   ```
   
   As written, calling this against a v1/v2 writer returns a `ManifestFile` whose `FirstRowID()` is non-nil but gets silently dropped on serialize. `WithManifestFileContent` has the same no-guard pattern so I'm fine either way, but the v3 exclusivity is a bit stronger here.



##########
manifest.go:
##########
@@ -1628,6 +1635,7 @@ func WriteManifest(
 	schema *Schema,
 	snapshotID int64,
 	entries []ManifestEntry,
+	opts ...ManifestFileOption,

Review Comment:
   nit (pre-existing): `WriteManifest` is exported but has no doc comment. Since you're already touching the signature, a one-liner noting that `opts` set v3-specific descriptor fields (e.g. `WithManifestFileFirstRowID`) would be a welcome add.



##########
manifest_test.go:
##########
@@ -1158,6 +1158,66 @@ func (m *ManifestTestSuite) TestV3DataManifestFirstRowIDInheritanceSkipsDeletedE
 	m.EqualValues(1000+liveCount, *read[2].DataFile().FirstRowID())
 }
 
+func (m *ManifestTestSuite) TestWriteManifestWithFirstRowIDOption() {

Review Comment:
   nit: consider adding (a) a v1/v2 + `WithManifestFileFirstRowID` case to pin the intended behavior (no-op vs non-nil `FirstRowID()`), and (b) a delete-manifest case, since the spec restricts `first_row_id` to data manifests. The read side already gates inheritance on `formatVersion >= 3 && content == data`, so this just locks down the write side.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3484939333


##########
manifest_test.go:
##########
@@ -1158,6 +1158,66 @@ func (m *ManifestTestSuite) TestV3DataManifestFirstRowIDInheritanceSkipsDeletedE
 	m.EqualValues(1000+liveCount, *read[2].DataFile().FirstRowID())
 }
 
+func (m *ManifestTestSuite) TestWriteManifestWithFirstRowIDOption() {

Review Comment:
   Added both in b6f3bbb:
   
   a v1 manifest + WithManifestFileFirstRowID case confirming it's a no-op (FirstRowID() is nil)
   a v3 delete-manifest case confirming the field can be set on the manifest itself (the guard only checks version), but entries don't inherit first_row_id on read since that's separately gated on content == data in the reader



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org


Re: [PR] feat: let WriteManifest set and return v3 first_row_id [iceberg-go]

Posted by "the-onewho-knocks (via GitHub)" <gi...@apache.org>.
the-onewho-knocks commented on code in PR #1321:
URL: https://github.com/apache/iceberg-go/pull/1321#discussion_r3484935386


##########
manifest.go:
##########
@@ -1274,6 +1274,13 @@ func WithManifestFileContent(content ManifestContent) ManifestFileOption {
 	}
 }
 
+// WithManifestFileFirstRowID sets the first_row_id on a v3+ data manifest.
+func WithManifestFileFirstRowID(firstRowID int64) ManifestFileOption {
+	return func(mf *manifestFile) {
+		mf.FirstRowIDValue = &firstRowID

Review Comment:
   added the mf.version >= 3 guard in b6f3bbb, with a doc comment noting it's a no-op on v1/v2 agreed it's worth being explicit here even though WithManifestFileContent doesn't guard the same way.



-- 
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: issues-unsubscribe@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@iceberg.apache.org
For additional commands, e-mail: issues-help@iceberg.apache.org