Skip to content

Commit

Permalink
Implement several Oracle workarounds.
Browse files Browse the repository at this point in the history
Fixes autoincrements.
Returns IDs from INSERTs.
Allows switching columns between NULL and NOT NULL.
  • Loading branch information
yunosh committed Jan 7, 2014
1 parent 0658ad8 commit 02ae830
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 48 deletions.
5 changes: 1 addition & 4 deletions framework/Db/lib/Horde/Db/Adapter/Oci8.php
Expand Up @@ -320,12 +320,9 @@ public function insert($sql, $arg1 = null, $arg2 = null, $pk = null,
$idValue = null, $sequenceName = null)
{
$this->execute($sql, $arg1, $arg2);

return $idValue
? $idValue
: ($sequenceName
? $this->selectOne('SELECT ' . $this->quoteColumnName($sequenceName) . '.currval FROM dual')
: null);
: $this->selectValue('SELECT id FROM horde_db_autoincrement');
}

/**
Expand Down
77 changes: 64 additions & 13 deletions framework/Db/lib/Horde/Db/Adapter/Oracle/Schema.php
Expand Up @@ -410,8 +410,6 @@ public function removeColumn($tableName, $columnName)
*/
public function changeColumn($tableName, $columnName, $type, $options = array())
{
$this->_clearTableCache($tableName);

$options = array_merge(
array(
'limit' => null,
Expand All @@ -422,6 +420,23 @@ public function changeColumn($tableName, $columnName, $type, $options = array())
$options
);

if ($type == 'autoincrementKey') {
try {
$this->removePrimaryKey($tableName);
} catch (Horde_Db_Exception $e) {
}
}

if (isset($options['null']) &&
$this->column($tableName, $columnName)->isNull() == $options['null']) {
unset($options['null']);
} elseif (!isset($options['null']) &&
!$this->column($tableName, $columnName)->isNull()) {
$options['null'] = true;
}

$this->_clearTableCache($tableName);

if ($type == 'binary') {
$this->beginDbTransaction();
$this->addColumn($tableName, $columnName . '_tmp', $type, $options);
Expand All @@ -437,17 +452,49 @@ public function changeColumn($tableName, $columnName, $type, $options = array())
return;
}

$sql = sprintf('ALTER TABLE %s MODIFY (%s %s)',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->typeToSql($type,
$options['limit'],
$options['precision'],
$options['scale'],
$options['unsigned']));
$sql = $this->quoteColumnName($columnName)
. ' '
. $this->typeToSql(
$type,
$options['limit'],
$options['precision'],
$options['scale'],
$options['unsigned']
);
$sql = $this->addColumnOptions($sql, $options);

return $this->execute($sql);
$sql = sprintf(
'ALTER TABLE %s MODIFY (%s)',
$this->quoteTableName($tableName),
$sql
);

$this->execute($sql);

if ($type == 'autoincrementKey') {
$this->createAutoincrementTrigger($tableName, $columnName);
}
}

public function createAutoincrementTrigger($tableName, $columnName)
{
$id = $tableName . '_' . $columnName;
if (!$this->selectValue('SELECT 1 FROM USER_TABLES WHERE TABLE_NAME = \'HORDE_DB_AUTOINCREMENT\'')) {
$this->execute('CREATE TABLE horde_db_autoincrement (id INTEGER)');
$this->execute('INSERT INTO horde_db_autoincrement (id) VALUES (0)');
}
$this->execute(sprintf(
'CREATE SEQUENCE %s_seq',
$id
));
$this->execute(sprintf(
'CREATE OR REPLACE TRIGGER %s_trig BEFORE INSERT ON %s FOR EACH ROW DECLARE increment INTEGER; BEGIN SELECT %s_seq.NEXTVAL INTO :NEW.%s FROM dual; SELECT %s_seq.CURRVAL INTO increment FROM dual; UPDATE horde_db_autoincrement SET id = increment; END;',
$id,
$tableName,
$id,
$columnName,
$id
));
}

/**
Expand Down Expand Up @@ -610,11 +657,15 @@ public function addColumnOptions($sql, $options)
$sql .= ' DEFAULT ' . $this->quote($default, $column);
}

if (isset($options['null']) && $options['null'] === false &&
if (isset($options['null']) &&
(!isset($options['column']) ||
($options['column']->getType() != 'text' &&
$options['column']->getType() != 'binary'))) {
$sql .= ' NOT NULL';
if ($options['null']) {
$sql .= ' NULL';
} else {
$sql .= ' NOT NULL';
}
}

return $sql;
Expand Down
13 changes: 1 addition & 12 deletions framework/Db/lib/Horde/Db/Adapter/Oracle/TableDefinition.php
Expand Up @@ -65,18 +65,7 @@ public function end()
{
parent::end();
if ($this->_createTrigger) {
$id = $this->_name . '_' . $this->_createTrigger;
$this->_base->execute(sprintf(
'CREATE SEQUENCE %s_seq',
$id
));
$this->_base->execute(sprintf(
'CREATE OR REPLACE TRIGGER %s_trig BEFORE INSERT ON %s FOR EACH ROW BEGIN SELECT %s_seq.NEXTVAL INTO :NEW.%s FROM dual; END;',
$id,
$this->_name,
$id,
$this->_createTrigger
));
$this->_base->createAutoincrementTrigger($this->_name, $this->_createTrigger);
}
}
}
41 changes: 24 additions & 17 deletions framework/Db/test/Horde/Db/Adapter/Oci8Test.php
Expand Up @@ -224,6 +224,13 @@ public function testRenameColumn()
$this->assertEquals('number', $afterChange->getSqlType());
}

public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertEquals('ind_spo_on_nam_and_is_col', $name);
}

public function testTypeToSqlTypePrimaryKey()
{
$result = $this->_conn->typeToSql('autoincrementKey');
Expand Down Expand Up @@ -298,29 +305,29 @@ public function testTypeToSqlBoolean()

public function testAddColumnOptions()
{
$result = $this->_conn->addColumnOptions("test", array());
$this->assertEquals("test", $result);
$result = $this->_conn->addColumnOptions('test', array());
$this->assertEquals('test', $result);
}

public function testAddColumnOptionsDefault()
{
$options = array('default' => '0');
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test DEFAULT '0'", $result);
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals('test DEFAULT \'0\'', $result);
}

public function testAddColumnOptionsNull()
{
$options = array('null' => true);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test", $result);
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals('test NULL', $result);
}

public function testAddColumnOptionsNotNull()
{
$options = array('null' => false);
$result = $this->_conn->addColumnOptions("test", $options);
$this->assertEquals("test NOT NULL", $result);
$result = $this->_conn->addColumnOptions('test', $options);
$this->assertEquals('test NOT NULL', $result);
}

public function testModifyDate()
Expand Down Expand Up @@ -364,23 +371,23 @@ public function testBuildClause()

$this->assertEquals(
"LOWER(name) LIKE LOWER('%search%')",
$this->_conn->buildClause('name', 'LIKE', "search"));
$this->_conn->buildClause('name', 'LIKE', 'search'));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search%')),
$this->_conn->buildClause('name', 'LIKE', "search", true));
array('LOWER(name) LIKE LOWER(?)', array('%search%')),
$this->_conn->buildClause('name', 'LIKE', 'search', true));
$this->assertEquals(
"LOWER(name) LIKE LOWER('%search\&replace\?%')",
$this->_conn->buildClause('name', 'LIKE', "search&replace?"));
$this->_conn->buildClause('name', 'LIKE', 'search&replace?'));
$this->assertEquals(
array("LOWER(name) LIKE LOWER(?)", array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true));
array('LOWER(name) LIKE LOWER(?)', array('%search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', 'search&replace?', true));
$this->assertEquals(
"(LOWER(name) LIKE LOWER('search\&replace\?%') OR LOWER(name) LIKE LOWER('% search\&replace\?%'))",
$this->_conn->buildClause('name', 'LIKE', "search&replace?", false, array('begin' => true)));
$this->_conn->buildClause('name', 'LIKE', 'search&replace?', false, array('begin' => true)));
$this->assertEquals(
array("(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))",
array('(LOWER(name) LIKE LOWER(?) OR LOWER(name) LIKE LOWER(?))',
array('search&replace?%', '% search&replace?%')),
$this->_conn->buildClause('name', 'LIKE', "search&replace?", true, array('begin' => true)));
$this->_conn->buildClause('name', 'LIKE', 'search&replace?', true, array('begin' => true)));

$this->assertEquals(
'value = 2',
Expand Down
Expand Up @@ -95,7 +95,7 @@ public function testToSqlNotNull()
$this->conn, 'col_name', 'string'
);
$col->setNull(true);
$this->assertEquals('col_name varchar2(255)', $col->toSql());
$this->assertEquals('col_name varchar2(255) NULL', $col->toSql());
}

public function testToSqlDefault()
Expand Down
2 changes: 1 addition & 1 deletion framework/Db/test/Horde/Db/Adapter/TestBase.php
Expand Up @@ -586,7 +586,7 @@ public function testIndexNameByMultiColumn()
{
$name = $this->_conn->indexName('sports', array('column' =>
array('name', 'is_college')));
$this->assertStringStartsWith($name, 'index_sports_on_name_and_is_college');
$this->assertEquals('index_sports_on_name_and_is_college', $name);
}

public function testIndexNameByName()
Expand Down

0 comments on commit 02ae830

Please sign in to comment.