doctrine / dbal

Doctrine Database Abstraction Layer
https://www.doctrine-project.org/projects/dbal.html
MIT License
9.43k stars 1.33k forks source link

Column precision is not specified 2 #6468

Open cavemanlu opened 1 month ago

cavemanlu commented 1 month ago

Bug Report

Q A
Version 4.*

Summary

Given:

Current behaviour

It is impossible to update doctrine-migrations and doctrine-dbal (3.8 -> 4) because dbal broke support for type NUMBER without scale/precision.

The 'correct' way to fix it - by updating all the columns with scale/precision cannot be applied easily (it will take days on the amount of data).

How to reproduce

Create a simple project with Postgres with dependency on doctrine-migrations. Create a table with a column with type NUMBER without scale/precision. Create any migration on the schema. Try to apply the migration. Get 'Column' precision is not specified' exception.

Expected behaviour

No errors.

A workaround with the possibility to configure default scale/precision project-wise/per-column would work.

berkut1 commented 1 month ago

Have you tried creating your own custom type to override the method https://github.com/doctrine/dbal/blob/90424473eb144659a89fb1b5c9bca37297085351/src/Platforms/AbstractPlatform.php#L1388 and bypass your issue?

derrabus commented 1 month ago

We've had a similar discussion in #6455: Postgres also supports VARCHAR without a limit which DBAL 4 "broke" as well. The problem is that those unconstrained types as Postgres calls them are not portable at all which makes them a bit out of scope for a database abstraction layer. A custom type as @berkut1 suggested is probably your best option for a Postgres-only type.

morozov commented 1 month ago

Postgres also supports VARCHAR without a limit which DBAL 4 "broke" as well.

I don't think this is accurate. If you use DBAL only with Postgres and/or SQLite, you shouldn't have to specify the length. The validation happens during rendering the type DDL by the platform.

For example (also note ?int in the signature): https://github.com/doctrine/dbal/blob/44635a2fd761686337c39bd9e682aeed1d8791ac/src/Platforms/PostgreSQLPlatform.php#L637-L646

berkut1 commented 1 month ago

@morozov It's "broken" in quotes :)

I tried to describe the problem here. In DBAL3, all platforms have this similar code:

https://github.com/doctrine/dbal/blob/b35648d64d9b641ee20f74b29f01a894e38027b6/src/Platforms/PostgreSQLPlatform.php#L1129-L1133

As you can see, if no value is specified, it returns VARCHAR(255). The problem is that ORM forcibly does this too here:

https://github.com/doctrine/orm/blob/9d4f54b9a476f13479c3845350b12c466873fc42/src/Tools/SchemaTool.php#L463-L465

So, ORM expects to always get VARCHAR(255) by default and uses tricks around this to fool DBAL without creating custom types. I tried to describe the issue using the INET example. https://github.com/doctrine/dbal/issues/6466

This is also how in ORM with DBAL4 it "breaks" ENUM, which was based on fooling/tricking DBAL https://github.com/doctrine/migrations/issues/1441#issuecomment-2227444186 (no one has checked my theory yet, but I’m sure the problem is related) . The problem is not in DBAL4 (partially, because the initial code contains examples of tricking), but in ORM and its hardcoded value of 255 for all strings.

But of course, this all relates only to VARCHAR and strings.

cavemanlu commented 1 month ago

Have you tried creating your own custom type to override the method

https://github.com/doctrine/dbal/blob/90424473eb144659a89fb1b5c9bca37297085351/src/Platforms/AbstractPlatform.php#L1388

and bypass your issue?

Thanks, this workaround worked for me. I replaced the default Decimal type with the new one that checks default values for precision/scale.