DESCRIPTION
I followed the exact steps from https://www.drupal.org/node/2754539 and installed the utf8mb4_convert drush command. I had configured my server as expected and adapted my settings.php file as advised. But an Exception was thrown which marked utf8mb4 as unsupported.
The culprit was the directive "default-storage-engine=MyISAM" in my my.cnf file. When the "drupal_utf8mb4_test" table was to be created, it was trying to be created as MyISAM which is limited to 1000 characters long. When requesting the table to be created as InnoDB everything worked fine.
SOLUTION
Change the SQL command from
CREATE TABLE {drupal_utf8mb4_test} (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC
to
CREATE TABLE {drupal_utf8mb4_test} (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC ENGINE=InnoDB
Comment | File | Size | Author |
---|---|---|---|
#20 | 2764221-20.patch | 776 bytes | stefan.r |
Comments
Comment #2
cilefen CreditAttribution: cilefen commentedNote for Drupal8:Drupal 8 no longer supports MyISAM as the default storage engine.
Comment #3
vensires CreditAttribution: vensires commentedRegarding to the solution proposed, I also want to remind that in Drupal 7 we don't have the requirements for InnoDB as the primary storage engine as is the case for Drupal 8.
Comment #4
cilefen CreditAttribution: cilefen commentedWhat piece of code executes that query?
Comment #5
vensires CreditAttribution: vensires commentedIt is found in includes/database/mysql/database.inc, l.224, function utf8mb4IsSupported().
It is called from Drush command utf8mb4_convert and from Drupal's status report.
Comment #6
cilefen CreditAttribution: cilefen commentedI recommend opening a similar issue in the utf8mb4_convert queue and marking this one a related issue.
Comment #7
vensires CreditAttribution: vensires commentedIt's not something the maintainers of utf8mb4_convert could fix though. I could open one though just for reference.
Comment #8
cilefen CreditAttribution: cilefen commentedOh, then I misunderstood #5. Ok, no need then.
Comment #9
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedThis needs a patch, but it seems like a reasonable change (I think)... @stefan.r would be a good person to review it.
Comment #10
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commented#9: The problem with that is that if later we try to create UTF8-MB4 tables with MyISAM it would fail in production use, so I am not sure about the patch - unless we specify the engine explicitly in later create table queries as well.
Comment #11
vensires CreditAttribution: vensires commentedMy proposition is to add the "ENGINE=InnoDB" directive to the SQL command as I initially proposed. utf8mb4_convert converts automatically any MyISAM tables to InnoDB as stated in #2762599-8: PDOException while converting cache_block table and I don't believe this function is used anywhere else or will ever be. It should be added though in both Drupal 7.50's and utf8mb4_convert's documentations that utf8mb4 is only supported with InnoDB database tables.
Comment #12
stefan.r CreditAttribution: stefan.r commentedI don't mind to have InnoDB as a requirement for D7 utf8mb4 support, so the solution proposed in the OP seems fine to me.
Setting to NW as this still needs a patch.
Comment #13
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commented#12: My Concern is would that not just hide the bug? Or would new tables created by Drupal be INNODB then?
I would imagine:
default = MyISAM
We test with specific InnoDB setting, we convert all tables => all is good
User installs 'foo' module, which creates 'foo' table.
Would 'foo' table then not use MyISAM or fail to create horribly?
Comment #14
stefan.r CreditAttribution: stefan.r commentedWell the combination of default engine = MyISAM and charset = utf8mb4 would not be allowed, and if we don't hard fail we'd probably have to ignore the default engine on table creation indeed (which seems like a better idea than falling back to utf8) and soft fail somehow
Comment #15
vensires CreditAttribution: vensires commentedI think Fabianx's point is correct. It seems to be something greater than what it originally seemed. We might have to change some other SQL commands too. For example, if the database configuration in settings.php has the following directives:
we could then add
Engine="InnoDB"
when creating new tables for modules to override the default directive.Besides, most modules (core or contrib) may not be Database Agnostic (since many assume MySQL is used) but they are definitely MySQL-Engine Agnostic. They don't know and they don't care if MEMORY, ARCHIVE, InnoDB or MyISAM is used.
If a module needs a specific engine, it could then ALTER the table in its hook_install() callback. It won't be something new actually, if you think about how modules set their weight: Drupal gives a weight of 0 and if they need something different, they set it in their hook_install() callback.
Comment #16
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedIn that respect the current behavior of saying that UTF8-MB4 is not supported is correct.
Just the reason is wrong.
Maybe we just add that InnoDB needs to be the default engine to the docs and messages and call it a day?
Comment #17
fietserwinincludes/database/mysql/schema.inc does add (since 2009-04-25, line 83):
So, IMO having it as server default is not a requirement and thus should DatabaseConnection_mysql::utf8mb4IsSupported() also add this to its test statement.
I tested with:
Results:
Fail (Error Code: 1071. Specified key was too long; max key length is 1000 bytes):
Success:
CREATE TABLE drupal_utf8mb4_test (id VARCHAR(255), PRIMARY KEY(id(255))) engine InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC
Comment #18
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commented#17: Okay, so the test case is that we already enforce InnoDB - regardless of the set default DB.
Then yes, we should use what is in schema.inc as engine explicitly.
Comment #19
stefan.r CreditAttribution: stefan.r commentedCan we add ENGINE=InnoDB to the test table creation query?
Comment #20
stefan.r CreditAttribution: stefan.r commentedUntested, but perhaps like this?
Comment #21
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedLooks good to me, RTBC.
Comment #22
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedCan someone test the patch to make sure that it works as expected?
Comment #23
fietserwinConfiguration:
show variables
gives(a.o.):The test:
utf8mb4-convert-databases
drush utf8mb4-convert-databases
Conclusion: RTBC, works as expected.
Comment #24
hass CreditAttribution: hass commentedI see this utf8mb4 support is now limited to InnoDB. Just asking - what about the other available storage engines? Memory storage engine is important I think and so on - they all do not support this utf8mb4? :-(
Comment #25
vensires CreditAttribution: vensires commentedTo enable utf8mb4, you have to specify it as your character set in your settings.php file as stated in Multi-byte UTF-8 support in Drupal 7 and UTF8MB4 Convert.
For everything to work as expected though, a query is used to validate that the database may actually create indexes with 3072 characters. 3072 characters is the limit for InnoDB tables when "innodb_large_prefix = true" exists in your configuration file. "MEMORY tables", as stated in MySQL documentation, "can have up to 64 indexes per table, 16 columns per index and a maximum key length of 3072 bytes". So, no extra configuration required for Memory engine tables. ARCHIVE tables, on the other hand, don't support indexes at all. The only problem are MyISAM tables which are still limited to 1000 characters and this was the starting point of this whole issue.
Long story short, utf8mb4 is a character set and is supported when your tables support it.
Comment #26
stefan.r CreditAttribution: stefan.r commentedComment #27
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedYup, this seems like a good improvement which makes this test table creation statement consistent with Drupal's normal table creation statements.
Committed to 7.x - thanks!
Comment #29
bobburns CreditAttribution: bobburns commentedA side note
Until I applied the patch - I could not successfully backup or copy my database for a backup in CPanel or WHM - I would get "Lost connection to server" error messages.
The table drupal_utf8mb4_test got created - but hung phpMyAdmin marked as "in use"
I could not also drop the table but had to rip it out using var/lib/mysql (other systems may have the database table in a different location) as the frm and ibd files in the backend and then use the successful query in #17 to recreate it
It would throw an error "drupal_utf8mb4_test is not in engine"
It should be noted that deleting the table was not sufficient to cause the database inc call to query and re-create it when loading the status report
I have the required support enabled in the my.cnf but not active in the settings.php and I have NOT yet converted the database
The message in the Status report also changed to
Database 4 byte UTF-8 support Disabled
4 byte UTF-8 for mysql is disabled. See the documentation on adding 4 byte UTF-8 support for more information.
from a much longer version that read
"4 byte UTF-8 for mysql is not activated, but it is supported on your system. It is recommended that you enable this to allow 4-byte UTF-8 input such as emojis, Asian symbols and mathematical symbols to be stored correctly. See the documentation on adding 4 byte UTF-8 support for more information."
The point is even if committed to core - even on the next core upgrade one may need to do manual work to fix the issue