dbal icon indicating copy to clipboard operation
dbal copied to clipboard

Identity columns

Open greg0ire opened this issue 2 years ago • 11 comments

Feature Request

Q A
New Feature yes
RFC yes
BC Break no

Summary

As of now, it seems that identity columns are not supported by the DBAL. This feature is available since Oracle 12.1 and PostgreSQL 10.

Supposed pros:

greg0ire avatar Aug 09 '21 21:08 greg0ire

Not sure why I originally made the title so shouty, this isn't SQL

greg0ire avatar Aug 10 '21 05:08 greg0ire

As of now, it seems that identity columns are not supported by the DBAL.

This looks a bit misleading given that there is an API for that: https://github.com/doctrine/dbal/blob/e974d4deca8c430d9eba0975f441538145a5a8f1/src/Platforms/AbstractPlatform.php#L3056

It's implemented natively by the SQL Server and IBM DB2 platforms: https://github.com/doctrine/dbal/blob/e974d4deca8c430d9eba0975f441538145a5a8f1/src/Platforms/SQLServer2012Platform.php#L1305-L1308 https://github.com/doctrine/dbal/blob/e974d4deca8c430d9eba0975f441538145a5a8f1/src/Platforms/DB2Platform.php#L176-L180

Most of the platforms implement it in their proprietary terms (e.g. MySQL, SQLite) and only PostgreSQL and Oracle currently emulate it via sequences.

I believe, the issue is about implementing native support where it's missing, right?

morozov avatar Aug 10 '21 14:08 morozov

Yes, you're right, what's missing is native support for the SQL standard (as opposed to PG-specific SERIAL notation). It looks like there is already some support for that in DB2Platform.php, maybe part of it could be moved up in AbstractPlatform.php, since that syntax is supposed to be standard?

greg0ire avatar Aug 10 '21 21:08 greg0ire

as opposed to PG-specific SERIAL notation

I believe it's not problem #​1 from the DBAL perspective: as long as it behaves as the identity column, it shouldn't be a problem from the API standpoint. For instance, MySQL and SQLite will keep using their own syntax anyways.

What's more important is that as long as not all platforms support identity columns, the API consumers have to use two different APIs to achieve effectively the same goal (identity generation) on different platforms. That's the problem I'd like to solve by eventually deprecating supportsIdentityColumns() and have all platforms support them.

Additionally, the identity columns will need the support for lastInsertId() at the drivel level for Oracle or some workaround in the DBAL. I bet neither oci8 nor especially pdo_oci support it.

From the article linked to https://github.com/doctrine/dbal/issues/2695:

Based on the requirement for the CREATE SEQUENCE privilege, it is not difficult to deduce that a sequence is being used to populate the identity column.

This is effectively how identity columns are currently implemented in the PostgreSQL platform.

Switching to the standard SQL syntax wherever possible would be the cherry on the cake. Note, that it's a breaking change.

It looks like there is already some support for that in DB2Platform.php, maybe part of it could be moved up in AbstractPlatform.php, since that syntax is supposed to be standard?

Sounds good. This also could be addressed closer to the end.

morozov avatar Aug 10 '21 23:08 morozov

Note, that it's a breaking change.

Because it will make the diff between a database and its in-memory equivalent not empty, and will suddenly generate a lot of migrations when using doctrine/migrations, right? I wonder how painful a migration from SERIAL to standard identity columns would be, and if the DBAL would generate the correct diff for those :thinking:

greg0ire avatar Aug 11 '21 20:08 greg0ire

Because it will make the diff [...], right?

Yes. Handling this diff automatically in the DBAL may be non-trivial: not only we'd have to properly migrate the table, trigger definitions, etc. we'd have to migrate their state (i.e. next sequence value). It might be easier to document a manual migration path, although even this will take quite some time.

morozov avatar Aug 12 '21 16:08 morozov

@morozov it doesn't look too bad. looking at: https://www.postgresql.org/docs/12/sql-altertable.html and https://www.postgresqltutorial.com/postgresql-identity-column/
As long as you can determine the current sequence value (easy), you can then:

ALTER TABLE table_name 
ALTER COLUMN column_name 
{ SET GENERATED { ALWAYS | BY DEFAULT } | 
  SET sequence_option | RESTART [ [ WITH ] restart ] }

where restart is the current sequence value.

bendavies avatar Aug 20 '21 21:08 bendavies

@bendavies if you want to give it a try, go for it.

morozov avatar Aug 21 '21 17:08 morozov

Apologies. I didn't realise comments weren't welcome unless accompanied by a PR. Let me know if you'd like me to delete my comment.

bendavies avatar Aug 21 '21 17:08 bendavies

Apologies. I didn't realise comments weren't welcome unless accompanied by a PR. Let me know if you'd like me to delete my comment.

Not at all. Thank you for the details.

morozov avatar Aug 21 '21 17:08 morozov

Apologies for my irritability. Rough day

bendavies avatar Aug 21 '21 18:08 bendavies