Problem/Motivation
Database identifiers resolution has grown recently, with escaping, caching and introduction of the square brackets syntax to resolve the problem of generic SQL statements to be ported across platforms using different quoting characters. This on top of the concept of prefixing tables.
All this has been added on the Connection class that is IMHO a bit overdoing.
Also, some platforms are hitting identifier length issues like e.g. #571548: Identifiers longer than 63 characters are truncated, causing Views to break on Postgres.
Developers should not be worried by exceeding identifiers length or using wrong identifiers; the database API should be self-sufficient in receiving input and cleansing/transforming it into machine usable information; failing as a last resort.
Proposed resolution
Decouple identifier management, including prefix management, in a class of its own, that platforms can override to manage their own restrictions.
Therefore:
- Table names, database name, column names, index names in a db are 'identifiers'.
- 'Identifiers' are subject to db-specific limitations (length, chars allowed, etc)
- In Drupal, 'Identifiers' are value objects. Each identifier has:
- a type (e.g. table, column, alias, etc)
- a raw value that include non SQL allowed characters and/or the quote characters, also in a
<database>.<schema>.<table>format (e.g. config, key_value, mydb."key_value", with$$invalidchar, etc.) - a canonical value, i.e. the raw value cleansed of unallowed characters (from the example above: config, key_value, mydb.key_value, withinvalidchar, etc.)
- a machine-usable value, i.e. the canonical value transformed to be used on the db-specific SQL query - including applying quote chars, prefixing, and shortening if necessary (from the example above, and assuming a prefix 'abba': "abbaconfig", "abbakey_value", "mydb"."key_value", "abbawithinvalidchar", etc.)
- each db-driver implements an 'IdentifierHandling' class that parses/transforms a raw value into the relevant value object, including a local cache to prevent processing again and again each raw value.
In this issue, only focus on table identifiers, which also require database and schema identifiers to be fleshed out. In follow ups, this approach could be extended from tables to columns, aliases, indexes etc.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #53 | Screenshot from 2025-11-18 10-57-56.png | 84.47 KB | daffie |
| #53 | Screenshot from 2025-11-18 11-18-37.png | 97.48 KB | daffie |
Issue fork drupal-3200743
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mondrakeA first patch, splitting the identifiers' resolution in a class of its own. I'd like to move table prefix management here too.
Comment #3
mondrakeComment #4
mondrakeProgress with SQLIte, MySql and PgSql will fail. Mainly trying to move prefixes to the new class, deprecating
Connection::tablePrefix. Ideally we could get to deprecating also::setPrefix.Comment #5
mondrakeComment #6
mondrakeComment #7
mondrakeComment #9
mondrakeComment #10
mondrakeWill come back on this later.
Comment #12
mondrakeI think this is D10 material, actually.
Comment #13
andypostSoon it will be open
Comment #14
andypostComment #15
mondrakeNeeds to do #3124382: Remove per-table prefixing first, anyway.
Comment #16
mondrakeRefreshed a bit.
Comment #17
mondrakeComment #18
mondrakeSo, here is the idea.
Developers should not be worried by exceeding identifiers length or using wrong identifiers; the database API should be self-sufficient in receiving input and cleansing/transforming it in machine usable information; failing as a last resort.
Therefore:
This works now for MySql and SQLite; the MySql implementation shortens table names that are longer than 64 characters using hashing techniques.
PgSql will follow with its own 63 chars max limitation.
In follow ups, this approach could be extended from tables to columns, aliases, indexes etc.
Comment #19
mondrakeAdded pgsql conversion. Tests are now green on all 3 core drivers. The concept is in and implemented; now to cleaning, BC and documenting.
Comment #20
mondrakeReady for review now.
Comment #21
mondrakeComment #22
mondrakeThe machineName in the value objects should be stored unquoted. On that.
Comment #23
mondrakeDone #22, back to NR.
Comment #24
daffie commentedI support the basic solution. Great work!
or
Those changes do not make for an improved developer experience. Lets keep those methods as a wrapper for the new implementation. Maybe we need to add some more wrapper methods to improve the DX. It is great that we have an improved identifier management solution. Now lets hide it from them as much as possible. It works just a little bit better then before. For most of them that is all they need to know and maybe they do not need to know at all.
Drupal\Core\Database\Identifierbe for just MySQL/MariaDB. The specific changes that are needed for PostgreSQL and SQLite need to be done in their database driver modules. Like no "schema" stuff in the namespaceDrupal\Core\Database\Identifier. Other database drivers that are not supported by Drupal core, have their own specific stuff they need to override. Let use the database drivers for PostgreSQL and SQLite as an example for those contrib database drivers. The current solution is limited to making it work for the by Drupal core supported database drivers.Comment #25
mondrakeFiled follow-up #3514117: [PP-2] Use Table identifier value objects instead of table name strings in database Schema classes
Comment #26
mondrake#24 thanks Daffie for your review!
1) for sure we can undeprecate those, or postpone removal to a later major (D13+). But why would that be desirable? Besides that those 'wrappers' would be redundant, what would someone call those for, given that the value objects encapsulate the result of those wrappers? Besides, once we move to value objects then we could pass them as arguments for methods instead of strings and the reason for such wrappers would simply not hold anymore - see for example #3514117: [PP-2] Use Table identifier value objects instead of table name strings in database Schema classes and how sqlite's Schema class would benefit.
Supposing a prefix 'foo' is required, given that the Table identifier implements \Stringable and it returns the machine name identifier:
would return, without any further processing:
for SQLite:
SELECT * FROM "foo"."try_me"for MySQL
SELECT * FROM "footry_me"for PostgreSql (supposing a 'bar' schema is in use)
SELECT * FROM "bar"."footry_me"2) that's exactly what the MR is doing no?
Identifier/Database,Identifier/Schema,Identifier/Tableare value objects, defined final - they only carry the values. The values themselves are determined by each driver'sIdentifierHandlerclass, that parses the 'raw value' string identifier and instantiates the value objects with the needed values. Each driver'sIdentifierHandlerextends from the abstractIdentifierHandlerBasewhich has the 'regular' implementation - and all drivers need diversions one way or another, say for the different max lenght, or for how tables are prefixed, or for adding schemas etc.Comment #27
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #28
mondrakeUpdated fork.
Comment #29
mondrakeFiled follow up #3514261: [PP-1] Allow using Table identifier value objects in database Query classes.
Comment #30
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #32
liam morlandRe-rolled.
Comment #33
mradcliffeSwitching to Needs work for phpunit and code quality failures.
Comment #34
mondrakeComment #35
joachim commentedI feel this might clash a bit with #3486125: add long table name abbreviation to Database API.
Is the MR here just rejecting names which are too long? Could it leave space for that issue to handle them?
Comment #36
mondrake#35: this is a totally alternative approach, that removes the need for the other issue.
Too long names are automatically shortened here to match the db limitations.
Comment #37
mradcliffeI came up with a rough outline for the change record after reviewing the changes.
It looks like this also applies to any usages of
querythat use escapeTable manually in addition to database driver modules.Finally a question. If a site provided a prefix and used a non-core database driver would that site stop working because $prefix isn't set anywhere by that database driver (if it relied on the protected property)?
Comment #38
mondrakeThanks @mradcliffe for your review! The bigger picture is better understandable IMHO if this is reviewed together with #3514261: [PP-1] Allow using Table identifier value objects in database Query classes and #3514117: [PP-2] Use Table identifier value objects instead of table name strings in database Schema classes that will show how this will improve readibility of code once we start using the identifiers as parameters in methods.
Re the BC concern:
I added here a more robust handling of the deprecated $prefix variable through the magic methods.
Definitely review by maintainers of non-core drivers would help; however I am not sure how many D11 non-core db drivers are out there; MSSQL and Oracle seem stuck at earlier Drupal versions.
Comment #39
finalist commentedThe remarks of this user belong to user @daffie.
Comment #40
mondrake@daffie thanks for the detailed review, it will take some time before I can get to it. In the meantime, please consider this is not the endgame, and consider reviewing this in combination with #3514261: [PP-1] Allow using Table identifier value objects in database Query classes and #3514117: [PP-2] Use Table identifier value objects instead of table name strings in database Schema classes that would further implement the changes occurring here.
For instance, when you talk about DX, the endgame would be using the new identifier object with its automatic conversion to string: for example,
$query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';would become
$query = $comments . "DELETE FROM $this->tableIdentifier";That's quite a DX improvement IMO... just we cannot do all of it toghether in a single MR otherwise it will become too big.
Comment #41
mondrakeComment #42
mondrakeComment #43
smustgrave commentedRecommended way to test this?
Comment #44
mondrake#43 you mean manually? An idea could be to create via
createTablea PostgreSQL table with a very long name. Then inspecting the database you would find a table with an abbreviated name 63 chars long. Any Database API select/insert/update/query etc with the long name in Drupal would return data from the real table with abbreviated name.Comment #45
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #46
mondrakefork update
Comment #47
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #48
mondrakerebased
Comment #49
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #50
mondrakeComment #51
daffie commentedBack to NW for the open remarks on the MR.
Comment #52
mondrakeSorry @daffie for some reason I cannot see your remarks on the GitLab UI, they show as collapsed and when I try to open them nothing shows up - I see what you wrote in the issue here, but the problem is I cannot see 'where' they are positioned. Can you try again or give some more details in comments here?
Comment #53
daffie commentedThe mistake I made is that I mixed up by using 2 different accounts.
The MR looks very good, just a couple of nitpicks:
- Can we in the Unit IdentifierTests add testing for prefix not duplicated and only a table name.
- See the added images.
Comment #54
harivansh commentedComment #55
mondrakeI think we should postpone this for the moment, and let #3411490: Replace array-based DB Schema API with a value object structure land first. That one may have implication/connections with this one, so let's pause for a moment.
Comment #56
harivansh commented