← 输入框|github.com|刷新
Skip to content

GH-830: Create Null children when building a struct writer from a Field - #1379

Open
ump45nose wants to merge 1 commit into
apache:mainfrom
ump45nose:fix/830-struct-writer-null-child
Open

ump45nose wants to merge 1 commit into
apache:mainfrom
ump45nose:fix/830-struct-writer-null-child

Conversation

@ump45nose

Copy link
Copy Markdown

What's Changed

NullableStructWriter / SingleStructWriter (generated from StructWriters.java) walk the struct field's children in their constructor and create a child vector for each one. There was no case NULL, so a struct whose field has a Null-typed child threw UnsupportedOperationException: Unknown type: NULL. Because StructVector builds its writer as soon as it is constructed, this broke new StructVector(field, ...) and anything that goes through it, such as StructVector#getTransferPair(Field, BufferAllocator) from the issue.

There is no writer for the Null type, so the new case only adds the NullVector child to the container (with the child's nullability). The resulting vector's field now matches the input field, and the other children's writers keep working as before.

Tests added to TestStructVector:

  • testStructVectorTransferPairWithNullType: the reproducer from the issue, plus a transfer() that checks the value count, struct validity and the NullVector child.
  • testStructVectorFromFieldWithNullChild: builds a StructVector straight from a Field with a Null child and an Int child, then writes through the struct writer.

Both fail on main with Unknown type: NULL and pass with this change. I also ran TestStructVector, TestComplexWriter, TestListVector, TestMapVector, TestUnionVector, TestDenseUnionVector, TestComplexCopier, TestPromotableWriter and TestSplitAndTransfer (all pass, both the default and netty runs), and mvn -pl vector spotless:check.

AI assistance disclosure: this change, its tests and this description were prepared with the help of an AI coding assistant. The tests listed above were run locally against this branch.

Closes #830.

… a Field

NullableStructWriter/SingleStructWriter threw "Unknown type: NULL" when
the struct field had a Null-typed child, which broke e.g.
StructVector#getTransferPair(Field, ...). Add the NullVector child instead.
@ump45nose

Copy link
Copy Markdown
Author

The "Ensure PR format" check is only waiting for a label. Could a maintainer add bug-fix? I do not have permission to label PRs here. (AI-assisted reply.)

@jbonofre jbonofre added the bug-fix PRs that fix a big. label Oct 21, 2026
@apache apache deleted a comment from github-actions Bot Oct 21, 2026
@jbonofre

Copy link
Copy Markdown
Member

@ump45nose I'm reviewing this PR. I set the label.

@github-actions github-actions Bot added this to the 20.0.0 milestone Oct 21, 2026
Comment on lines +89 to +95
case NULL: {
// There is no writer for the Null type, but the child vector still has to exist so that
// the container matches its field (e.g. when it is created from a Field by a TransferPair).
FieldType fieldType = new FieldType(addVectorAsNullable, MinorType.NULL.getType(), null, null);
container.addOrGet(child.getName(), fieldType, NullVector.class);
break;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addVectorAsNullable is lost further down: addOrGet -> FieldType.createNewSingleVector -> MinorType.NULL.getNewVector, which returns new NullVector(field.getName()). That always gives a nullable field with no metadata. So for a child like Field("n", FieldType.notNullable(ArrowType.Null.INSTANCE), null), the struct field doesn't match the input field.

Could we change Types.java (line 167) to return new NullVector(field); and pass the child own FieldType here? That keeps both nullability and metadata. It also fixes Field.createVector, which goes through the same getNewVector.

Suggested change
case NULL: {
// There is no writer for the Null type, but the child vector still has to exist so that
// the container matches its field (e.g. when it is created from a Field by a TransferPair).
FieldType fieldType = new FieldType(addVectorAsNullable, MinorType.NULL.getType(), null, null);
container.addOrGet(child.getName(), fieldType, NullVector.class);
break;
}
case NULL:
// There is no writer for the Null type, but the child vector still has to exist so that
// the container matches its field (e.g. when it is created from a Field by a TransferPair).
container.addOrGet(child.getName(), child.getFieldType(), NullVector.class);
break;


@Test
public void testStructVectorFromFieldWithNullChild() {
Field nullField = new Field("null_child", FieldType.nullable(ArrowType.Null.INSTANCE), null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this child be non nullable and carry metadata? Then assertEquals(structField, vector.getField()) below checks that the Null child field is kept. As written, it passes even though a non nullable Null child comes back nullable.

Suggested change
Field nullField = new Field("null_child", FieldType.nullable(ArrowType.Null.INSTANCE), null);
Field nullField =
new Field(
"null_child",
new FieldType(false, ArrowType.Null.INSTANCE, null, Map.of("k", "v")),
null);

NullVector toChild = toVector.getChild("null_child", NullVector.class);
assertNotNull(toChild);
assertEquals(3, toChild.getValueCount());
assertTrue(toChild.isNull(0));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NullVector.isNull always returns true, so this always passes. Checking the child field against the input would be more helpful:

Suggested change
assertTrue(toChild.isNull(0));
assertEquals(nullField, toChild.getField());

Same idea for line 402: s1 is built through the same getNewVector path, so assertEquals(s1.getField(), toVector.getField()) passes even when both are wrong. Comparing with structField would catch it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PRs that fix a big.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'Unknown type: NULL' when initialising a NullableStructWriter from a struct with NullVector children

2 participants