Streaming aggregation implementation of ARRAY_AGG() - #4463
Conversation
c4bc382 to
6951560
Compare
ARRAY_AGG()ARRAY_AGG()
6951560 to
31f7c37
Compare
This change implements the `ArrayAggValue` built-in to evaluate the `ARRAY_AGG()` aggregate function, as a `StreamableAggregateValue` (as opposed to an `IndexableAggregateValue`; indexing would require a new index type or maintainer and is not in scope).
The `DISTINCT` and `ORDER BY` clauses are not yet supported. The `{RESPECT|IGNORE} NULLS` clause is, in principle, supported, but subject to the limitation that nulls in arrays cannot currently be represented (Issue #3646).
The accumulator collects elements into a list and (since `OneOfTypedState` has no list slot) serializes that list for continuations through a wrapper record with a single `repeated` field.
31f7c37 to
18da484
Compare
📊 Metrics Diff Analysis ReportSummary
ℹ️ About this analysisThis automated analysis compares query planner metrics between the base branch and this PR. It categorizes changes into:
The last category in particular may indicate planner regressions that should be investigated. New QueriesCount of new queries by file:
|
| * the element type will be non-nullable, since {@code NULL} values are then skipped rather than collected. | ||
| */ | ||
| public ArrayAggValue(@Nonnull final Value child, final boolean ignoreNulls) { | ||
| this(child, ignoreNulls ? child.getResultType().notNullable() : child.getResultType(), ignoreNulls); |
There was a problem hiding this comment.
if child.getResultType() == Type.NULL, notNullable() will throw an exception. is this expected? Or should the method verify child.getResultType() before this line?
| this.elementType = elementType; | ||
| this.ignoreNulls = ignoreNulls; | ||
| this.wrapperDescriptorSupplier = Suppliers.memoize(() -> wrapperDescriptorFor(elementType)); | ||
| this.resultTypeSupplier = Suppliers.memoize(() -> new Type.Array(true, elementType)); |
There was a problem hiding this comment.
so here the array's isNullable = true, while in line#145, it is constructed as Type.Array(false, elementType), is it intentional?
| Type.Record.Field.of(new Type.Array(false, elementType), | ||
| Optional.of(NullableArrayTypeUtils.getRepeatedFieldName())))); | ||
| final TypeRepository localRepository = TypeRepository.newBuilder().addTypeIfNeeded(wrapperType).build(); | ||
| return Verify.verifyNotNull(localRepository.getMessageDescriptor(wrapperType)); |
There was a problem hiding this comment.
are you trying to reuse some logics in TypeRepository here? is it possible to extract the logic as some static method and call the static method here instead?
| this.valuesField = Verify.verifyNotNull( | ||
| wrapperDescriptor.findFieldByName(NullableArrayTypeUtils.getRepeatedFieldName())); | ||
| this.elements = new ArrayList<>(); | ||
| this.ignoreNulls = ignoreNulls; |
There was a problem hiding this comment.
this.seenAnyRow = false;
| // Under IGNORE NULLS a NULL is simply dropped. Under RESPECT NULLS (the SQL default) it would have to | ||
| // be collected. However, nulls are not representable currently. | ||
| SemanticException.check(ignoreNulls, SemanticException.ErrorCode.UNSUPPORTED, | ||
| "An ARRAY value cannot have NULL elements"); |
There was a problem hiding this comment.
what happens if ignoreNulls = false?
| - maxRows: 1 | ||
| - result: [{10, [100, 200, 300]}] | ||
| - result: [{20, [400, 500]}] | ||
| - result: [{30, []}] |
There was a problem hiding this comment.
if not ignore nulls, will this row be result: [{30, [null]}]?
This change implements the
ArrayAggValuebuilt-in to evaluate theARRAY_AGG()aggregate function, as aStreamableAggregateValue(as opposed to anIndexableAggregateValue; indexing would require a new index type or maintainer and is not in scope).The
DISTINCTandORDER BYclauses are not yet supported. The{RESPECT|IGNORE} NULLSclause is, in principle, supported, but subject to the limitation that nulls in arrays cannot currently be represented (Issue #3646).The accumulator collects elements into a list and (since
OneOfTypedStatehas no list slot) serializes that list for continuations through a wrapper record with a singlerepeatedfield.