+ // XXX: DB engine portability -> toilet
+
+ try {
+ $td = $this->getTableDef($tableName);
+ } catch (Exception $e) {
+ if (preg_match('/no such table/', $e->getMessage())) {
+ return $this->createTable($tableName, $columns);
+ } else {
+ throw $e;
+ }
+ }
+
+ $cur = $this->_names($td->columns);
+ $new = $this->_names($columns);
+
+ $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);
+
+ if (!$newCol->equals($curCol)) {
+ $tomod[] = $newCol->name;
+ }
+ }
+
+ 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) {
+ $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);
+ }
+
+ $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
+
+ $res = $this->conn->query($sql);
+
+ if (PEAR::isError($res)) {
+ throw new Exception($res->getMessage());
+ }
+
+ return true;