diff --git a/lib/schema.php b/lib/schema.php index f6543a21b1..04bd2d1d94 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -234,7 +234,7 @@ class Schema */ 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']); - $new = array_keys($def['fields']); - - $toadd = array_diff($new, $cur); - $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; - } - } + // @fixme check if not present + $fields = $this->diffArrays($old['fields'], $def['fields'], array($this, 'columnsEqual')); + $uniques = $this->diffArrays($old['unique keys'], $def['unique keys']); + $indexes = $this->diffArrays($old['indexes'], $def['indexes']); + /* if (count($toadd) + count($todrop) + count($tomod) == 0) { // nothing to do return true; } + */ // For efficiency, we want this all in one // query, instead of using our methods. $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, $def['fields'][$columnName]); } - foreach ($todrop as $columnName) { + foreach ($fields['mod'] as $columnName) { $this->appendAlterModifyColumn($phrase, $columnName, $old['fields'][$columnName], $def['fields'][$columnName]); } - foreach ($tomod as $columnName) { + foreach ($fields['del'] as $columnName) { $this->appendAlterDropColumn($phrase, $columnName); } - $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); - - $res = $this->conn->query($sql); - - if (PEAR::isError($res)) { - throw new Exception($res->getMessage()); + foreach ($uniques['mod'] + $uniques['add'] as $keyName) { + $this->appendAlterAddUnique($phrase, $keyName, $def['unique keys'][$keyName]); } - 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); } + 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. * diff --git a/scripts/dumpschema.php b/scripts/dumpschema.php index c0bf84f7c4..3c23636383 100644 --- a/scripts/dumpschema.php +++ b/scripts/dumpschema.php @@ -23,9 +23,15 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); $helptext = <<buildEnsureTable($tableName, $def); + $sql[] = ''; + + echo implode(";\n", $sql); + echo "\n"; +} + function showDiff($a, $b) { $fnameA = tempnam(sys_get_temp_dir(), 'defined-diff-a'); @@ -156,6 +177,8 @@ if (count($args)) { showDiff($defined, $detected); } else if (have_option('build')) { dumpBuildTable($tableName); + } else if (have_option('update')) { + dumpEnsureTable($tableName); } else { dumpTable($tableName, true); }