Skip to content

Commit

Permalink
MDL-34271 use the same collation when adding new tables or columns
Browse files Browse the repository at this point in the history
  • Loading branch information
skodak committed Jul 12, 2012
1 parent 7ec63b2 commit 41e8883
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
42 changes: 40 additions & 2 deletions lib/ddl/mysql_sql_generator.php
Expand Up @@ -119,6 +119,9 @@ public function getResetSequenceSQL($table) {
public function getCreateTableSQL($xmldb_table) {
// First find out if want some special db engine.
$engine = $this->mdb->get_dbengine();
// Do we know collation?
$collation = $this->mdb->get_dbcollation();

$sqlarr = parent::getCreateTableSQL($xmldb_table);

// Let's inject the extra MySQL tweaks.
Expand All @@ -127,6 +130,12 @@ public function getCreateTableSQL($xmldb_table) {
if ($engine) {
$sqlarr[$i] .= " ENGINE = $engine";
}
if ($collation) {
if (strpos($collation, 'utf8_') === 0) {
$sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
}
$sqlarr[$i] .= " DEFAULT COLLATE = $collation";
}
}
}

Expand All @@ -141,9 +150,26 @@ public function getCreateTableSQL($xmldb_table) {
* @return array of sql statements
*/
public function getCreateTempTableSQL($xmldb_table) {
// Do we know collation?
$collation = $this->mdb->get_dbcollation();
$this->temptables->add_temptable($xmldb_table->getName());
$sqlarr = parent::getCreateTableSQL($xmldb_table); // we do not want the engine hack included in create table SQL
$sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sqlarr);

$sqlarr = parent::getCreateTableSQL($xmldb_table);

// Let's inject the extra MySQL tweaks.
foreach ($sqlarr as $i=>$sql) {
if (strpos($sql, 'CREATE TABLE ') === 0) {
// We do not want the engine hack included in create table SQL.
$sqlarr[$i] = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sql);
if ($collation) {
if (strpos($collation, 'utf8_') === 0) {
$sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
}
$sqlarr[$i] .= " DEFAULT COLLATE $collation";
}
}
}

return $sqlarr;
}

Expand Down Expand Up @@ -224,9 +250,21 @@ public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null
$xmldb_length='255';
}
$dbtype .= '(' . $xmldb_length . ')';
if ($collation = $this->mdb->get_dbcollation()) {
if (strpos($collation, 'utf8_') === 0) {
$dbtype .= " CHARACTER SET utf8";
}
$dbtype .= " COLLATE $collation";
}
break;
case XMLDB_TYPE_TEXT:
$dbtype = 'LONGTEXT';
if ($collation = $this->mdb->get_dbcollation()) {
if (strpos($collation, 'utf8_') === 0) {
$dbtype .= " CHARACTER SET utf8";
}
$dbtype .= " COLLATE $collation";
}
break;
case XMLDB_TYPE_BINARY:
$dbtype = 'LONGBLOB';
Expand Down
74 changes: 73 additions & 1 deletion lib/dml/mysqli_native_moodle_database.php
Expand Up @@ -82,7 +82,13 @@ public function create_database($dbhost, $dbuser, $dbpass, $dbname, array $dbopt
throw new dml_connection_exception($dberr);
}

$result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci");
if (isset($dboptions['dbcollation']) and strpos($dboptions['dbcollation'], 'utf8_') === 0) {
$collation = $dboptions['dbcollation'];
} else {
$collation = 'utf8_unicode_ci';
}

$result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ".$collation);

$conn->close();

Expand Down Expand Up @@ -207,6 +213,72 @@ public function get_dbengine() {
return $engine;
}

/**
* Returns the current MySQL db collation.
*
* This is an ugly workaround for MySQL default collation problems.
*
* @return string or null MySQL collation name
*/
public function get_dbcollation() {
if (isset($this->dboptions['dbcollation'])) {
return $this->dboptions['dbcollation'];
}
if ($this->external) {
return null;
}

$collation = null;

// Look for current collation of our config table (the first table that gets created),
// so that we create all tables with the same collation.
$sql = "SELECT collation_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config' AND column_name = 'value'";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
$collation = $rec['collation_name'];
}
$result->close();

if (!$collation) {
// Get the default database collation, but only if using UTF-8.
$sql = "SELECT @@collation_database";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
if (strpos($rec['@@collation_database'], 'utf8_') === 0) {
$collation = $rec['@@collation_database'];
}
}
$result->close();
}

if (!$collation) {
// We want only utf8 compatible collations.
$collation = null;
$sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
$this->query_start($sql, NULL, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end($result);
while ($res = $result->fetch_assoc()) {
$collation = $res['Collation'];
if (strtoupper($res['Default']) === 'YES') {
$collation = $res['Collation'];
break;
}
}
$result->close();
}

// Cache the result to improve performance.
$this->dboptions['dbcollation'] = $collation;
return $collation;
}

/**
* Returns localised database type name
* Note: can be used before connect()
Expand Down

0 comments on commit 41e8883

Please sign in to comment.