8000 fix(mysql): type a window aggregate over the current row as not null by colinhacks · Pull Request #115 · colinhacks/reylo · GitHub
[go: up one dir, main page]

Skip to content

fix(mysql): type a window aggregate over the current row as not null - #115

Merged
colinhacks merged 5 commits into
mainfrom
window-nonnull-mysql
Oct 24, 2026
Merged

colinhacks merged 5 commits into
mainfrom
window-nonnull-mysql

Conversation

@colinhacks
@colinhacks colinhacks commented Oct 24, 2026 •
Copy link
Copy Markdown
Owner

MySQL typed every aggregate used as a window function nullable but count and the bit functions: the server flags sum, avg, min, max, json_arrayagg and json_objectagg nullable under OVER whatever the frame. A frame that always holds the current row has that row's input, so now such an aggregate follows its argument there, and the JSON aggregates are never NULL.

Column Before After
sum(count(*)) over (order by date_format(published_at, '%Y-%m')), grouped by the month nullable non-null
sum(p.id) over (order by p.id), over (), over (partition by p.user_id) nullable non-null
max(p.title) over w with window w as (partition by p.user_id order by p.id) nullable non-null
json_arrayagg(p.note) over (partition by p.user_id) nullable non-null (its items stay nullable)
max(p.note) over (partition by p.user_id) with where p.note is not null nullable non-null
sum(p.id) over (order by p.id rows between 1 following and 2 following) nullable nullable
sum(p.id) over (order by p.published_at range between interval 1 day preceding and interval 1 day following) nullable nullable
sum(p.id) over (partition by u.id) over users u left join posts p nullable nullable

Frames that hold the current row. No frame clause (the whole partition, or with ORDER BY every row through the current row's last peer); a ROWS frame that starts at UNBOUNDED PRECEDING, n PRECEDING or CURRENT ROW and ends at CURRENT ROW, n FOLLOWING or UNBOUNDED FOLLOWING; and a RANGE frame whose bounds are unbounded or CURRENT ROW.

Frames that can leave it out, which stay nullable: a start n FOLLOWING, an end n PRECEDING, and any RANGE frame with an offset. Measured on 8.4, over a DATETIME column that holds a zero date, range between interval 1 day preceding and interval 1 day following finds no row for every row whose date is not NULL, so a RANGE offset claims nothing.

Named windows. OVER w and OVER (w …) take the frame of w where the call gives none, through a chain of definitions (w2 as (w1 order by …)); a window the WINDOW clause does not define claims nothing.

How. window_probe in engine/mysql/src/mysql_nulls.rs writes the statement with each such call replaced by its argument, under the same FROM, WHERE and GROUP BY; window_flags in engine/mysql/src/mysql.rs prepares it and takes the argument's NOT NULL flag, or the WHERE's proof of a bare column, for the call's column. json_arrayagg's JSON shape takes the same frame rule (mysql_shape.rs). Only sum, avg, min and max follow their argument: var_samp and stddev_samp are NULL over one row, so the variance family is left as the server flags it.

  • New oracle case oracle/cases/mysql_window_aggregates (23 statements, blessed on MySQL 8.4), with NULL and edge values in every ordering column. Under WITH ROLLUP the server's flags stand (rollup_window.sql).
  • Other cases' expected.txt lines that lost a ?, each a window aggregate over a frame holding the current row: mysql_json_shapes (json_arrayagg(id) over (), json_arrayagg(id = 1) over ()), mysql_row_counts (sum(count(*)) over ()), mysql_types (sum(whole) over () under where whole between 0 and 2), and mysql_server_flags (sum, max, min, avg and json_arrayagg over NOT NULL columns, and max(day) over () over a DATE NOT NULL that holds zero dates). The frames 1 preceding and 1 preceding and 1 following and 2 following there stay nullable.
  • The MySQL page's Nullability rules gain a Window functions entry, captured.

Checks: cargo build --workspace --all-targets with no warning, cargo test of every crate, the whole oracle with --strict-coverage (132 cases, 0 failed), engine/build.sh (only the MySQL artifact changes), nub run typecheck, nub run test with both databases (254 passed, 0 skipped), nub run build, and the site's capture and build.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 03:03
@pullfrog
pullfrog Bot commented Oct 24, 2026 •
Copy link
Copy Markdown
Contributor

No configured credential can serve this run. Your Claude Pro/Max subscription has hit its usage limit, which resets at 2026-10-26 08:00 UTC. Re-trigger after it resets, or add an API key for this provider, which Pullfrog falls back to automatically.

The providers' responses
CLAUDE_CODE_OAUTH_TOKEN: 429: This request would exceed your account's rate limit. Please try again later.

Pick another model →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using claude-opus-5-5

@vercel
vercel Bot commented Oct 24, 2026 •
Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
reylo Ready Ready Preview Oct 24, 2026 3:43am UTC

Request Review

Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@colinhacks
colinhacks force-pushed the window-nonnull-mysql branch from 9a2058a to ffd0767 Compare October 24, 2026 03:23
@pullfrog pullfrog Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues. Two minor suggestions inline.

Reviewed changes

Pullfrog has not reviewed this PR before, so this covers the whole PR, including the new commit that keeps the server's flags under a ROLLUP.

  • Frame rule: frame_holds_current_row accepts no frame clause, ROWS frames that start at or before the current row and end at or after it, and RANGE frames whose bounds are unbounded or CURRENT ROW. It follows named windows through chains of definitions.
  • Probe: window_probe replaces each sum/avg/min/max window call with its argument, and window_flags takes the argument's NOT NULL flag, or the WHERE's proof, for that column. It guards positions by comparing column counts.
  • ROLLUP exclusion (new commit): window_probe now returns None under WITH ROLLUP, so the server's flags stand there. The commit also rebuilds engine.wasm.
  • JSON shape: json_arrayagg over a frame that holds the current row is a non-null array at the top level.
  • Oracle and docs: adds the new mysql_window_aggregates case, loosens other cases' expected.txt only for frames that hold the current row, and adds a captured Window functions entry to the MySQL page.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread engine/mysql/src/mysql_nulls.rs Resolved
Comment thread site/content/docs/mysql.mdx Resolved
@pullfrog pullfrog Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found. Both points from the last review are addressed.

Reviewed changes

Since the last Pullfrog review, two commits address its two inline points.

  • ROLLUP pinned in the oracle: rollup_window.sql in mysql_window_aggregates is blessed with the server's own flags (running: numeric?, top_user: int4|int8?) under group by p.user_id with rollup, so the guard in window_probe now has an oracle case behind it.
  • Docs wording narrowed: the Window functions entry on the MySQL page now says only sum, avg, min and max follow their argument, and names json_arrayagg and json_objectagg as never null. This matches WINDOW_FOLLOWING and WINDOW_NEVER_NULL in mysql_nulls.rs.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

@colinhacks
colinhacks merged commit 1b2bbbf into main Oct 24, 2026
9 checks passed
@colinhacks
colinhacks deleted the window-nonnull-mysql branch October 24, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0