Skip to content

Implemented RETURNING support for SQL#3935

Open
egormanga wants to merge 3 commits into
clockworklabs:masterfrom
egormanga:sql-returning
Open

Implemented RETURNING support for SQL#3935
egormanga wants to merge 3 commits into
clockworklabs:masterfrom
egormanga:sql-returning

Conversation

@egormanga

Copy link
Copy Markdown
Contributor

Description of Changes

SQL RETURNING for DML to return affected rows to the caller:

INSERT INTO test (a, b)
VALUES (1, 2)
RETURNING *;

gives:

 a | b 
---+---
 1 | 2 

(same goes for UPDATE & DELETE).

Individual columns can be specified, too — separately from the fields the statement operates on:

UPDATE test
SET a = 1
WHERE b < 2
RETURNING b;

allowing to efficiently combine DML with implicit SELECTs.

API and ABI breaking changes

None.

Expected complexity level and risk

2.

Testing

  • Manual testing
  • Unit tests

@bfops

bfops commented Jan 6, 2026

Copy link
Copy Markdown
Collaborator

Thank you for filing this! We'll work on getting a reviewer on it.

@cloutiertyler

Copy link
Copy Markdown
Contributor

Going to get someone to review this.

@joshua-spacetime joshua-spacetime 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.

I think this is a good feature to add. I'd just like to see some tests. In particular I think the following tests would either fail or wrongly succeed today:

UPDATE a SET ... RETURNING a.*;
UPDATE a SET ... RETURNING count(*) AS n;

(
SqlResult {
tx_offset: tx_offset_receiver,
rows: vec![],

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.

Suggested change
rows,

This is the other possible return branch.

let returning = returning
.map(|proj| type_proj(RelExpr::RelVar(Relvar {
schema: schema,
alias: ST_VAR_NAME.into(),

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.

This alias should be the insert table.

let returning = returning
.map(|proj| type_proj(RelExpr::RelVar(Relvar {
schema: from.clone(),
alias: ST_VAR_NAME.into(),

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.

This should be the delete table.

let returning = returning
.map(|proj| type_proj(RelExpr::RelVar(Relvar {
schema: schema.clone(),
alias: ST_VAR_NAME.into(),

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.

Similarly this should be the update table.

table: parse_ident(table_name)?,
fields: columns.into_iter().map(SqlIdent::from).collect(),
values: parse_values(*source)?,
returning: returning.map(parse_projection).transpose()?,

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.

I believe parse_projection allows for aggregate expressions like COUNT, not valid in RETURNING.

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.

4 participants