Problem/Motivation
Schema::fieldSetDefault and Schema::fieldSetNoDefault, and their legacy procedural counterparts db_field_set_default and db_set_no_default, are implemented in the core db drivers, and are tested in SchemaTest, but in fact are used nowhere in core.
IMHO all these methods should just be deprecated, in favor of Schema::changeField with a full field specification passed in.
Some db systems may not have the DDL specific for adding/removing only the default value of a field, forcing therefore to use changeField anyway. But in that case you would have to introspect the field spec from the actual field to be changed, and there are cases when this can be messy (for example to determine if a field is unsigned).
Proposed resolution
Deprecate Schema::fieldSetDefault, Schema::fieldSetNoDefault, as well as db_field_set_default and db_set_no_default.
Remaining tasks
1. Discuss/agree if this makes sense
2. Write patch
3. The rest
User interface changes
none
API changes
2 public methods in the Database API deprecated
Data model changes
none
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | 2993663-25.patch | 16.55 KB | mondrake |
| #25 | interdiff_23-25.txt | 1.59 KB | mondrake |
Comments
Comment #2
mondrakeComment #3
andypostComment #4
mondrakeLet's see what actually breaks by adding the deprecation message.
Comment #6
mondrake#4 confirms the IS
Here, changing the
SchemaTestto useSchema::changeFieldwith a full field specification passed in.Comment #7
mondrakeNow, with deprecation tests.
If we do this, we need to have a CR and then adjust the deprecation messages.
Comment #9
mondrake...
Comment #10
andypostThis change makes API incomplete - you causes contrib to provide full field definition instead of just managing column default value
Then we need complimentary method to retrieve current field definition & cast it to schema definition just to allow change default value(
PS: Also
\Drupal\Core\Database\Schema::escapeDefaultValue()looks orphan without this methodsThat's what worries loosing this api-calls without alternative to get current definition of the field (I found no public way to get introspection from schema)
Comment #11
mondrakeTrue, but:
In other words -- IMHO
changeFieldshould be the most atomic method to deal with changes on table colums, to ensure integrity. Suppose you have a column defined as Unsigned. You change default to -1. What happens? If you had changeField somehow validating the combination of column attributes (not there yet, but directionally...), you could avoid this ambiguity.Comment #12
longwaveI did some digging to find when this was first introduced, and to see if I could find when it would actually be useful, as I am not really sure of the use case of changing a column default at runtime, except perhaps during an update hook.
db_field_set_default() was first added in the patch in https://www.drupal.org/project/drupal/issues/136171#comment-541294 which was the precursor to the Schema API introduced in the Drupal 6 development cycle. There is a cursory mention of "there are now table manipulation functions: db_add_field, db_drop_field, db_create_index, db_drop_index, db_set_default_value" but it doesn't explain why the last one is actually useful.
I found a couple of mentions in old contrib:
https://cgit.drupalcode.org/boost/tree/boost.install?h=6.x-1.x#n950
https://cgit.drupalcode.org/mass_contact/tree/mass_contact.install?h=6.x...
https://cgit.drupalcode.org/taxonomy_display/tree/taxonomy_display.insta...
All of these cases are where the module owns the schema in question and so they wouldn't need to introspect it.
I am struggling to think of a case where something might want to alter a schema that it doesn't own, yet doesn't know enough about that schema to be able to use the changeField() method.
Comment #13
mondrakeExactly, +1. This seems a 'shortcut' for use in update hooks. But contrib have to keep their
hook_schemaimplementation aligned, to ensure that new installation get the same db structure as the one that results from updates, otherwise hell breaks loose. And, if the hook_schema is aligned, the full field spec is available from code without any need to introspect.Comment #14
mondrakeThis should fix the Pgsql failure, that was due to using the now deprecated method.
Comment #15
longwaveLooks good to me.
Comment #16
mondrakeThank you @longwave
This is not ready yet for prime time, but leaving RTBC in the hope of getting core commiter's feeback on the direction.
If we are going ahead in this, the todos are:
changeField, and nothing is testingfieldSet(No)DefaultanymoreComment #18
mondrakeComment #19
alexpottWe need the list of things in #16 done.
Comment #20
mondrakeI will work on that
Comment #21
mondrakeComment #22
mondrakeAddressed points in #16. Added draft CR here https://www.drupal.org/node/2999035 and adjusted the overall db_* deprecation CR here https://www.drupal.org/node/2993033.
Comment #23
mondrakeInteresting. in case of a database insertion that fails to comply to constraints, pgSql and SQLite drivers throw a much more accurate exception (IntegrityConstraintViolationException) than MySql (DatabaseExceptionWrapper). Here just catching the common base interface class, then.
Comment #24
andypostMaybe better to assertFalse(TRUE) here?
Comment #25
mondrake#24 here we are deliberately executing an insert that is due to fail and raise an exception, so whatever is in the catch block cannot fail the test.
Let's make things a bit clearer.
The MySql 8 failure in #23 is unrelated.
Comment #26
andypostGreat! Now it looks polished)
Comment #28
catchCommitted ca4076c and pushed to 8.7.x. Thanks!
Comment #29
mondrakePublished CR https://www.drupal.org/node/2999035
Comment #30
mondrakeOpened #2999569: MySql driver throws a generic DatabaseExceptionWrapper for integrity violation at insertion when column has no default as a follow-up for #23.