MySQL schema: fix dropping unique indexes, add support for changing table properties back from old code.

This commit is contained in:
Brion Vibber 2010-10-18 17:44:41 -07:00
parent a923ef9719
commit 4aa6c4e49f
2 changed files with 32 additions and 140 deletions

View File

@ -245,6 +245,9 @@ class MysqlSchema extends Schema
* @param string $name
* @param array $def
* @return string;
*
* @fixme ENGINE may need to be set differently in some cases,
* such as to support fulltext index.
*/
function endCreateTable($name, array $def)
{
@ -267,153 +270,36 @@ class MysqlSchema extends Schema
return "{$tableName}_{$columnName}_idx";
}
/**
* Ensures that a table exists with the given
* name and the given column definitions.
* MySQL doesn't take 'DROP CONSTRAINT', need to treat unique keys as
* if they were indexes here.
*
* If the table does not yet exist, it will
* create the table. If it does exist, it will
* alter the table to match the column definitions.
*
* @param string $tableName name of the table
* @param array $columns array of ColumnDef
* objects for the table
*
* @return boolean success flag
* @param array $phrase
* @param <type> $keyName MySQL
*/
public function oldensureTable($tableName, $columns)
function appendAlterDropUnique(array &$phrase, $keyName)
{
// XXX: DB engine portability -> toilet
try {
$td = $this->getTableDef($tableName);
} catch (SchemaTableMissingException $e) {
return $this->createTable($tableName, $columns);
}
$cur = $this->_names($td->columns);
$new = $this->_names($columns);
$dropIndex = array();
$toadd = array_diff($new, $cur);
$todrop = array_diff($cur, $new);
$same = array_intersect($new, $cur);
$tomod = array();
$addIndex = array();
$tableProps = array();
foreach ($same as $m) {
$curCol = $this->_byName($td->columns, $m);
$newCol = $this->_byName($columns, $m);
if (!$newCol->equals($curCol)) {
$tomod[] = $newCol->name;
continue;
}
// Earlier versions may have accidentally left tables at default
// charsets which might be latin1 or other freakish things.
if ($this->_isString($curCol)) {
if ($curCol->charset != 'utf8') {
$tomod[] = $newCol->name;
continue;
}
}
}
// Find any indices we have to change...
$curIdx = $this->_indexList($td->columns);
$newIdx = $this->_indexList($columns);
if ($curIdx['primary'] != $newIdx['primary']) {
if ($curIdx['primary']) {
$dropIndex[] = 'drop primary key';
}
if ($newIdx['primary']) {
$keys = implode(',', $newIdx['primary']);
$addIndex[] = "add constraint primary key ($keys)";
}
}
$dropUnique = array_diff($curIdx['uniques'], $newIdx['uniques']);
$addUnique = array_diff($newIdx['uniques'], $curIdx['uniques']);
foreach ($dropUnique as $columnName) {
$dropIndex[] = 'drop key ' . $this->_uniqueKey($tableName, $columnName);
}
foreach ($addUnique as $columnName) {
$addIndex[] = 'add constraint unique key ' . $this->_uniqueKey($tableName, $columnName) . " ($columnName)";;
}
$dropMultiple = array_diff($curIdx['indices'], $newIdx['indices']);
$addMultiple = array_diff($newIdx['indices'], $curIdx['indices']);
foreach ($dropMultiple as $columnName) {
$dropIndex[] = 'drop key ' . $this->_key($tableName, $columnName);
}
foreach ($addMultiple as $columnName) {
$addIndex[] = 'add key ' . $this->_key($tableName, $columnName) . " ($columnName)";
}
$phrase[] = 'DROP INDEX ' . $keyName;
}
/**
* Throw some table metadata onto the ALTER TABLE if we have a mismatch
* in expected type, collation.
*/
function appendAlterExtras(array &$phrase, $tableName)
{
// Check for table properties: make sure we're using a sane
// engine type and charset/collation.
// @fixme make the default engine configurable?
$oldProps = $this->getTableProperties($tableName, array('ENGINE', 'TABLE_COLLATION'));
if (strtolower($oldProps['ENGINE']) != 'innodb') {
$tableProps['ENGINE'] = 'InnoDB';
$phrase[] = 'ENGINE=InnoDB';
}
if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
$tableProps['DEFAULT CHARSET'] = 'utf8';
$tableProps['COLLATE'] = 'utf8_bin';
$phrase[] = 'DEFAULT CHARSET=utf8';
$phrase[] = 'COLLATE=utf8_bin';
}
if (count($dropIndex) + count($toadd) + count($todrop) + count($tomod) + count($addIndex) + count($tableProps) == 0) {
// nothing to do
return true;
}
// For efficiency, we want this all in one
// query, instead of using our methods.
$phrase = array();
foreach ($dropIndex as $indexSql) {
$phrase[] = $indexSql;
}
foreach ($toadd as $columnName) {
$cd = $this->_byName($columns, $columnName);
$phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd);
}
foreach ($todrop as $columnName) {
$phrase[] = 'DROP COLUMN ' . $columnName;
}
foreach ($tomod as $columnName) {
$cd = $this->_byName($columns, $columnName);
$phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd);
}
foreach ($addIndex as $indexSql) {
$phrase[] = $indexSql;
}
foreach ($tableProps as $key => $val) {
$phrase[] = "$key=$val";
}
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
common_log(LOG_DEBUG, __METHOD__ . ': ' . $sql);
$res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
}
return true;
}
/**

View File

@ -493,12 +493,6 @@ class Schema
$uniques = $this->diffArrays($old, $def, 'unique keys');
$indexes = $this->diffArrays($old, $def, 'indexes');
$total = $fields['count'] + $uniques['count'] + $indexes['count'];
if ($total == 0) {
// nothing to do
return array();
}
// For efficiency, we want this all in one
// query, instead of using our methods.
@ -527,6 +521,13 @@ class Schema
$this->appendAlterAddUnique($phrase, $keyName, $def['unique keys'][$keyName]);
}
$this->appendAlterExtras($phrase, $tableName);
if (count($phrase) == 0) {
// nothing to do
return array();
}
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase);
return array($sql);
@ -625,6 +626,11 @@ class Schema
$phrase[] = 'DROP CONSTRAINT ' . $keyName;
}
function appendAlterExtras(array &$phrase, $tableName)
{
// no-op
}
/**
* Quote a db/table/column identifier if necessary.
*