protected $_limit;
protected $_precision;
protected $_scale;
+ protected $_unsigned;
protected $_default;
protected $_sqlType;
protected $_isText;
*
* @param string $name The column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
* @param string $default The type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
- * @param string $sqlType Only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
+ * @param string $sqlType Used to extract the column's length and signed status, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>, or +unsigned => true+ in <tt>int(10) UNSIGNED</tt>.
* @param boolean $null Determines if this column allows +NULL+ values.
*/
public function __construct($name, $default, $sqlType = null, $null = true)
$this->_limit = $this->_extractLimit($sqlType);
$this->_precision = $this->_extractPrecision($sqlType);
$this->_scale = $this->_extractScale($sqlType);
+ $this->_unsigned = $this->_extractUnsigned($sqlType);
$this->_type = $this->_simplifiedType($sqlType);
$this->_isText = $this->_type == 'text' || $this->_type == 'string';
/**
* @return boolean
*/
+ public function isUnsigned()
+ {
+ return $this->_unsigned;
+ }
+
+ /**
+ * @return boolean
+ */
public function isNull()
{
return $this->_null;
}
/**
+ * @param string $sqlType
+ * @return int
+ */
+ protected function _extractUnsigned($sqlType)
+ {
+ return (boolean)preg_match('/^int.*unsigned/i', $sqlType);
+ }
+
+ /**
* @param string $fieldType
* @return string
*/
return 'boolean';
}
}
-
}
protected $_limit = null;
protected $_precision = null;
protected $_scale = null;
+ protected $_unsigned = null;
protected $_default = null;
protected $_null = null;
/**
* Construct
*/
- public function __construct($base, $name, $type, $limit=null,
- $precision=null, $scale=null, $default=null, $null=null)
+ public function __construct($base, $name, $type, $limit = null,
+ $precision = null, $scale = null, $unsigned = null,
+ $default = null, $null = null)
{
// protected
$this->_base = $base;
$this->_limit = $limit;
$this->_precision = $precision;
$this->_scale = $scale;
+ $this->_unsigned = $unsigned;
$this->_default = $default;
$this->_null = $null;
}
+
/*##########################################################################
# Public
##########################################################################*/
*/
public function toSql()
{
- $sql = $this->_base->quoteColumnName($this->_name).' ';
- try {
- $sql .= $this->_base->typeToSql($this->_type, $this->_limit,
- $this->_precision, $this->_scale);
- } catch (Exception $e) {
- $sql .= $this->_type;
- }
- return $this->_addColumnOptions($sql, array('null' => $this->_null,
- 'default' => $this->_default));
+ $sql = $this->_base->quoteColumnName($this->_name) . ' ' . $this->getSqlType();
+ return $this->_addColumnOptions($sql, array('null' => $this->_null,
+ 'default' => $this->_default));
}
/**
public function getSqlType()
{
try {
- return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale);
+ return $this->_base->typeToSql($this->_type, $this->_limit, $this->_precision, $this->_scale, $this->_unsigned);
} catch (Exception $e) {
return $this->_type;
}
/**
* @return boolean
*/
+ public function isUnsigned()
+ {
+ return $this->_unsigned;
+ }
+
+ /**
+ * @return boolean
+ */
public function isNull()
{
return $this->_null;
/**
* @param boolean
*/
+ public function setUnsigned($unsigned)
+ {
+ $this->_unsigned = $unsigned;
+ }
+
+ /**
+ * @param boolean
+ */
public function setNull($null)
{
$this->_null = $null;
$limit = isset($options['limit']) ? $options['limit'] : null;
$precision = isset($options['precision']) ? $options['precision'] : null;
$scale = isset($options['scale']) ? $options['scale'] : null;
+ $unsigned = isset($options['unsigned']) ? $options['unsigned'] : null;
$sql = 'ALTER TABLE ' . $this->quoteTableName($tableName) .
' ADD '.$this->quoteColumnName($columnName) .
- ' '.$this->typeToSql($type, $limit, $precision, $scale);
+ ' '.$this->typeToSql($type, $limit, $precision, $scale, $unsigned);
$sql = $this->addColumnOptions($sql, $options);
return $this->execute($sql);
}
* @param string $type
* @param string $limit
*/
- public function typeToSql($type, $limit=null, $precision=null, $scale=null)
+ public function typeToSql($type, $limit = null, $precision = null, $scale = null, $unsigned = null)
{
$natives = $this->nativeDatabaseTypes();
$native = isset($natives[$type]) ? $natives[$type] : null;
}
} else {
$nativeLimit = is_array($native) ? $native['limit'] : null;
+
+ // If there is no explicit limit, adjust $nativeLimit for unsigned
+ // integers.
+ if (!empty($unsigned) && empty($limit) && is_integer($nativeLimit)) {
+ $nativeLimit--;
+ }
+
if ($limit = !empty($limit) ? $limit : $nativeLimit) {
$sql .= "($limit)";
}
}
+
+ if (!empty($unsigned)) {
+ $sql .= ' UNSIGNED';
+ }
+
return $sql;
}
$column->setPrecision(isset($opt['precision']) ? $opt['precision'] : null);
$column->setScale(isset($opt['scale']) ? $opt['scale'] : null);
+ $column->setUnsigned(isset($opt['unsigned']) ? $opt['unsigned'] : null);
$column->setDefault(isset($opt['default']) ? $opt['default'] : null);
$column->setNull(isset($opt['null']) ? $opt['null'] : null);
$limit = !empty($options['limit']) ? $options['limit'] : null;
$precision = !empty($options['precision']) ? $options['precision'] : null;
$scale = !empty($options['scale']) ? $options['scale'] : null;
+ $unsigned = !empty($options['unsigned']) ? $options['unsigned'] : null;
- $typeSql = $this->typeToSql($type, $limit, $precision, $scale);
+ $typeSql = $this->typeToSql($type, $limit, $precision, $scale, $unsigned);
$sql = "ALTER TABLE $quotedTableName CHANGE $quotedColumnName $quotedColumnName $typeSql";
$sql = $this->addColumnOptions($sql, $options);
$limit = isset($options['limit']) ? $options['limit'] : null;
$precision = isset($options['precision']) ? $options['precision'] : null;
$scale = isset($options['scale']) ? $options['scale'] : null;
+ $unsigned = isset($options['unsigned']) ? $options['unsigned'] : null;
// 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).' '.$this->typeToSql($type, $limit, $precision, $scale, $unsigned));
$default = isset($options['default']) ? $options['default'] : null;
$notnull = isset($options['null']) && $options['null'] === false;
$limit = isset($options['limit']) ? $options['limit'] : null;
$precision = isset($options['precision']) ? $options['precision'] : null;
$scale = isset($options['scale']) ? $options['scale'] : null;
+ $unsigned = isset($options['unsigned']) ? $options['unsigned'] : null;
$quotedTableName = $this->quoteTableName($tableName);
try {
- $this->execute('ALTER TABLE '.$quotedTableName.' ALTER COLUMN '.$this->quoteColumnName($columnName).' TYPE '.$this->typeToSql($type, $limit, $precision, $scale));
+ $this->execute('ALTER TABLE '.$quotedTableName.' ALTER COLUMN '.$this->quoteColumnName($columnName).' TYPE '.$this->typeToSql($type, $limit, $precision, $scale, $unsigned));
} catch (Horde_Db_Exception $e) {
// This is PostgreSQL 7.x, or the old type could not be coerced to
// the new type, so we have to use a more arcane way of doing it.
break;
}
}
- if ($oldType === null)
+ if ($oldType === null) {
throw new Horde_Db_Exception("$tableName does not have a column '$columnName'");
+ }
$this->beginDbTransaction();
$this->addColumn($tableName, $tmpColumnName, $type, $options);
if ($oldType == 'boolean') {
- $this->execute('UPDATE '.$quotedTableName.' SET '.$this->quoteColumnName($tmpColumnName).' = CAST(CASE WHEN '.$this->quoteColumnName($columnName).' IS TRUE THEN 1 ELSE 0 END AS '.$this->typeToSql($type, $limit, $precision, $scale).')');
+ $this->execute('UPDATE '.$quotedTableName.' SET '.$this->quoteColumnName($tmpColumnName).' = CAST(CASE WHEN '.$this->quoteColumnName($columnName).' IS TRUE THEN 1 ELSE 0 END AS '.$this->typeToSql($type, $limit, $precision, $scale, $unsigned).')');
} else {
- $this->execute('UPDATE '.$quotedTableName.' SET '.$this->quoteColumnName($tmpColumnName).' = CAST('.$this->quoteColumnName($columnName).' AS '.$this->typeToSql($type, $limit, $precision, $scale).')');
+ $this->execute('UPDATE '.$quotedTableName.' SET '.$this->quoteColumnName($tmpColumnName).' = CAST('.$this->quoteColumnName($columnName).' AS '.$this->typeToSql($type, $limit, $precision, $scale, $unsigned).')');
}
$this->removeColumn($tableName, $columnName);
/**
* Maps logical Rails types to PostgreSQL-specific data types.
*/
- public function typeToSql($type, $limit = null, $precision = null, $scale = 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, $unsigned);
+
+ $unsigned = !empty($unsigned) ? ' UNSIGNED' : '';
switch ($limit) {
case 1:
case 2:
- return 'smallint';
+ return 'smallint' . $unsigned;
case 3:
case 4:
case null:
- return 'integer';
+ return 'integer' . $unsigned;
case 5:
case 6:
case 7:
case 8:
- return 'bigint';
+ return 'bigint' . $unsigned;
default:
throw new Horde_Db_Exception("No integer type has byte size $limit. Use a numeric with precision 0 instead.");
}
$this->assertEquals('`col_name` decimal(5, 2)', $col->toSql());
}
+ public function testToSqlUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer', null, null, null, true
+ );
+ $this->assertEquals('`col_name` int(10) UNSIGNED', $col->toSql());
+
+ // set attribute instead
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer'
+ );
+ $col->setUnsigned(true);
+ $this->assertEquals('`col_name` int(10) UNSIGNED', $col->toSql());
+ }
+
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, null, false
+ $this->_conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('`col_name` varchar(255) NOT NULL', $col->toSql());
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, 'test', null
+ $this->_conn, 'col_name', 'string', null, null, null, null, 'test'
);
$this->assertEquals("`col_name` varchar(255) DEFAULT 'test'", $col->toSql());
$col->setDefault('test');
$this->assertEquals("`col_name` varchar(255) DEFAULT 'test'", $col->toSql());
}
-
}
{
$col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
+ $this->assertFalse($col->isUnsigned());
+ }
+
+ public function testTypeIntegerUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Mysql_Column('age', 'NULL', 'int(10) UNSIGNED');
+ $this->assertTrue($col->isUnsigned());
}
public function testTypeFloat()
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
}
+ public function testToSqlUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer', null, null, null, true
+ );
+ $this->assertEquals('"col_name" integer UNSIGNED', $col->toSql());
+
+ // set attribute instead
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer'
+ );
+ $col->setUnsigned(true);
+ $this->assertEquals('"col_name" integer UNSIGNED', $col->toSql());
+ }
+
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, null, false
+ $this->_conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('"col_name" character varying(255) NOT NULL', $col->toSql());
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, 'test', null
+ $this->_conn, 'col_name', 'string', null, null, null, null, 'test'
);
$this->assertEquals('"col_name" character varying(255) DEFAULT \'test\'', $col->toSql());
$col->setDefault('test');
$this->assertEquals('"col_name" character varying(255) DEFAULT \'test\'', $col->toSql());
}
-
}
{
$col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
+ $this->assertFalse($col->isUnsigned());
+ }
+
+ public function testTypeIntegerUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Postgresql_Column('age', 'NULL', 'integer UNSIGNED');
+ $this->assertTrue($col->isUnsigned());
}
public function testTypeFloat()
$this->assertEquals('"col_name" decimal(5, 2)', $col->toSql());
}
+ public function testToSqlUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer', null, null, null, true
+ );
+ $this->assertEquals('"col_name" int UNSIGNED', $col->toSql());
+
+ // set attribute instead
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'integer'
+ );
+ $col->setUnsigned(true);
+ $this->assertEquals('"col_name" int UNSIGNED', $col->toSql());
+ }
+
public function testToSqlNotNull()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, null, false
+ $this->_conn, 'col_name', 'string', null, null, null, null, null, false
);
$this->assertEquals('"col_name" varchar(255) NOT NULL', $col->toSql());
);
$col->setNull(false);
$this->assertEquals('"col_name" varchar(255) NOT NULL', $col->toSql());
+
+ // set attribute to the default (true)
+ $col = new Horde_Db_Adapter_Base_ColumnDefinition(
+ $this->_conn, 'col_name', 'string'
+ );
+ $col->setNull(true);
+ $this->assertEquals('"col_name" varchar(255)', $col->toSql());
}
public function testToSqlDefault()
{
$col = new Horde_Db_Adapter_Base_ColumnDefinition(
- $this->_conn, 'col_name', 'string', null, null, null, 'test', null
+ $this->_conn, 'col_name', 'string', null, null, null, null, 'test', null
);
$this->assertEquals('"col_name" varchar(255) DEFAULT \'test\'', $col->toSql());
{
$col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'int(11)');
$this->assertEquals('integer', $col->getType());
+ $this->assertFalse($col->isUnsigned());
+ }
+
+ public function testTypeIntegerUnsigned()
+ {
+ $col = new Horde_Db_Adapter_Sqlite_Column('age', 'NULL', 'int UNSIGNED');
+ $this->assertTrue($col->isUnsigned());
}
public function testTypeFloat()