From: Michael M Slusarz Date: Mon, 24 May 2010 23:50:50 +0000 (-0600) Subject: Add ability to add auto-increment to columns X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=2e856e3669ebc439d13bb8127b5ff29434525ad2;p=horde.git Add ability to add auto-increment to columns Only tested on PostgreSQL --- diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php index 76c68ce44..69c405e02 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php +++ b/framework/Db/lib/Horde/Db/Adapter/Base/ColumnDefinition.php @@ -23,35 +23,37 @@ */ class Horde_Db_Adapter_Base_ColumnDefinition { - protected $_base = null; - protected $_name = null; - protected $_type = null; - protected $_limit = null; - protected $_precision = null; - protected $_scale = null; - protected $_unsigned = null; - protected $_default = null; - protected $_null = null; + protected $_base; + protected $_name; + protected $_type; + protected $_limit; + protected $_precision; + protected $_scale; + protected $_unsigned; + protected $_default; + protected $_null; + protected $_autoincrement; /** * Construct */ public function __construct($base, $name, $type, $limit = null, $precision = null, $scale = null, $unsigned = null, - $default = null, $null = null) + $default = null, $null = null, $autoincrement = null) { // protected $this->_base = $base; // public - $this->_name = $name; - $this->_type = $type; - $this->_limit = $limit; - $this->_precision = $precision; - $this->_scale = $scale; - $this->_unsigned = $unsigned; - $this->_default = $default; - $this->_null = $null; + $this->_name = $name; + $this->_type = $type; + $this->_limit = $limit; + $this->_precision = $precision; + $this->_scale = $scale; + $this->_unsigned = $unsigned; + $this->_default = $default; + $this->_null = $null; + $this->_autoincrement = $autoincrement; } @@ -159,6 +161,14 @@ class Horde_Db_Adapter_Base_ColumnDefinition } /** + * @return boolean + */ + public function isAutoIncrement() + { + return $this->_autoincrement; + } + + /** * @param string */ public function setName($name) @@ -222,6 +232,14 @@ class Horde_Db_Adapter_Base_ColumnDefinition $this->_null = $null; } + /** + * @param boolean + */ + public function setAutoIncrement($autoincrement) + { + $this->_autoincrement = $autoincrement; + } + /*########################################################################## # Schema Statements diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php index 2957c6ab6..db3066770 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Base/Schema.php @@ -706,14 +706,18 @@ abstract class Horde_Db_Adapter_Base_Schema */ public function addColumnOptions($sql, $options) { + /* 'autoincrement' is not handled here - it varies too much between + * DBs. Do autoincrement specific handling in the driver. */ if (isset($options['null']) && $options['null'] === false) { $sql .= ' NOT NULL'; } + if (isset($options['default'])) { $default = $options['default']; $column = isset($options['column']) ? $options['column'] : null; $sql .= ' DEFAULT '.$this->quote($default, $column); } + return $sql; } diff --git a/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php b/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php index c8b4d42f6..11d7f758f 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php +++ b/framework/Db/lib/Horde/Db/Adapter/Base/TableDefinition.php @@ -92,6 +92,14 @@ class Horde_Db_Adapter_Base_TableDefinition implements ArrayAccess, IteratorAggr * * :null: * Allows or disallows +NULL+ values in the column. This option could * have been named :null_allowed. + * * :precision + * TODO + * * :scale + * TODO + * * :unsigned + * TODO + * * :autoincrement + * TODO * * This method returns self. * @@ -123,6 +131,7 @@ class Horde_Db_Adapter_Base_TableDefinition implements ArrayAccess, IteratorAggr $column->setUnsigned(isset($options['unsigned']) ? $options['unsigned'] : null); $column->setDefault(isset($options['default']) ? $options['default'] : null); $column->setNull(isset($options['null']) ? $options['null'] : null); + $column->setAutoIncrement(isset($options['autoincrement']) ? $options['autoincrement'] : null); $this[$name] ? $this[$name] = $column : $this->_columns[] = $column; return $this; diff --git a/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php index a999e5b89..611e76139 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mssql/Schema.php @@ -49,7 +49,7 @@ class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Base_Schema { return array( /* TODO, just put in nchar for unicode strings */ - 'primaryKey' => 'int(11) DEFAULT NULL auto_increment PRIMARY KEY', + 'primaryKey' => 'int(11) DEFAULT NULL IDENTITY PRIMARY KEY', 'string' => array('name' => 'nchar', 'limit' => 255), 'text' => array('name' => 'text', 'limit' => null), 'integer' => array('name' => 'int', 'limit' => 11), @@ -129,4 +129,40 @@ class Horde_Db_Adapter_Mssql_Schema extends Horde_Db_Adapter_Base_Schema return $this->selectOne('SELECT @@IDENTITY'); } + /** + * Changes the column of a table. + */ + public function changeColumn($tableName, $columnName, $type, + $options = array()) + { + parent::changeColumn($tableName, $columnName, $type, $options); + + if (!empty($options['autoincrement'])) { + /* Can't alter column in table - need to create, remove old + * column, and rename: + * http://www.eggheadcafe.com/software/aspnet/30132263/alter-table-add-identity.aspx */ + // TODO: Better temp name? + $this->addColumn($tableName, $columnName . '_temp', $type, $options); + $this->removeColumn($tableName, $columnName); + $this->renameColumn($tableName, $columnName . '_temp', $columnName); + } + } + + /** + * Add additional column options. + * + * @param string $sql + * @param array $options + * @return string + */ + public function addColumnOptions($sql, $options) + { + $sql = parent::addColumnOptions($sql, $options); + if (!empty($options['autoincrement'])) { + $sql .= ' IDENTITY'; + } + return $sql; + } + + } diff --git a/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php index ddbf4dd5f..24b3263ca 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Mysql/Schema.php @@ -414,7 +414,7 @@ class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Base_Schema } /** - * Add AFTER option + * Add additional column options. * * @param string $sql * @param array $options @@ -426,6 +426,9 @@ class Horde_Db_Adapter_Mysql_Schema extends Horde_Db_Adapter_Base_Schema if (isset($options['after'])) { $sql .= " AFTER ".$this->quoteColumnName($options['after']); } + if (!empty($options['autoincrement'])) { + $sql .= ' AUTO_INCREMENT'; + } return $sql; } diff --git a/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php index 321dac840..f269d0b85 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php @@ -35,4 +35,57 @@ class Horde_Db_Adapter_Oracle_Schema extends Horde_Db_Adapter_Base_Schema return '"' . str_replace('"', '""', $name) . '"'; } + /** + * Adds a new column to the named table. + * See TableDefinition#column for details of the options you can use. + * + * @throws Horde_Db_Exception + */ + public function addColumn($tableName, $columnName, $type, + $options = array()) + { + parent::addColumn($tableName, $columnName, $type, $options); + + if (!empty($options['autoincrement'])) { + $this->_autoSequenceColumn($tableName, $columnName); + } + } + + /** + * Changes the column of a table. + * + * @throws Horde_Db_Exception + */ + public function changeColumn($tableName, $columnName, $type, + $options = array()) + { + parent::changeColumn($tableName, $columnName, $type, $options); + + if (!empty($options['autoincrement'])) { + $this->_autoSequenceColumn($tableName, $columnName); + } + } + + /** + * Add auto-sequencing to a column. + * + * @throws Horde_Db_Exception + */ + protected function _autoSequenceColumn($tableName, $columnName) + { + $seq_name = $tableName . '_' . $columnName . '_seq'; + $trigger_name = $tableName . '_' . $columnName . '_trigger'; + + $this->beginDbTransaction(); + $this->executeWrite('CREATE SEQUENCE ' . $seq_name); + $this->executeWrite( + 'CREATE TRIGGER ' . $trigger_name . ' ' . + 'BEFORE INSERT ON ' . $this->quoteTableName($tableName) . ' ' . + 'FOR EACH ROW ' + 'BEGIN ' + 'SELECT ' . $seq_name . '.nextval INTO :new.' . $columnName . ' FROM dual; END' + ); + $this->commitDbTransaction(); + } + } diff --git a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php index c49f97d05..991fe75e5 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Postgresql/Schema.php @@ -437,23 +437,45 @@ class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema * Adds a new column to the named table. * See TableDefinition#column for details of the options you can use. */ - public function addColumn($tableName, $columnName, $type, $options = array()) + public function addColumn($tableName, $columnName, $type, + $options = array()) { $this->_clearTableCache($tableName); + $autoincrement = isset($options['autoincrement']) ? $options['autoincrement'] : null; $limit = isset($options['limit']) ? $options['limit'] : null; $precision = isset($options['precision']) ? $options['precision'] : null; $scale = isset($options['scale']) ? $options['scale'] : null; + $sqltype = $this->typeToSql($type, $limit, $precision, $scale); + + /* Convert to SERIAL type if needed. */ + if ($autoincrement) { + switch ($sqltype) { + case 'bigint': + $sqltype = 'BIGSERIAL'; + break; + + case 'integer': + default: + $sqltype = 'SERIAL'; + break; + } + } + // Add the column. - $this->execute('ALTER TABLE '.$this->quoteTableName($tableName).' ADD COLUMN '.$this->quoteColumnName($columnName).' '.$this->typeToSql($type, $limit, $precision, $scale)); + $this->execute('ALTER TABLE ' . $this->quoteTableName($tableName) . ' ADD COLUMN ' . $this->quoteColumnName($columnName) . ' ' . $sqltype); $default = isset($options['default']) ? $options['default'] : null; $notnull = isset($options['null']) && $options['null'] === false; - if (array_key_exists('default', $options)) + + if (array_key_exists('default', $options)) { $this->changeColumnDefault($tableName, $columnName, $default); - if ($notnull) + } + + if ($notnull) { $this->changeColumnNull($tableName, $columnName, false, $default); + } } /** @@ -463,6 +485,7 @@ class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema { $this->_clearTableCache($tableName); + $autoincrement = isset($options['autoincrement']) ? $options['autoincrement'] : null; $limit = isset($options['limit']) ? $options['limit'] : null; $precision = isset($options['precision']) ? $options['precision'] : null; $scale = isset($options['scale']) ? $options['scale'] : null; @@ -511,10 +534,18 @@ class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema } $default = isset($options['default']) ? $options['default'] : null; - if (array_key_exists('default', $options)) + + if ($autoincrement) { + $seq_name = $this->quoteSequenceName($this->defaultSequenceName($tableName, $columnName)); + $this->execute('CREATE SEQUENCE ' . $seq_name); + $this->changeColumnDefault($tableName, $columnName, 'NEXTVAL(' . $seq_name . ')'); + } elseif (array_key_exists('default', $options)) { $this->changeColumnDefault($tableName, $columnName, $default); - if (array_key_exists('null', $options)) + } + + if (array_key_exists('null', $options)) { $this->changeColumnNull($tableName, $columnName, $options['null'], $default); + } } /** @@ -555,27 +586,34 @@ class Horde_Db_Adapter_Postgresql_Schema extends Horde_Db_Adapter_Base_Schema /** * Maps logical Rails types to PostgreSQL-specific data types. + * + * @throws Horde_Db_Exception */ - public function typeToSql($type, $limit = null, $precision = null, $scale = null, $unsigned = null) + public function typeToSql($type, $limit = null, $precision = null, + $scale = null, $unsigned = null) { - if ($type != 'integer') return parent::typeToSql($type, $limit, $precision, $scale); + if ($type != 'integer') { + return parent::typeToSql($type, $limit, $precision, $scale); + } switch ($limit) { case 1: case 2: return 'smallint'; + case 3: case 4: case null: return 'integer'; + case 5: case 6: case 7: case 8: return 'bigint'; - default: - throw new Horde_Db_Exception("No integer type has byte size $limit. Use a numeric with precision 0 instead."); } + + throw new Horde_Db_Exception("No integer type has byte size $limit. Use a numeric with precision 0 instead."); } /** diff --git a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php index 6ff7efa95..76a1d797e 100644 --- a/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php +++ b/framework/Db/lib/Horde/Db/Adapter/Sqlite/Schema.php @@ -207,6 +207,8 @@ class Horde_Db_Adapter_Sqlite_Schema extends Horde_Db_Adapter_Base_Schema */ public function addColumn($tableName, $columnName, $type, $options=array()) { + /* Ignore ':autoincrement' - it is handled automatically my SQLite + * for any 'INTEGER PRIMARY KEY' column. */ if ($this->transactionStarted()) { throw new Horde_Db_Exception('Cannot add columns to a SQLite database while inside a transaction'); } diff --git a/framework/Db/package.xml b/framework/Db/package.xml index 37faba39d..ee6ac00fa 100644 --- a/framework/Db/package.xml +++ b/framework/Db/package.xml @@ -30,7 +30,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> beta BSD - * Add ability to define a write DB for use with split-DB installations. + * Add support for adding autoincrement to a column. + * Add ability to define a write DB for use with split-DB installations. * Initial release