Problem/Motivation

#2503755: Switch from user login block to login menu link and search block in standard profile got committed and then needed to be reverted because there was a single test failure in both SQLite and Postgres, that was only discovered after commit (because we don't test every patch against those two DBs, but we do test HEAD against them).

After a long search, the root cause was discovered at #2503755-142: Switch from user login block to login menu link and search block in standard profile:

I found the root cause.

There are two.

On MySQL, ToolbarAdminMenuTest::testLocaleTranslationSubtreesHashCacheClear(), where it saves a translation ($this->drupalPostForm('admin/config/regional/translate', $edit, t('Save translations'));) is posting the translation for Menus to the first text area on this page:

On SQLite, it looks like this:

On SQLite, but without this patch's DefaultMenuLinkTreeManipulators and MenuLinkBase hunks, it looks like this:

Root cause one: config_translation behaves differently in SQLite/Postgres vs. Mysql
Note how there is one match in MySQL versus 3 in SQLite. Note how MySQL appears to be doing case-sensitive matching, and SQLite case-insensitive.
Root cause two: different ordering with this patch
Somehow, the changes in DefaultMenuLinkTreeManipulators and/or MenuLinkBase are causing a different ordering of those 3 matches.
Conclusion
The test assumes there will be only one match. It's only by chance that HEAD is passing, because in HEAD the first match just happens to be the right one. It should actually only show one match.
So the test translates the WRONG string, and therefore the toolbar menu is the same before and after, and hence the subtrees hash doesn't change on SQLite/Postgres.

Clearly, there are much deeper problems at play here.

This was one giant WTF! It'd be funny if it wasn't just before RC and I now have to somehow fix SQLite support in code totally unrelated to this issue…

Then, Gábor Hojtsy did a further analysis, figuring out why it's behaving differently on SQLite/Postgres, i.e. where the DB mismatch exists, over at #2503755-144: Switch from user login block to login menu link and search block in standard profile:

Looking at the locale schema (the bug has nothing to do with config translation):

function locale_schema() {
  $schema['locales_source'] = array(
    'description' => 'List of English source strings.',
    'fields' => array(
      // ...
      'source' => array(
        'type' => 'text',
        'mysql_type' => 'blob',
        'not null' => TRUE,
        'description' => 'The original string in English.',
      ),
      // ...
    ),
    'primary key' => array('lid'),
    'indexes' => array(
      'source_context' => array(array('source', 30), 'context'),
    ),
  );

  $schema['locales_target'] = array(
    'description' => 'Stores translated versions of strings.',
    'fields' => array(
      // ...
      'translation' => array(
        'type' => 'text',
        'mysql_type' => 'blob',
        'not null' => TRUE,
        'description' => 'Translation string value in this language.',
      ),
      // ...
  );

So in both cases, specifies blob only for MySQL specifically. I don't know if there was a reason to not specify blob for other DB engines given the 'type' key itself supports blob as per our docs:

 *     - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int',
 *       'float', 'numeric', or 'serial'. Most types just map to the according
 *       database engine specific datatypes. Use 'serial' for auto incrementing
 *       fields. This will expand to 'INT auto_increment' on MySQL.
 *       A special 'varchar_ascii' type is also available for limiting machine
 *       name field to US ASCII characters.
 *     - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to
 *       use a record type not included in the officially supported list
 *       of types above, you can specify a type for each database
 *       backend. In this case, you can leave out the type parameter,
 *       but be advised that your schema will fail to load on backends that
 *       do not have a type specified. A possible solution can be to
 *       use the "text" type as a fallback.

As per our database.api.php. OTOH looking at the SQLite schema driver, it would only make a text field case insensitive if we did explictly provide a binary key with a FALSE value:

      if (in_array($spec['sqlite_type'], array('VARCHAR', 'TEXT'))) {
        if (isset($spec['length'])) {
          $sql .= '(' . $spec['length'] . ')';
        }

        if (isset($spec['binary']) && $spec['binary'] === FALSE) {
          $sql .= ' COLLATE NOCASE_UTF8';
        }
      }

Did not find the relevant code in the PgSQL driver.

Proposed resolution

Adjust locale.module's DB schema per Gábor's findings.

Remaining tasks

TBD

User interface changes

None.

API changes

None.

Data model changes

None.

Comments

Wim Leers created an issue. See original summary.

gábor hojtsy’s picture

Title: Update locale DB schema to allow for case-insensitive search » Update locale DB schema to be case insensitive (blob) on all database types
Issue tags: +Needs tests, +language-ui

We should make it case sensitive, NOT case insensitive. If it is insensitive, then "Menus" = "menus", while you don't want that to get translations for things that don't match your source string case. It used to be at least prohibitive to try and match case insensitive columns sensitively at runtime (and vice-versa I believe was impossible). So our solution has been to make the field case sensitive, so each string is unique if there is a different in cases, so "menus" != "Menus".

gábor hojtsy’s picture

Title: Update locale DB schema to be case insensitive (blob) on all database types » Locale DB schema case insensitive (blob) only on MySQL not on other databases

Retitle again for the bug itself instead of what to do :)

wim leers’s picture

LOL, oops — sorry about that typo! :D

catch’s picture

david_garcia’s picture

Issue tags: +Needs backport to D7

Revisiting this from the related issue there are 2 possible ways of fixing it:

1 - Use "serial => 'true'" to indicate that this should be case sensitive.
2 - Use "type => 'blob'"

I'd rather use (1) because after all we are storing strings here and that makes the locale related tables more usable and readable.

Binary storage should be used for stuff that actualy makes sense to store as binary.

Anyways, anything such as this:

'mysql_type' => 'blob',

should be removed from core there is a database abstraction layer for something...

And this is happening in D7 too.

gábor hojtsy’s picture

Where is that serial => TRUE option? I also see a serial type and that would be a number so not suitable.

david_garcia’s picture

I meant binary not serial.

gábor hojtsy’s picture

@david_garcia: oh, ok! Wanna take a first stab at the patch / tests?

david_garcia’s picture

Status: Active » Needs review
StatusFileSize
new1.46 KB

I don't work on *nix or MySQL so I did not test on that platform, but I am so sure that the MySQL driver will not handle the switch from BLOB back to text.

Let's see what the test bot has to say about it.

No tests yet. I feel there is a lot more to test here than just this specific use case such as:

- Underlying driver properly handling the BINARY specificacion. This is not covered by core tests.
- Testing the ability to switch between BLOB and other Data Types, I have a feeling that none of the current drivers will be able to do so.

gábor hojtsy’s picture

Status: Needs review » Needs work

Looking good on all tested environments, woot :) Would need tests for the update itself as well as the new schema :)

  1. +++ b/core/modules/locale/locale.install
    @@ -296,3 +296,33 @@ function locale_requirements($phase) {
    + * Fixes an error in the definition of locale_source and locales_target
    + * where specific MySQL attributes where being used.
    

    Should be on one line. This shows up on update.php

  2. +++ b/core/modules/locale/locale.install
    @@ -296,3 +296,33 @@ function locale_requirements($phase) {
    +  $schema = locale_schema();
    

    Should not use the runtime schema. This may change in later releases which would change the behavior of this function. The newly desired schema for the two fields should be included verbatim.

david_garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new5.04 KB

Let's try luck with this test.

Status: Needs review » Needs work

The last submitted patch, 12: 2580671-locale-issue.patch, failed testing.

david_garcia’s picture

So looks like blob should be case sensitive and accent sensitive... makes sense...

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

valthebald’s picture

Version: 8.2.x-dev » 8.4.x-dev
Issue tags: +SprintWeekend2017

Working on this as part of SprintWeekend2017 in Sofia

valthebald’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new5.56 KB

Removing 'Needs tests', as test is in place
Changed location of SchemaTest
Applied code style changes
Removed deprecated functions/methods calls

david_garcia’s picture

Status: Needs review » Needs work

Please do not use the "query" method of the connection object. We have a database abstraction layer for something....

david_garcia’s picture

Issue tags: +Perfomance

Added the performance tag. This issue prevents prevents the locale cache from working as expected on non mysql databases.

valthebald’s picture

Status: Needs work » Needs review
StatusFileSize
new4.73 KB
new2.78 KB

@david_garcia fair point about db_query(). I've changed the query, and also dared to exclude accent-insensitive part of test, since:
a) This consistently fails under sqlite
b) I have found no clear evidence on cross-database way to handle accent sensitivity.
IMO it's more important to have test coverage about case (in)sensitivity, than accent sensitivity

Status: Needs review » Needs work

The last submitted patch, 22: 2580671-22.patch, failed testing.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

rosk0’s picture

rosk0’s picture

Assigned: Unassigned » rosk0

MySQL: Patch fails because we assuming that we use accent sensitive collation, but we don't according to https://dev.mysql.com/doc/refman/5.7/en/charset-collation-implementation.... See also http://mysqlserverteam.com/sushi-beer-an-introduction-of-utf8-support-in...

PostgreSQL: According to documentation all collations work in accent sensitive manner. Refer to https://www.postgresql.org/docs/9.1/static/textsearch-dictionaries.html https://www.postgresql.org/docs/9.1/static/unaccent.html

Based on this I'm going to remove accented words from test matrix.

rosk0’s picture

Assigned: rosk0 » Unassigned
Status: Needs work » Needs review
StatusFileSize
new4.5 KB
new1.15 KB
rosk0’s picture

Removed all mentions of accent from the patch because we are not testing it and improved assertion message.

I think this issue is block by #2464481: PostgreSQL: deal with case insensitivity and #1518506: Normalize how case sensitivity is handled across database engines.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Came here for stale-issue-content but still appears to be blocked on the issues in #28

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.