From 2e475ceab05c92014e428fe6db6bc79badaad9ca Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 18:33:02 -0700 Subject: Some more poking at schema stuff, on the road towards a more portable table-modification with the new schema bits --- lib/schema.php | 117 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 16 deletions(-) (limited to 'lib/schema.php') diff --git a/lib/schema.php b/lib/schema.php index 5868627ed..60d3324ad 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -345,12 +345,12 @@ class Schema * @return boolean success flag */ - public function ensureTable($tableName, $columns) + public function ensureTable($tableName, $def) { // XXX: DB engine portability -> toilet try { - $td = $this->getTableDef($tableName); + $old = $this->getTableDef($tableName); } catch (Exception $e) { if (preg_match('/no such table/', $e->getMessage())) { return $this->createTable($tableName, $columns); @@ -359,20 +359,22 @@ class Schema } } - $cur = $this->_names($td->columns); - $new = $this->_names($columns); + $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(); - foreach ($same as $m) { - $curCol = $this->_byName($td->columns, $m); - $newCol = $this->_byName($columns, $m); + // 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 (!$newCol->equals($curCol)) { - $tomod[] = $newCol->name; + if (!$this->columnsEqual($curCol, $newCol)) { + $tomod[] = $name; } } @@ -387,19 +389,18 @@ class Schema $phrase = array(); foreach ($toadd as $columnName) { - $cd = $this->_byName($columns, $columnName); - - $phrase[] = 'ADD COLUMN ' . $this->_columnSql($cd); + $this->appendAlterAddColumn($phrase, $columnName, + $def['fields'][$columnName]); } foreach ($todrop as $columnName) { - $phrase[] = 'DROP COLUMN ' . $columnName; + $this->appendAlterModifyColumn($phrase, $columnName, + $old['fields'][$columnName], + $def['fields'][$columnName]); } foreach ($tomod as $columnName) { - $cd = $this->_byName($columns, $columnName); - - $phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd); + $this->appendAlterDropColumn($phrase, $columnName); } $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase); @@ -413,6 +414,90 @@ class Schema return true; } + /** + * Append phrase(s) to an array of partial ALTER TABLE chunks in order + * to add the given column definition to the table. + * + * @param array $phrase + * @param string $columnName + * @param array $cd + */ + function appendAlterAddColumn(array &$phrase, $columnName, array $cd) + { + $phrase[] = 'ADD COLUMN ' . + $this->quoteIdentifier($columnName) . + ' ' . + $this->columnSql($cd); + } + + /** + * Append phrase(s) to an array of partial ALTER TABLE chunks in order + * to alter the given column from its old state to a new one. + * + * @param array $phrase + * @param string $columnName + * @param array $old previous column definition as found in DB + * @param array $cd current column definition + */ + function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd) + { + $phrase[] = 'MODIFY COLUMN ' . + $this->quoteIdentifier($columnName) . + ' ' . + $this->columnSql($cd); + } + + /** + * Append phrase(s) to an array of partial ALTER TABLE chunks in order + * to drop the given column definition from the table. + * + * @param array $phrase + * @param string $columnName + */ + function appendAlterDropColumn(array &$phrase, $columnName) + { + $phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName); + } + + /** + * Quote a db/table/column identifier if necessary. + * + * @param string $name + * @return string + */ + function quoteIdentifier($name) + { + return $name; + } + + function quoteDefaultValue($cd) + { + if ($cd['type'] == 'datetime' && $cd['default'] == 'CURRENT_TIMESTAMP') { + return $cd['default']; + } else { + return $this->quoteValue($cd['default']); + } + } + + function quoteValue($val) + { + return $this->conn->escape($val); + } + + /** + * Check if two column definitions are equivalent. + * The default implementation checks _everything_ but in many cases + * you may be able to discard a bunch of equivalencies. + * + * @param array $a + * @param array $b + * @return boolean + */ + function columnsEqual(array $a, array $b) + { + return !array_diff_assoc($a, $b) && !array_diff_assoc($b, $a); + } + /** * Returns the array of names from an array of * ColumnDef objects. -- cgit v1.2.3-54-g00ecf