This issue is part of #2157455: [Meta] Make Drupal 8 work with PostgreSQL or remove support from core before release.
Problem/Motivation
Some migrate tables use reserved keywords as column name like OFFSET currently causing exceptions on PostgreSQL because such names need quoting to work. As this is somehow not a problem for MySQL we decided to add support for PostgreSQL also by adding quotes where needed.
Proposed resolution
- Add new reserved words for PostgreSQL 9.1.2 and other versions.
- Ensure quoting for column names on insert/update/delete for reserved words.
- Add tests to ensure quoting for column names.
Remaining tasks
Write Patch
Patch review
Run tests on PostgreSQL test bot
Write beta evaluation
User interface changes
None.
API changes
None.
Beta phase evaluation
| Issue category | Bug because migrate system uses reserved words and render migrate unusable on PostgreSQL. |
|---|---|
| Issue priority | Major because it affects secondary environments and the migrate component is not required for new Drupal 8 web sites. |
| Prioritized changes | PostgreSQL until 2015.07.01 |
| Comment | File | Size | Author |
|---|---|---|---|
| #47 | interdiff-2477853-44-47.txt | 722 bytes | daffie |
| #47 | 2477853-47.patch | 10.92 KB | daffie |
Comments
Comment #1
bzrudi71 commentedComment #2
amateescu commentedNote that you will also have to update
core/modules/migrate_drupal/src/Tests/d6.gzfollowing the procedure detailed incore/scripts/migrate-dump-d6.sh, see #2454669-10: SQLite: Fix tests in migrate_drupal test group and #2452709-4: migrate_drupal test dump generation documentation.Comment #3
bzrudi71 commentedOh no, really? That seems like a time consuming thing to me from the documentation and in addition I have no working MySQL setup ;-) Updated IS to reflect that...
Comment #4
amateescu commentedYep, it's quite cumbersome and time consuming :/ But at least there's a plan to improve it: #2469623: Process for creating migration source DBs for automated tests
Comment #5
mradcliffeVisibility.
Comment #6
bzrudi71 commented#2469623: Process for creating migration source DBs for automated tests just landed. That should make it much easier to create the required d6 dump file. So someone with MySQL setup out there doing this part PLEASE? :) With this one in and #2477845: PostgreSQL: Fix broken migrate table creation, we are close to 100% migrate_drupal tests passing!
Comment #7
erik.erskine commented@bzrudi is the d6 dump file still needed?
Comment #8
bzrudi71 commented@ingaro, not sure as I didn't follow the latest development in #2469623: Process for creating migration source DBs for automated tests ;) I just know it was planned and not sure if this is already covered by this patch. However, we need at least a patch against the generated EventTimezones table file, as this fails as discovered by the new MigrateTableDumpTest :)
Comment #9
erik.erskine commentedIs renaming the column the right approach? Just been having a look at the event contrib module, which defines the
event_timezonestable. It does contain a column calledoffset, which is allowed by PostgreSQL but requires surrounding with quotes.See
event.install:The tests aren't failing when the table is created, because the
createTableSqlfunction inDrupal\Core\Database\Driver\pgsql\Schemaescapes the column name with"". However theDrupal\Core\Database\Driver\pgsql\Insertclass does not do this, and perhaps it should. If reserved column names are supported then the PG driver seems like the right place to escape them.Attached patch illustrates what I mean (and fixes various test failures), but I imagine needs some more work as there may well be other instances of this happening (DELETE, UPDATE etc).
Please note it also only works with #2477845: PostgreSQL: Fix broken migrate table creation applied too.
Comment #10
bzrudi71 commented@ingaro Yep it is allowed as long as quoted, but I still think it is absolutely no good practice to allow such identifiers at all. But that's my personal point of view. If other followers here like to see those identifiers supported for INSERT/UPDATE etc. I'm fine with that :)
Comment #11
erik.erskine commentedJust noticed a silly mistake in #9, where the escape function isn't actually doing anything. Uploading a new patch.
Comment #12
bzrudi71 commentedOkay, after another night of sleep I think we should go for #11 as that will help with contrib modules and because we mimic the behavior of MySQL all around :) I think we will have no problems within the schema API itself as we already take good care of escaping. Also I see no problems for the entity system and views as well, because all columns are prefixed by field_ or something similar and that should be save to make them work. So we just have to take care for native select/insert/update/delete queries?
Comment #13
bzrudi71 commentedOkay, I was to curios so I quick-hacked some test coverage for at least insert, update and delete. We have pass in insert and delete, but fail in update where 'offset' isn't escaped properly. Anyway, seems we can handle it this way and ensure better PG contrib support! I have very, very limited time over the next days, so feel free to work further here :)
Comment #15
bzrudi71 commentedQuick-fixed typo, MySQL should pass now...
Comment #16
mradcliffeFlip to needs review.
Comment #17
bzrudi71 commentedBack to needs work as just a proof of concept ;) + IS Update
Comment #18
erik.erskine commentedThanks for the extra test coverage.
#1600670: Cannot query Postgres database that has column names with capital letters addressed a similar concern, making case identifiers case-sensitive (again, technically allowed by PostgreSQL, but you need to escape them). It added some functions in the
Drupal\Core\Database\Driver\pgsql\Connectionclass to escape table/column names if they have an uppercase character. Their use seems inconsistent across create table/insert/update etc though.Is it best to always escape all identifiers? Are there any implications with doing that, other than an unnecessarily verbose query string?
I've attached a new patch that changes the various
escape...functions to add the quotes regardless of case. Also calls the escaping forUPDATEstatements.Comment #19
bzrudi71 commented@ingaro thanks for your work on this issue! Please see the comments in the mentioned issue #1600670: Cannot query Postgres database that has column names with capital letters, why the identifiers are not all quoted by default. The changes for insert and update are looking good to me, but I think we should revert the changes within the escape functions please ;) Thanks again, and as soon as I have some time I will do a test run and code review.
Comment #20
mikeryanComment #21
daffie commentedChanged the name of the patch file from comment #18 to have it tested by the testbot.
The patch looks good to me.
Does anybody know which tests this patch should fix?
@bzrudi71: Can you test the patch with a postgresql database.
Comment #23
bzrudi71 commented@daffie, this will fix all the remaining exceptions within the migrate_drupal tests :) Anyway, we can't go with the patch as is, because of my comment in #19. I really like to see this one getting in and hopefully have the time tomorrow to revert the changes regarding quoting by default, lets see :)
Comment #24
erik.erskine commentedThanks for the feedback @bzrudi, and I now have some more time to work on this over the next few days.
Here is a new patch based on #18 but without the changes to the escape functions. This doesn't stop
MigrateDrupal6Testfrom failing though, because the column name offset is no longer quoted within the INSERT statement.Specifically, this code:
... results in this SQL statement:
What I'm a bit uncertain of is why we are always quoting identifiers in the
createTablemethod, but notinsert/update. So the table is created ok despite the reseved work, but the tests fail once we try to populate it. Shouldn't the behaviour be consistent?Please can you clarify which comments you are referring to as I read through them but am still a bit confused.
Comment #25
daffie commentedFor the testbot
Comment #26
daffie commentedI have changed the patch so that only PostgreSQL reserved key words are quoted.
The following tests passes for me locally with a PostgreSQL backend:
Comment #28
bzrudi71 commentedUnfortunately I didn't find a minute to work at this today so happy to see some good progress here, thanks all :) At least I have just started a new full testbot run some minutes ago with the new approach by daffie (special approach, but lovely :)) and will post the result later.
Comment #30
bzrudi71 commentedOkay, nice. We have 100% pass in migrate_drupal with patch from #26. The only thing I see are new fails in:
Drupal\system\Tests\Installer\SingleVisibleProfileTest 15 passes 9 failsBut not sure if this is related to this patch, needs investigation. Anyway a promising start :)
I agree with @ingaro that this is all but consistent regarding the escaping this time, but I think for now our main goal is 100% passing tests, right? I think of a follow-up to major clean up and deep review the pg-driver space and see how we can get more consistent once we have passing tests...
Comment #31
daffie commented@bzrudi71: Thank you for testing the patch on your testbot. ;)
The Drupal\system\Tests\Installer\SingleVisibleProfileTest passes with the patch from #26 on my local machine.
Comment #32
bzrudi71 commentedAs a very last thing for today I ran the Installer tests twice and don't see the fails any more :) I didn't really review the patch yet so can we have some more comments on this approach from others please?
Comment #33
erik.erskine commentedThe approach looks good to me, and the migrate_drupal tests that were failing before are all passing.
One small thing:
The list should probably be based on PostgreSQL 9.4, and include
collationandlateralwhich have become reserved keywords since 9.1.Comment #34
daffie commented@ingaro: Thanks for the review and you made a very good point!
Added
collationandlateralto the list.Accidentally added
overto the list. Now removed.Comment #35
bzrudi71 commentedI'm still not really happy with this approach but think we should go for now as is. As we do all and everything in PG driver space we can handle that later on once we get the quote-all-and-everything stuff done. We have pass, we have test, so let's do it :) RTBC
BTW: We need a follow up on commit (will take care of that) Thanks all!
Comment #36
bzrudi71 commentedComment #37
mradcliffeUpdated issue summary, added beta evaluation template, and beta evaluation after reviewing the issue and patch.
Firefox crashed on me the first time so I had to rewrite it.
Comment #38
alexpottselect * from pg_get_keywords() where catcode in ('R', 'T');reveals that there are 99 reserved words - the list in the method appears to be 98 long. Not sure what is missing. Also the query looks useful for a kernel test :)
Should be @see and no fullstop and a blank line above.
This looks very testable. It'd be great to see a test that ensure all postgres reserved words are quoted as expected for both escapeField, escapeAlias, and escapeTable. Given that the reserved word list is queryable perhaps a kernel testbase that skips if the db is not pgsql would be good.
Two line method summary - should be one line.
Comment #39
alexpottMy list from
psql -c "select * from pg_get_keywords() where catcode in ('R', 'T');"Comment #40
erik.erskine commentedThe missing one is
freeze. I've added this and also addressed points 2 and 4 in #38.Added a new test in
Drupal\system\Tests\Database\ConnectionTestthat does the query @alexpott mentioned, and tests the variousescapeXXXmethods. Is this the right place to do that?By having this query in the test we should also catch any new reserved words that might appear in future versions of PostgreSQL.
Comment #41
erik.erskine commentedComment #42
bzrudi71 commented@ingaro thanks a lot for the patch! I didn't review yet and just quickly applied locally. Noticed that it at lest seems to work as it discovered a new missing reserved keyword "over" in my installation that leads to failing tests :)
Comment #43
erik.erskine commentedInteresting. It looks like
overwas a reserved word up to and including 9.3, but is no longer. I had a look through other versions since 9.1 and as far as I can tell that is the only one.I've added it to the list.
Comment #44
daffie commentedThe added test looks good to me. Thanks ingaro.
I think that
Drupal\system\Tests\Database\ConnectionTestis the right place to add the new test for the escapeTable(), escapeField() and escapeAlias() methods.We only test the keywords from the PostgreSQL database version(s) we use in our testbot.
The keyword "over" was in my patch from comment #26. I removed it later because in PostgreSQL 9.4 it is no longer a keyword. I thought that I made an error by adding it in the first place. :(
I made one minor documentation change to the patch:
alexpott stated in comment #38.4 that a summary line should be on one line.
Comment #45
daffie commentedAll points from alexpott are addressed.
The newly added Drupal\system\Tests\Database\ConnectionTest passes for me locally.
It all looks good to me.
The last patch from me was only a documentation change.
So for me it is back to RTBC.
Comment #46
bzrudi71 commentedSorry, I think all in all this looks very good just one nitpick so:
I think we usually use UPPERCASE in SQL queries...
The test itself looks good. I'm happy with testing this in ConnectionTest cause moving it over to CaseSensitiveTest feels wrong even if it is some kind of sensitive testing. Creating a new test class is also a bit overhead I think :)
Comment #47
daffie commentedGood point bzrudi71. I missed that one.
Comment #48
bzrudi71 commentedAs I expect test pass setting back to RTBC :) Just to remember: This is the last open issue on the way to 100% bot pass, so let's get this in! Thanks @all
Comment #49
alexpottCommitted 40335e9 and pushed to 8.0.x. Thanks!
Thanks for adding the beta evaluation to the issue summary.
Comment #51
Drupa1ish commentedComment #52
Drupa1ish commentedComment #53
daffie commentedFor the backport.
Comment #54
David_Rothstein commentedComment #55
Crell commentedI only just became aware of this issue via #2560965: Reserved column names are broken on MySQL, the test lies.
Per comments 5 and 7 in that issue, and the very-old issue linked from there as well, this fix is contrary to the design of the DB layer and is also incomplete and buggy. It should be reverted.
From the summary: "Some migrate tables use reserved keywords as column name like OFFSET". Well, then it shouldn't be using reserved keywords as columns. That's a deliberate design decision and changing that design should not be done in an ad hoc fashion like this.
Comment #65
rosk0Comment #67
alexpottWell this has not been reverted and I think the whole
has been blown out-of-water by MySQL 8 and the new reserved words that's introduced. The decisions in #371: resolve ANSI SQL-92/99/2003 reserved words conflict in query statements are no longer tenable - db drivers need to be able to quote field (and table) names as they see fit. We are never going to be able to come up with a list of reserved words because Drupal just is not in charge of what different databases considered a reserved keyword.
Comment #69
joseph.olstadThis issue appears to be preventing us from using aegir hostmaster with Postgresql