I just pushed 5.29rc through our WMF CI & it failed on a situation where it created a temp
table and that got joined on a non-temp table with a collation mix error. The issue is that the
DB default is set to utf8_general_ci (at least on our development DBs) whereas the
civicrm tables are utf8_unicode_ci. Until https://github.com/civicrm/civicrm-core/pull/18012/files
there was a list of permitted matches for db collation but now any 'utf' string matches.
From what I can tell utf8_general_ci is a pretty common collation on drupal DBs and from my tests
it causes problems if not excluded here
return CRM_Core_DAO::singleValueQuery('SELECT @@collation_database');
}
+ /**
+ * Get the collation actually being used by the tables in the database.
+ *
+ * The db collation may not match the collation used by the tables, get what is
+ * set on the tables (represented by civicrm_contact).
+ *
+ * @return string
+ */
+ public static function getInUseCollation() {
+ if (!isset(\Civi::$statics[__CLASS__][__FUNCTION__])) {
+ $dao = CRM_Core_DAO::executeQuery('SHOW TABLE STATUS LIKE \'civicrm_contact\'');
+ $dao->fetch();
+ \Civi::$statics[__CLASS__][__FUNCTION__] = $dao->Collation;
+ }
+ return \Civi::$statics[__CLASS__][__FUNCTION__];
+ }
+
/**
* Get the database collation.
*
/**
* Get the utf8 string for the table.
*
- * If the db collation is already utf8 by default (either
- * utf8 or utf84mb) then rely on that. Otherwise set to utf8.
- *
- * Respecting the DB collation supports utf8mb4 adopters, which is currently
- * not the norm in civi installs.
+ * Our tables are either utf8_unicode_ci OR utf8mb8_unicode_ci - check the contact table
+ * to see which & use the matching one.
*
* @return string
*/
public function getUtf8String() {
- if (!$this->utf8) {
- return '';
- }
- $dbUTF = CRM_Core_BAO_SchemaHandler::getDBCollation();
- if (strpos($dbUTF, 'utf8') !== FALSE) {
- return '';
- }
- return self::UTF8;
+ return $this->utf8 ? ('COLLATE ' . CRM_Core_BAO_SchemaHandler::getInUseCollation()) : '';
}
/**
$this->assertEquals(2, $rows['count'], 'Report failed - the sql used to generate the results was ' . print_r($rows['metadata']['sql'], TRUE));
- $expected = preg_replace('/\s+/', ' ', 'DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci AS
+ $expected = preg_replace('/\s+/', ' ', 'COLLATE utf8_unicode_ci AS
SELECT SQL_CALC_FOUND_ROWS contact_civireport.id as cid FROM civicrm_contact contact_civireport INNER JOIN civicrm_contribution contribution_civireport USE index (received_date) ON contribution_civireport.contact_id = contact_civireport.id
AND contribution_civireport.is_test = 0
AND contribution_civireport.receive_date BETWEEN \'20140701000000\' AND \'20150630235959\'