-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Add non-callback based entry builder for row and array block builders #27198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Reviewer's GuideIntroduces a non-callback based entry builder by defining a RowEntryBuilder interface and integrating it into RowBlockBuilder alongside existing callback-based API, updates tests to cover both construction styles and error handling, and adjusts Revapi config to suppress the new interface from API checks. Class diagram for RowBlockBuilder and RowEntryBuilder changesclassDiagram
class RowBlockBuilder {
+buildEntry(RowValueBuilder<E> builder)
+buildEntry() RowEntryBuilder
-fieldBlockBuilders: BlockBuilder[]
-currentEntryOpened: boolean
}
class RowEntryBuilder {
+getFieldBuilder(int fieldId) BlockBuilder
+build()
}
class RowEntryBuilderImplementation {
+RowEntryBuilderImplementation()
+getFieldBuilder(int fieldId) BlockBuilder
+build()
}
RowBlockBuilder --> RowEntryBuilder
RowEntryBuilder <|.. RowEntryBuilderImplementation
RowEntryBuilderImplementation ..> BlockBuilder : uses
RowBlockBuilder ..> BlockBuilder : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `core/trino-spi/src/main/java/io/trino/spi/block/RowBlockBuilder.java:132-136` </location>
<code_context>
+ }
+
+ @Override
+ public BlockBuilder getFieldBuilder(int fieldId)
+ {
+ return fieldBlockBuilders[fieldId];
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Validate fieldId to prevent out-of-bounds access.
Add a bounds check for fieldId in getFieldBuilder to avoid IndexOutOfBoundsException and enhance robustness.
```suggestion
@Override
public BlockBuilder getFieldBuilder(int fieldId)
{
if (fieldId < 0 || fieldId >= fieldBlockBuilders.length) {
throw new IndexOutOfBoundsException("fieldId " + fieldId + " is out of bounds (0, " + (fieldBlockBuilders.length - 1) + ")");
}
return fieldBlockBuilders[fieldId];
}
```
</issue_to_address>
### Comment 2
<location> `core/trino-spi/src/main/java/io/trino/spi/block/RowBlockBuilder.java:138-143` </location>
<code_context>
+ }
+
+ @Override
+ public void build()
+ {
+ entryAdded(false);
</code_context>
<issue_to_address>
**suggestion:** Consider handling double build() calls gracefully.
Currently, repeated build() calls reset currentEntryOpened and trigger entryAdded(false) multiple times. Consider adding a guard to prevent unintended behavior from double builds.
```suggestion
@Override
public void build()
{
if (!currentEntryOpened) {
// Already built, ignore repeated build() calls
return;
}
entryAdded(false);
currentEntryOpened = false;
}
```
</issue_to_address>
### Comment 3
<location> `core/trino-spi/src/test/java/io/trino/spi/block/TestRowBlockBuilder.java:85-88` </location>
<code_context>
+ }
+ assertThat(blockToValues(blockBuilder.buildValueBlock())).isEqualTo(values);
+
+ blockBuilder = new RowBlockBuilder(List.of(VARCHAR, INTEGER, BOOLEAN), null, 1);
+ blockBuilder.buildEntry();
+ assertThatThrownBy(blockBuilder::buildEntry).isInstanceOf(IllegalStateException.class);
+ }
</code_context>
<issue_to_address>
**suggestion (testing):** Missing test for incomplete entry (no build call).
Add a test where buildEntry() is called without a subsequent build(), to confirm RowBlockBuilder's behavior with incomplete entries.
```suggestion
blockBuilder = new RowBlockBuilder(List.of(VARCHAR, INTEGER, BOOLEAN), null, 1);
blockBuilder.buildEntry();
assertThatThrownBy(blockBuilder::buildEntry).isInstanceOf(IllegalStateException.class);
// Test for incomplete entry (no build call)
RowBlockBuilder incompleteEntryBuilder = new RowBlockBuilder(List.of(VARCHAR, INTEGER, BOOLEAN), null, 1);
incompleteEntryBuilder.buildEntry();
assertThatThrownBy(incompleteEntryBuilder::buildValueBlock)
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Incomplete entry");
}
```
</issue_to_address>
### Comment 4
<location> `core/trino-spi/src/test/java/io/trino/spi/block/TestRowBlockBuilder.java:71-83` </location>
<code_context>
+ assertThat(blockToValues(blockBuilder.buildValueBlock())).isEqualTo(values);
+
+ blockBuilder = new RowBlockBuilder(List.of(VARCHAR, INTEGER, BOOLEAN), null, 1);
+ for (TestRow row : values) {
+ RowEntryBuilder rowEntryBuilder = blockBuilder.buildEntry();
+ if (row.name() == null) {
+ rowEntryBuilder.getFieldBuilder(0).appendNull();
+ }
+ else {
+ VARCHAR.writeString(rowEntryBuilder.getFieldBuilder(0), row.name());
+ }
+ INTEGER.writeLong(rowEntryBuilder.getFieldBuilder(1), row.number());
+ BOOLEAN.writeBoolean(rowEntryBuilder.getFieldBuilder(2), row.flag());
+ rowEntryBuilder.build();
+ }
+ assertThat(blockToValues(blockBuilder.buildValueBlock())).isEqualTo(values);
</code_context>
<issue_to_address>
**suggestion (testing):** Missing test for out-of-bounds field access in RowEntryBuilder.
Add a test that calls getFieldBuilder with an invalid index (negative or >= number of fields) to verify that RowEntryBuilder throws the correct exception.
```suggestion
for (TestRow row : values) {
RowEntryBuilder rowEntryBuilder = blockBuilder.buildEntry();
if (row.name() == null) {
rowEntryBuilder.getFieldBuilder(0).appendNull();
}
else {
VARCHAR.writeString(rowEntryBuilder.getFieldBuilder(0), row.name());
}
INTEGER.writeLong(rowEntryBuilder.getFieldBuilder(1), row.number());
BOOLEAN.writeBoolean(rowEntryBuilder.getFieldBuilder(2), row.flag());
rowEntryBuilder.build();
// Test out-of-bounds field access
assertThatThrownBy(() -> rowEntryBuilder.getFieldBuilder(-1))
.isInstanceOf(IndexOutOfBoundsException.class);
assertThatThrownBy(() -> rowEntryBuilder.getFieldBuilder(3))
.isInstanceOf(IndexOutOfBoundsException.class);
}
assertThat(blockToValues(blockBuilder.buildValueBlock())).isEqualTo(values);
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
core/trino-spi/src/test/java/io/trino/spi/block/TestRowBlockBuilder.java
Show resolved
Hide resolved
core/trino-spi/src/test/java/io/trino/spi/block/TestRowBlockBuilder.java
Show resolved
Hide resolved
0782396 to
d0dc089
Compare
core/trino-spi/src/main/java/io/trino/spi/block/ArrayEntryBuilder.java
Outdated
Show resolved
Hide resolved
core/trino-spi/src/main/java/io/trino/spi/block/RowEntryBuilder.java
Outdated
Show resolved
Hide resolved
There are cases where the row can not be completely build in a single callback. For example, when remapping json paths to multiple columns, the fields do not arrive in a single neat bundle.
d0dc089 to
6684339
Compare
Description
There are cases where the row or array can not be completely build in a single
callback. For example, when remapping json paths to multiple columns,
the fields do not arrive in a single neat bundle.
Release notes
I'm not sure this is worth adding a release note.
( ) This is not user-visible or is docs only, and no release notes are required.
( ) Release notes are required. Please propose a release note for me.
(X) Release notes are required, with the following suggested text: