*/
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;
}
}
/**
+ * @return boolean
+ */
+ public function isAutoIncrement()
+ {
+ return $this->_autoincrement;
+ }
+
+ /**
* @param string
*/
public function setName($name)
$this->_null = $null;
}
+ /**
+ * @param boolean
+ */
+ public function setAutoIncrement($autoincrement)
+ {
+ $this->_autoincrement = $autoincrement;
+ }
+
/*##########################################################################
# Schema Statements
*/
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;
}
* * <tt>:null</tt>:
* Allows or disallows +NULL+ values in the column. This option could
* have been named <tt>:null_allowed</tt>.
+ * * <tt>:precision</tt>
+ * TODO
+ * * <tt>:scale</tt>
+ * TODO
+ * * <tt>:unsigned</tt>
+ * TODO
+ * * <tt>:autoincrement</tt>
+ * TODO
*
* This method returns <tt>self</tt>.
*
$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;
{
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),
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;
+ }
+
+
}
}
/**
- * Add AFTER option
+ * Add additional column options.
*
* @param string $sql
* @param array $options
if (isset($options['after'])) {
$sql .= " AFTER ".$this->quoteColumnName($options['after']);
}
+ if (!empty($options['autoincrement'])) {
+ $sql .= ' AUTO_INCREMENT';
+ }
return $sql;
}
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();
+ }
+
}
* 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);
+ }
}
/**
{
$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;
}
$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);
+ }
}
/**
/**
* 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.");
}
/**
*/
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');
}
<api>beta</api>
</stability>
<license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
- <notes>* Add ability to define a write DB for use with split-DB installations.
+ <notes>* Add support for adding autoincrement to a column.
+ * Add ability to define a write DB for use with split-DB installations.
* Initial release
</notes>
<contents>