Skip to content

feat: split INSERT .. SELECT <columns> FROM unnest(..) into sharded tables (not only SELECT *) - #2000

Merged
jkaczman merged 2 commits into
mainfrom
jk-unnest-select-targets
Nov 10, 2026
Merged

jkaczman merged 2 commits into
mainfrom
jk-unnest-select-targets

Conversation

@jkaczman

@jkaczman jkaczman commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

#1988, the previous PR implementing unnest split, only handled splitting when the SELECT for the INSERT was SELECT *, e.g., in INSERT INTO <sharded table> .. SELECT * FROM unnest($1, ..). As this is unimplemented functionality, since #1987, we (correctly) returned an error for this, as this is one of the cases not handled by that previous PR (anything other than SELECT *).

Now, as an extension of #1988, this PR also splits these unnest INSERTs when the SELECT explicitly lists the output columns of unnest(..) one at a time instead of *, as well as when the SELECT includes constants (e.g., NULL).

The motivation for this is fully completing unnest support (instead of VALUES) for re-writing subqueries.

E.g., if we have a statement such as

INSERT INTO subpackages (id, user_id, order_id) SELECT id, id + 1, NULL FROM suborders

The subquery support I'm working on for unnest will run SELECT id, id + 1, NULL FROM suborders on the shards. The shards return some rows, e.g., (1, 2, NULL), (2, 3, NULL) and (3, 4, NULL). Then, subqueries will send these rows back to the INSERT as unnest(..) arrays. However, the shards return the NULL column with the type text (default Postgres association for the NULL constant). If we sent the NULL column as an array too, the array would be a text[], and Postgres would return an error when we insert text into the bigint column order_id. Not to mention, this is inefficient. Therefore, I opted when implementing support for this in subqueries to keep the constants in the SELECT as a nice workaround:

INSERT INTO subpackages (id, user_id, order_id) SELECT u.c1, u.c2, NULL FROM unnest($1::pg_catalog._int8, $2::pg_catalog._int8) AS u(c1, c2)

SELECT * would only return the columns of unnest(..), so there'd be no way for SELECT to include the NULL with SELECT * without the array mentioned prior. Therefore, we need this PR before subquery support can use unnest(..) to properly split constants apart from the unnest array.

To route the rows, this follows the alias AS u(c1, c2) and the SELECT to find the unnest(..) argument that Postgres uses to insert into the sharding key. Then, the rows are routed as if the client sent INSERT INTO subpackages (id, user_id, order_id) VALUES ($1, $2, NULL).

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (arm64) failed. build failed to run.

Logs

build, verdict.json

Ran 00d0ea1 on m8g.metal-24xl (spot).

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (x86) failed. build failed to run.

Logs

build, verdict.json

Ran 00d0ea1 on c7i.metal-48xl (on-demand).

@jkaczman
jkaczman force-pushed the jk-unnest-select-targets branch 4 times, most recently from 9762111 to df1af3b Compare November 9, 2026 22:01
@codecov

codecov Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.47368% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...frontend/router/parser/rewrite/statement/insert.rs 99.32% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@jkaczman
jkaczman force-pushed the jk-unnest-select-targets branch 2 times, most recently from 456e183 to 86e48ab Compare November 9, 2026 23:52
Base automatically changed from jk-unnest-insert-split to main November 10, 2026 00:31
@jkaczman
jkaczman force-pushed the jk-unnest-select-targets branch from 86e48ab to 00d0ea1 Compare November 10, 2026 00:31
@jkaczman
jkaczman merged commit 4bb1985 into main Nov 10, 2026
41 of 44 checks passed
@jkaczman
jkaczman deleted the jk-unnest-select-targets branch November 10, 2026 02:12
jkaczman added a commit that referenced this pull request Nov 10, 2026
…, SELECT/UPDATE FROM (#2003)

Works off the previous changes implementing splitting INSERT with unnest
(#1988, #2000) to now implement this unnest functionality to be used
when re-writing subqueries (as opposed to re-writing the SQL to have an
explicit VALUES clause with all the DataRows inlined) when we send the
subquery data rows back to Postgres in the outer statement to be
evaluated.

This should be a considerable speedup vs. before; if we had 10,000
DataRows returned, it's much cheaper to include the data in an array in
a Bind parameter vs. creating a new SQL statement with 10,000 tuples and
deparsing it.

Not handled for WHERE clause yet. Will follow up.
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.

1 participant