Skip to content

Conversation

@MooSayed1
Copy link

MySQL 8.0.20 introduced a new syntax for INSERT ... ON DUPLICATE KEY UPDATE that allows referencing the inserted row using an alias instead of the VALUES() function:

-- Old syntax (still supported)
INSERT INTO t1 (a, b) VALUES (1, 2)
  ON DUPLICATE KEY UPDATE b = VALUES(b);

-- New syntax (this patch adds support)
INSERT INTO t1 (a, b) VALUES (1, 2) AS new
  ON DUPLICATE KEY UPDATE b = new.b;

The alias syntax is cleaner and more readable, especially when referencing multiple columns or using expressions like new.a + new.b.


Implementation

  • Parser: Added opt_values_row_alias rule to accept AS alias after VALUES
  • LEX: Added insert_values_alias field to store the alias
  • Name resolution: In Item_field::fix_fields(), when we're in ON DUPLICATE KEY UPDATE and the table qualifier matches the alias, we convert the reference to an Item_insert_value (equivalent to VALUES())

The traditional VALUES() function continues to work unchanged.

Tests

Added mysql-test/main/insert_update_alias.test covering:

  • Basic INSERT ... AS alias ON DUPLICATE KEY UPDATE
  • Multiple rows with alias
  • Expressions using alias columns (new.a + new.b)
  • Backward compatibility with VALUES() function
  • Mix of alias and table column references
  • INSERT without ON DUPLICATE KEY (alias ignored)
  • Different alias names

@CLAassistant
Copy link

CLAassistant commented Jan 15, 2026

CLA assistant check
All committers have signed the CLA.

@MooSayed1 MooSayed1 force-pushed the MDEV-29919-insert-as-alias branch from b3b3fa7 to d724e69 Compare January 15, 2026 20:20
@MooSayed1 MooSayed1 force-pushed the MDEV-29919-insert-as-alias branch from d724e69 to ff235ab Compare January 15, 2026 21:20
@github-actions github-actions bot added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Jan 17, 2026
Copy link
Contributor

@FooBarrior FooBarrior left a comment

Choose a reason for hiding this comment

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

Hi @MooSayed1! Thanks for your contribution.

I think this needs a better high-level detalization. What happens if a table has a field with the same name? This is a MySQL compatibility task -- so it's important to know what MySQL does in this case.

These details on the approach to name resolution will be important to be mentioned in the commit comment.

When we are in ON DUPLICATE KEY UPDATE and the table qualifier matches
the insert_values_alias, we should resolve this as VALUES(column).
*/
if (select &&
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. No need to specify MDEV in the comments.
  2. It's enough to have a meaningful comment.
  3. In general, better not to refer to an exact sql_command value.
  4. We need to make sure the syntax can't be used in the unsupposed ways, like that REPLACE...AS would fail with a syntax error, and CREATE ... VALUES would.
  5. I'm surprised you have to check select. Why?
  6. What does this code placement mean? it's in if (!field), meaning that it would apply only if field is not early-provided[?], but before find_field_in_tables, meaning that it would supersede a name resolution?

Copy link
Author

@MooSayed1 MooSayed1 Jan 19, 2026

Choose a reason for hiding this comment

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

first thanks for the review
then
Q1, Q2, Q3: Got it, will fix all of these.

Q4: Currently the grammar allows REPLACE ... AS alias to parse (since table_value_constructor is shared), but it's ignored at runtime because duplicates != DUP_UPDATE. but i think it would be better to get a syntax error at parse time instead of silent acceptance? and maybe adding tests for these scenarios

Q5: The select check was me being cautious - ensuring we have a valid query context. It's probably redundant.

Q6: It's placed before find_field_in_tables() so the alias takes priority. If a table and alias share the same name, new.b should resolve to the alias (inserted value), not the table. This matches MySQL behavior.

and should we continue the discussion here or move to Zulip?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

3 participants