fix(sql): a view's HAVING reads every aggregate it names; GREATEST/LEAST skip NULL; DATEDIFF per group and by unit - #409
Merged
Conversation
…AST skip NULL; DATEDIFF per group and by unit One core function (Criteria.bucketMetrics / Having.metricNames) lists every aggregate a HAVING condition reads, for core's view rules, search and extensions. A view's HAVING may compare two aggregates or apply COALESCE, GREATEST, LEAST or SIGN over several; a bare ISNULL(MIN(a)) deploys again; a per-group calculation channel (BucketScriptTransformAggregation) lets a view store and filter SELECT arithmetic over aggregates. ISNULL/ISNOTNULL and the DATEDIFF family parse an aggregate operand as the aggregate; a SELECT alias inside a HAVING function is replaced by its aggregate at every depth; GREATEST/LEAST skip NULL arguments in HAVING. DATEDIFF / DATE_DIFF / TIMESTAMPDIFF run per group over aggregates, compute HOUR/MINUTE/SECOND on timestamps (DAY and above keep calendar dates), type literal operands and support QUARTER; over a window function with no GROUP BY they are refused by name. Docs follow the engine's date2 - date1 sign. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fupelaqu
marked this pull request as ready for review
October 2, 2026 17:25
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.
What
A materialized view's HAVING reads every aggregate it names. Before, a view declared one aggregate per comparison, so on 0.23.0 a
COALESCE(MAX(a), MIN(b))condition was silently dropped. On main it was refused, with remedies that pointed at each other.Criteria.bucketMetrics/Having.metricNames, lists every aggregate a HAVING condition reads. Core's view rules, the search path and (next) extensions read it.ISNULL(MIN(a))/ISNOTNULL(MIN(a))deploys again, with exactly the alias spelling's filter, as on 0.23.0.BucketScriptTransformAggregation, with the script params it reads, e.g.__now__) lets a view compute SELECT arithmetic over aggregates (MAX(a) - MIN(b) AS d) and filter on it. Such a column used to be declared in the view schema and never stored.Search: HAVING over functions of aggregates
ISNULL(MIN(r.a)).COALESCE(max_a, min_b) > 4) is replaced by its aggregate at every depth. Each shape now has one verdict and one message across its spellings, and is accepted again where expressible, as on 0.23.0.DATEDIFF / DATE_DIFF / TIMESTAMPDIFF
Docs: the DATEDIFF sign is
date2 - date1, the engine's behaviour, with corrected examples, the units, literals, and MySQL's two-argumentDATEDIFF(a, b) = a - b.Measured (ES 8.18.3 through the gateway; oracles computed independently in Scala)
Suites:
sql1785,es6bridge256,softclient4es8-sql-bridge263,core1148. ES 8.18.3 integration: 9 suites, 327/327. Lint (headerCheck scalafmtSbtCheck scalafmtCheck test:scalafmtCheck) is clean.Not run locally, left to CI: ES 6.8 / 7.17 / 9.0, the Scala 2.12 cross-compile, the es7 / es9 bridges. Extensions and arrow are not touched by this PR.
Behaviour changes (release notes)
ISNULL(MIN(r.a))and alias-in-function HAVING are accepted;GREATEST(MAX(a), NULL)(was an Elasticsearch compile error), andHAVING nested(s > 5)(views dropped the condition).Criteria.bucketMetrics(public),Having.metricNames,BucketScriptTransformAggregation,SingleSearch.transformBucketScripts/transformBucketScriptOperands;Expression.extractAllMetricsPath's override andIdentifier.allMetricsPath;Once the "two aggregates compared" rule is gone, extensions main still declares one aggregate per comparison, so such a view would come out partial or empty (HTTP 200) until the extensions PR lands. That PR:
Having.metricNamesin the view filter, and fails loudly instead of dropping a filter;__now__);🤖 Generated with Claude Code