This issue is part of #2157455: [Meta] Make Drupal 8 work with PostgreSQL or remove support from core before release.
Problem/Motivation
Currently some tests fail because PostgreSQL tries to create some indexes twice. We already have a method to prevent that (indexExists()) but this method is never ever called from within createTableSQL() where the index create statements are build.
Proposed resolution
Add an indexExist check to createTableSql() to prevent PostgreSQL from creating indexes twice. This is because indexes in PostgreSQL are global.
The pgsql driver already prefixes the index with the table name so this would mean the indexes are unique per table (see comment #12 for details). The solution, at this time, should only be to check if the index exists and create it if it does not exist.
MD5 (postgresql-index-exists.patch) = 5206e5687da7065aa75fc79f7caba208
MD5 (postgresql-index-exists-17.patch) = 5206e5687da7065aa75fc79f7caba208
- Follow-up issues:
Remaining tasks
Review.
User interface changes
None
API changes
None
Beta phase evaluation
| Issue category | Bug because of broken tests |
|---|---|
| Issue priority | Major because of broken test environment |
| Disruption | None disruptive for core/contributed and custom modules/themes because it is a bugfix only |
| Comment | File | Size | Author |
|---|---|---|---|
| #17 | postgresql-index-exists-17.patch | 818 bytes | mradcliffe |
| #8 | index_names_mariadb.txt | 18.12 KB | jaredsmith |
| postgresql-index-exists.patch | 818 bytes | bzrudi71 |
Comments
Comment #1
andypostThis looks like hack, maybe better solution to make index name generation "prefixed" somehow?
Comment #2
jaredsmith commentedI have reviewed this code both on a manual installation on my laptop and using the drupalci test infrastructure, and this patch solves a number of failing simpletest tests and doesn't appear to cause any additional failures. I am comfortable marking this as RTBC and asking that it be committed.
Comment #3
alexpottDoes this mean that we have indexes with the same name on different tables?
Comment #4
alexpottI'm concerned that this will cause us not to create important indexes.
Comment #5
jaredsmith commentedComment #6
alexpottComment #7
alexpottSetting back to needs review to get answers to #3/#4
Comment #8
jaredsmith commentedAbsolutely, it does -- and the more I think about it, this patch really would prevent us from building indices on important tables.
To show that we really do have indices with the same name on different tables, I ran the following query on MariaDB 10.0.15 after a fresh installation of 8.0.x HEAD (installed yesterday):
SELECT DISTINCT INDEX_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'drupal8' ORDER BY INDEX_NAME, TABLE_NAME;(Obviously, you can replace
'drupal8'with the name of your own database.)If you look at the attached file, it shows that we have thirteen tables that all have an index named "revision_id".
Looks like we're back to the drawing board on this patch, perhaps by prefixing the index name with the table name.
Comment #9
bzrudi71 commentedI don't have much time but just to give some feedback:
No. That could never ever happen as PostgreSQL indexes are unique and global. In other words you can't have an index named 'my_index' twice in PostgreSQL.
No worries I guess. As above, it does not prevent from creating an index, just from creating it twice, which will fail because it's not possible with global indexes. In addition, I didn't count it, but this happens on a complete test bot run not more than 5 times or so. But I'm with you, maybe this is just required because of weird tests scenarios...
Comment #10
jaredsmith commentedAnother attempt at a patch for this issue, this time by prefixing the index name with the table name, so that we don't have conflicting index names in PostgreSQL. Please let me know if this resolves the concerns from comments 1, 3, and 4.
Comment #11
bzrudi71 commented@jaredsmith: First off all thanks for taking care of PostgreSQL :-)
I'm sorry, but this issue is not about forcing to create another (duplicate) index with a different name if an index with the same name already exists. This issue is about preventing from creating an index twice. Please see ensureIdentifiersLength() method which does all the magic of index naming already (including table name+index name), and even to make sure we do not exceed the maximal length of an index name - in case of PostgreSQL 63 chars.
To give an example:
So you can create as many duplicated indexes on the same table and even on the same column as long as the name differs, but you can't create a second index, even on a different table if the index name is the same, because it's global. So in short - I just tried to prevent creating duplicate indexes, as that would result in an exception :-)
Comment #12
jaredsmith commentedBefore I get into the specifics of your last comment, let me just give some background so that we can all agree where we're coming from.
I wasn't aware until I looked into it further today that the
ensureIdentifiersLength()function already concatenates the table name plus the index name plus 'idx' when creating an index in PostgreSQL, in addition to making sure the name of the table/index/constraint doesn't exceed PostgreSQL's limit. So, in short, it's already doing what my new patch proposed to do, so my patch is superfluous.To answer the other comments on this issue after more investigation and reflection:
Comment #1: We already prefix the table name, so that's taken care of.
Comment #3: We do in fact in MySQL, but it doesn't really matter there. We don't in PostgreSQL.
Comment #4: Because we're fixing up the index names in PostgreSQL, this isn't a problem.
Which brings us all the way back around to @bzrudi71's patch, which really is the correct thing to do in this situation -- because we can now be sure that it really is an attempt to create a duplicate index on the same table, and not a naming conflict on the indices.
I'm setting this back to RTBC, as I don't see any other issues with @bzrudi71's patch.
Comment #13
jaredsmith commentedComment #14
alexpottWow can we get a followup to give
ensureIdentifiersLength()a better name. Also the variadic nature of the method seems unnecessarily fragile and complex.So now my question is why are we trying to create duplicate indexes on a table? Since this has nothing to do with the global nature of postgres's indexes. (Setting back to needs review for this)
Plus can @bzrudi71's patch be re-uploaded since the rtbc retest only retests the latest patch - it doesn't check the hidden files property (afaik).
Comment #15
alexpottAccording to the latest comments this is not why we're doing this change so this needs updating.
Comment #16
andypostI think here should be a follow-up to extend schema generators to not produce a duplicated names for indexes, tables, constrains there's no reason to relay on storage and introduce hacks within drivers.
Oracle contrib driver exposes own identifier constraints. I'm pretty sure that mssql has the same issue.
So better to extend schema generator once it has previous state knowledge now.
Comment #17
mradcliffeI haven't really read this issue in depth, but I read over comment #12 and updated the issue summary. I downloaded the patch, copied it to a new file name, and ran interdiff and md5 to confirm the files were the same.
Comment #18
mradcliffeCreated follow-up issues.
Comment #19
mradcliffeComment #20
alexpottBut why are duplicate indexes being created #14 still needs an answer.
Comment #21
bzrudi71 commented@jaredsmith: many thanks for the great summary write up of this issue, I couldn't explain it any better!
I'm totally +1 for making my patch obsolete if we could handle all this within the schema creators as suggested by @andypost. To address @alexpott concerns why we are trying to create indexes twice. I don't have the complete overview but it only happens in very, very rare cases during tests. Identified test groups are:
and in particular:
So these tests seem to do something special compared to all other test. To remember, if we do a table drop, we can be sure that PostgreSQL will take care of complete removal of all! indexes and whatever else. That could mean we do some operations on existing tables that lead to those errors. To trace this down I did some debug on the FileFieldValidateTests and ran them locally.
As expected the test does the usual, enable modules, create role, create user and so on. Now to the interesting part :-)
ensureIdentifiersLength()takes care of that an rewrites the index name to drupal_Z_WsWR9d7FLUJXO39jjBUIE6QdolJoJS_EnpuxeA4lY_idx, no problems so far$storage->delete()to take care of field deletion, not the article content entity itself$this->createFileField()which seems to be the problematic part. From the debug$this->createFileFielddoes create a lot of indexes and yes we hit it, it to tries to create simpletest845018node_revision__fdtwrve2__fdtwrve2_target_id__idx (drupal_Z_WsWR9d7FLUJXO39jjBUIE6QdolJoJS_EnpuxeA4lY_idx ) again, gotcha!As I'm all but an entity insider and it's late after midnight I leave this open for suggestions from the entity experts!
[UPDATE] I had a second look this morning and the test itself is easy to fix. The second call to
$this->createFileField()uses the same $field_name again and that causes the problem. By using a different $field_name I can make test pass. So what are the next steps here?- Try to identify every single broken test and try to fix it?
- Use my patch hack to prevent it globally?
- Try to fix that globally within the schema generators and not in driver space?
Comment #22
alexpottSo this is a problem with renaming tables in postgres. We need to rename any keys they have too. So the patch #17 is definitely wrong because the tables for the new fields will not have the correct indexes. Basically SqlContentEntityStorageSchema::onFieldStorageDefinitionDelete() calls Drupal\Core\Database\Driver\pgsql\Schema::renameTable() which should take care of renaming the indexes but, from @bzrudi71's report, this appears not to be working.
Comment #23
bzrudi71 commentedOkay, if the SqlContentEntityStorageSchema::onFieldStorageDefinitionDelete() calls Drupal\Core\Database\Driver\pgsql\Schema::renameTable() internally then the mother of all problems is already known: #1013034: PostgreSQL constraints do not get renamed by db_rename_table() ;-)
Guess we should focus on this now and see if that will fix all exceptions in this issue.
Comment #24
andypostLet's postpone that on #1013034: PostgreSQL constraints do not get renamed by db_rename_table()
Comment #25
bzrudi71 commentedJust did a complete test run with latest patch from #1013034: PostgreSQL constraints do not get renamed by db_rename_table() and all reported problems here (and some others too) are gone! So I think this one, as well as the follow up #2426581: Fix schema generators to prevent creating duplicate table, indexes, and other constraints so that database drivers do not need to implement their own solutions can be marked as closed/fixed. Regarding #2426579: Change method name for pgsql driver's ensureIdentifiersLength() to accurately describe what the method is doing this is now considered a follow up of #1013034: PostgreSQL constraints do not get renamed by db_rename_table() to fix pkeys that are currently prefixed by four underscores instead of two. This is more a cosmetic issue but we should take care of unique naming conventions.
So anyone, let's please focus on the db renaming issue now to get this long term showstopper (4 years!) to RTBC state - and committed.
Comment #26
bzrudi71 commented