Skip to content

feat(mysql): translate UPDATE … FROM … syntax to UPDATE … JOIN … when generating MySQL#6655

Merged
VaggelisD merged 5 commits intotobymao:mainfrom
brdbry:main
Jan 9, 2026
Merged

feat(mysql): translate UPDATE … FROM … syntax to UPDATE … JOIN … when generating MySQL#6655
VaggelisD merged 5 commits intotobymao:mainfrom
brdbry:main

Conversation

@brdbry
Copy link
Contributor

@brdbry brdbry commented Jan 2, 2026

Extend the MySQL generator so that UPDATE … FROM … statements (not supported by MySQL) are emitted as UPDATE … JOIN …, synthesizing ON TRUE predicates when no join condition is specified, and handling nested/comma joins.

Add test_update_from_to_join to cover the new rendering and adjust a Teradata cross-dialect test expectation to match the JOIN-based MySQL output.

@brdbry brdbry changed the title Translate UPDATE … FROM … syntax to UPDATE … JOIN … when generating MySQL feat(mysql): translate UPDATE … FROM … syntax to UPDATE … JOIN … when generating MySQL Jan 2, 2026
Copy link
Collaborator

@georgesittas georgesittas left a comment

Choose a reason for hiding this comment

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

Hey, thanks for the PR @brdbry.

This needs to be cleaned up a bit & the testing coverage needs to be increased, it seems.

@brdbry
Copy link
Contributor Author

brdbry commented Jan 7, 2026

Thanks @georgesittas , hopefully this looks a bit better now

Copy link
Collaborator

@VaggelisD VaggelisD left a comment

Choose a reason for hiding this comment

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

@brdbry Thank you for addressing the previous round of comments, leaving a few as well:

"UPDATE foo JOIN bar ON TRUE SET a = bar.a WHERE foo.id = bar.id",
read={
"postgres": "UPDATE foo SET a = bar.a FROM bar WHERE foo.id = bar.id",
"mysql": "UPDATE foo JOIN bar ON TRUE SET a = bar.a WHERE foo.id = bar.id",
Copy link
Collaborator

@VaggelisD VaggelisD Jan 8, 2026

Choose a reason for hiding this comment

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

This doesn't seem to work:

mysql> create table t1 as (select 3 as id);
Query OK, 1 row affected (0.015 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> create table t2 as (select 1 as id);
Query OK, 1 row affected (0.012 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> UPDATE t1 JOIN t2 ON TRUE SET id = t2.id;
ERROR 1052 (23000): Column 'id' in field list is ambiguous

We'd need to qualify all non-t2 columns with t1:

mysql> UPDATE t1 JOIN t2 ON TRUE SET t1.id = t2.id;
Query OK, 1 row affected (0.003 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.001 sec)

And the opposite does not work in Postgres to allow for the happy case of not having to qualify columns:

postgres> UPDATE t1 SET t1.id = t2.id FROM t2;
ERROR:  column "t1" of relation "t1" does not exist
LINE 1: UPDATE t1 SET t1.id = t2.id FROM t2;

Copy link
Collaborator

Choose a reason for hiding this comment

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

This might be as simple as traversing all exp.Columns and setting col.table with from.this, given that Postgres assumes that t1's columns will all be unqualified while all other columns must be qualified.

This hypothesis will need more testing, of course

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated and tested the new generated sql against both MySQL and PG

@brdbry
Copy link
Contributor Author

brdbry commented Jan 8, 2026

Thanks @VaggelisD, changes made

Copy link
Collaborator

@VaggelisD VaggelisD left a comment

Choose a reason for hiding this comment

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

Thank you for the PR & iterations @brdbry! Got one comment but i'll go ahead and merge this

Comment on lines +218 to +220
read={
"postgres": "UPDATE t1 SET t1.id = t2.id FROM t2 WHERE t1.x = t2.x",
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Given that this isn't correct Postgres it'd be better to remove the test; SQLGlot lives by the "garbage in, garbage out" rule so it's not our responsibility to cover such cases.

@VaggelisD VaggelisD merged commit efa77df into tobymao:main Jan 9, 2026
9 checks passed
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.

3 participants