some of the ensureTable stuff partially working

This commit is contained in:
Brion Vibber 2010-10-12 17:58:26 -07:00
parent 72cba88650
commit 621233e1ad
2 changed files with 88 additions and 30 deletions

View File

@ -234,7 +234,7 @@ class Schema
*/ */
function appendUniqueKeyDef(array &$sql, $name, array $def) function appendUniqueKeyDef(array &$sql, $name, array $def)
{ {
$sql[] = "UNIQUE $key " . $this->buildIndexList($def); $sql[] = "UNIQUE $name " . $this->buildIndexList($def);
} }
/** /**
@ -487,59 +487,81 @@ class Schema
} }
} }
$cur = array_keys($old['fields']); // @fixme check if not present
$new = array_keys($def['fields']); $fields = $this->diffArrays($old['fields'], $def['fields'], array($this, 'columnsEqual'));
$uniques = $this->diffArrays($old['unique keys'], $def['unique keys']);
$toadd = array_diff($new, $cur); $indexes = $this->diffArrays($old['indexes'], $def['indexes']);
$todrop = array_diff($cur, $new);
$same = array_intersect($new, $cur);
$tomod = array();
// Find which fields have actually changed definition
// in a way that we need to tweak them for this DB type.
foreach ($same as $name) {
$curCol = $old['fields'][$name];
$newCol = $cur['fields'][$name];
if (!$this->columnsEqual($curCol, $newCol)) {
$tomod[] = $name;
}
}
/*
if (count($toadd) + count($todrop) + count($tomod) == 0) { if (count($toadd) + count($todrop) + count($tomod) == 0) {
// nothing to do // nothing to do
return true; return true;
} }
*/
// For efficiency, we want this all in one // For efficiency, we want this all in one
// query, instead of using our methods. // query, instead of using our methods.
$phrase = array(); $phrase = array();
foreach ($toadd as $columnName) { foreach ($uniques['del'] + $uniques['mod'] as $keyName) {
$this->appendAlterDropUnique($phrase, $keyName);
}
foreach ($fields['add'] as $columnName) {
$this->appendAlterAddColumn($phrase, $columnName, $this->appendAlterAddColumn($phrase, $columnName,
$def['fields'][$columnName]); $def['fields'][$columnName]);
} }
foreach ($todrop as $columnName) { foreach ($fields['mod'] as $columnName) {
$this->appendAlterModifyColumn($phrase, $columnName, $this->appendAlterModifyColumn($phrase, $columnName,
$old['fields'][$columnName], $old['fields'][$columnName],
$def['fields'][$columnName]); $def['fields'][$columnName]);
} }
foreach ($tomod as $columnName) { foreach ($fields['del'] as $columnName) {
$this->appendAlterDropColumn($phrase, $columnName); $this->appendAlterDropColumn($phrase, $columnName);
} }
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); foreach ($uniques['mod'] + $uniques['add'] as $keyName) {
$this->appendAlterAddUnique($phrase, $keyName, $def['unique keys'][$keyName]);
$res = $this->conn->query($sql);
if (PEAR::isError($res)) {
throw new Exception($res->getMessage());
} }
return true; $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase);
return array($sql);
}
function diffArrays($old, $new, $compareCallback=null)
{
$oldKeys = array_keys($old ? $old : array());
$newKeys = array_keys($new ? $new : array());
$toadd = array_diff($newKeys, $oldKeys);
$todrop = array_diff($oldKeys, $newKeys);
$same = array_intersect($newKeys, $oldKeys);
$tomod = array();
$tokeep = array();
// Find which fields have actually changed definition
// in a way that we need to tweak them for this DB type.
foreach ($same as $name) {
if ($compareCallback) {
$same = call_user_func($compareCallback, $old[$name], $new[$name]);
} else {
$same = ($old[$name] != $new[$name]);
}
if ($same) {
$tokeep[] = $name;
continue;
}
$tomod[] = $name;
}
return array('add' => $toadd,
'del' => $todrop,
'mod' => $tomod,
'keep' => $tokeep);
} }
/** /**
@ -587,6 +609,19 @@ class Schema
$phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName); $phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName);
} }
function appendAlterAddUnique(array &$phrase, $keyName, array $def)
{
$sql = array();
$sql[] = 'ADD';
$this->appendUniqueKeyDef($sql, $keyName, $def);
$phrase[] = implode(' ', $sql);'ADD CONSTRAINT ' . $keyName;
}
function appendAlterDropUnique(array &$phrase, $keyName)
{
$phrase[] = 'DROP CONSTRAINT ' . $keyName;
}
/** /**
* Quote a db/table/column identifier if necessary. * Quote a db/table/column identifier if necessary.
* *

View File

@ -23,9 +23,15 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<END_OF_CHECKSCHEMA_HELP $helptext = <<<END_OF_CHECKSCHEMA_HELP
Attempt to pull a schema definition for a given table. Attempt to pull a schema definition for a given table.
--all run over all defined core tables
--diff do a raw text diff between the expected and live table defs
--update dump SQL that would be run to update or create this table
--build dump SQL that would be run to create this table fresh
END_OF_CHECKSCHEMA_HELP; END_OF_CHECKSCHEMA_HELP;
$longoptions = array('diff', 'all', 'build'); $longoptions = array('diff', 'all', 'build', 'update');
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
function indentOptions($indent) function indentOptions($indent)
@ -121,6 +127,21 @@ function dumpBuildTable($tableName)
echo "\n"; echo "\n";
} }
function dumpEnsureTable($tableName)
{
echo "-- \n";
echo "-- $tableName\n";
echo "-- \n";
$schema = Schema::get();
$def = getCoreSchema($tableName);
$sql = $schema->buildEnsureTable($tableName, $def);
$sql[] = '';
echo implode(";\n", $sql);
echo "\n";
}
function showDiff($a, $b) function showDiff($a, $b)
{ {
$fnameA = tempnam(sys_get_temp_dir(), 'defined-diff-a'); $fnameA = tempnam(sys_get_temp_dir(), 'defined-diff-a');
@ -156,6 +177,8 @@ if (count($args)) {
showDiff($defined, $detected); showDiff($defined, $detected);
} else if (have_option('build')) { } else if (have_option('build')) {
dumpBuildTable($tableName); dumpBuildTable($tableName);
} else if (have_option('update')) {
dumpEnsureTable($tableName);
} else { } else {
dumpTable($tableName, true); dumpTable($tableName, true);
} }