Return one NULL row for last_by over a never-written device (#16985)#18267
Open
PDGGK wants to merge 1 commit into
Open
Return one NULL row for last_by over a never-written device (#16985)#18267PDGGK wants to merge 1 commit into
PDGGK wants to merge 1 commit into
Conversation
…6985) A global aggregation without GROUP BY always produces exactly one row; over empty input every aggregate except count() evaluates to NULL. For the last-cache-optimized last/last_by path, a device set that resolves to zero devices (e.g. a filter on a device that was never written) left the operator with nothing to iterate, so it returned zero rows instead of the single NULL row required by SQL semantics (consistent with engines such as Trino). LastQueryAggTableScanOperator now emits one all-NULL row when there are zero devices, no GROUP BY, and the aggregation is at its final/complete stage. GROUP BY over an empty group still returns no rows, and a partial stage still emits nothing. The deleted-device case (the device still exists, so the operator iterates and already emits the NULL row) is unchanged. Scoped to last/last_by; the general aggregation operator (max/min/sum/avg) likely returns empty for a never-written device too and is left as a follow-up. Signed-off-by: Zihan Dai <99155080+PDGGK@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Per @Wei-hao-Li's clarification in #16985: an aggregate function should always return NULL when there is no input data (except
count), consistent with SQL-standard engines such as Trino. Soselect last_by(s0, time) from t where deviceId = 'never'— where the device was never written — must return exactly one row whose value is NULL, not zero rows.Root cause: for the last-cache-optimized
last/last_bypath, a device set that resolves to zero devices leavesLastQueryAggTableScanOperatorwithallDeviceCount == 0, so the device loop never runs and the operator returns no rows.How
LastQueryAggTableScanOperatornow emits one all-NULL row when there are zero devices, no GROUP BY, and the aggregation is at its final/complete stage (each aggregator's no-inputevaluate()writes NULL forlast/last_by). Guards:Tests
IoTDBDeletionTableIT: a never-written device queried with 2-arg and 3-arglast_byreturns one NULL row; multiplelast_byaggregates return one all-NULL row; GROUP BY over a never-written device returns no rows; and a regression check that a deleted device still returns one NULL row (both the last-value-cache and recomputed paths).Scope
Scoped to
last/last_by. The general aggregation operator (max/min/sum/avg) likely returns empty for a never-written device as well; that is left as a follow-up rather than expanding this PR.Relates to #16985.