Commit d5bb0441 authored by Marco Pivetta's avatar Marco Pivetta

Merge pull request #676 from deeky666/DBAL-831

[DBAL-831] Fix explicit case sensitive identifiers in Oracle
parents d4005861 255c396d
......@@ -374,8 +374,10 @@ class OraclePlatform extends AbstractPlatform
*/
public function getListSequencesSQL($database)
{
$database = $this->normalizeIdentifier($database);
return "SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ".
"WHERE SEQUENCE_OWNER = '".strtoupper($database)."'";
"WHERE SEQUENCE_OWNER = '" . $database->getName() . "'";
}
/**
......@@ -415,7 +417,7 @@ class OraclePlatform extends AbstractPlatform
*/
public function getListTableIndexesSQL($table, $currentDatabase = null)
{
$table = strtoupper($table);
$table = $this->normalizeIdentifier($table);
return "SELECT uind.index_name AS name, " .
" uind.index_type AS type, " .
......@@ -424,7 +426,8 @@ class OraclePlatform extends AbstractPlatform
" uind_col.column_position AS column_pos, " .
" (SELECT ucon.constraint_type FROM user_constraints ucon WHERE ucon.constraint_name = uind.index_name) AS is_primary ".
"FROM user_indexes uind, user_ind_columns uind_col " .
"WHERE uind.index_name = uind_col.index_name AND uind_col.table_name = '$table' ORDER BY uind_col.column_position ASC";
"WHERE uind.index_name = uind_col.index_name AND uind_col.table_name = '" . $table->getName() . "' " .
"ORDER BY uind_col.column_position ASC";
}
/**
......@@ -468,45 +471,49 @@ class OraclePlatform extends AbstractPlatform
*/
public function getCreateAutoincrementSql($name, $table, $start = 1)
{
$table = strtoupper($table);
$name = strtoupper($name);
$tableIdentifier = $this->normalizeIdentifier($table);
$quotedTableName = $tableIdentifier->getQuotedName($this);
$unquotedTableName = $tableIdentifier->getName();
$nameIdentifier = $this->normalizeIdentifier($name);
$quotedName = $nameIdentifier->getQuotedName($this);
$unquotedName = $nameIdentifier->getName();
$sql = array();
$sql = array();
$indexName = $table . '_AI_PK';
$autoincrementIdentifierName = $this->getAutoincrementIdentifierName($tableIdentifier);
$idx = new Index($indexName, array($name), true, true);
$idx = new Index($autoincrementIdentifierName, array($quotedName), true, true);
$sql[] = 'DECLARE
constraints_Count NUMBER;
BEGIN
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \''.$table.'\' AND CONSTRAINT_TYPE = \'P\';
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \'' . $unquotedTableName . '\' AND CONSTRAINT_TYPE = \'P\';
IF constraints_Count = 0 OR constraints_Count = \'\' THEN
EXECUTE IMMEDIATE \''.$this->getCreateConstraintSQL($idx, $table).'\';
EXECUTE IMMEDIATE \''.$this->getCreateConstraintSQL($idx, $quotedTableName).'\';
END IF;
END;';
$sequenceName = $this->getIdentitySequenceName($table, $name);
$sequenceName = $this->getIdentitySequenceName($unquotedTableName, $unquotedName);
$sequence = new Sequence($sequenceName, $start);
$sql[] = $this->getCreateSequenceSQL($sequence);
$triggerName = $table . '_AI_PK';
$sql[] = 'CREATE TRIGGER ' . $triggerName . '
$sql[] = 'CREATE TRIGGER ' . $autoincrementIdentifierName . '
BEFORE INSERT
ON ' . $table . '
ON ' . $quotedTableName . '
FOR EACH ROW
DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
IF (:NEW.' . $name . ' IS NULL OR :NEW.'.$name.' = 0) THEN
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL;
IF (:NEW.' . $quotedName . ' IS NULL OR :NEW.'.$quotedName.' = 0) THEN
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = \'' . $sequenceName . '\';
SELECT :NEW.' . $name . ' INTO last_InsertID FROM DUAL;
SELECT :NEW.' . $quotedName . ' INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
......@@ -517,22 +524,62 @@ END;';
}
/**
* @param string $table
* Returns the SQL statements to drop the autoincrement for the given table name.
*
* @param string $table The table name to drop the autoincrement for.
*
* @return array
*/
public function getDropAutoincrementSql($table)
{
$table = strtoupper($table);
$trigger = $table . '_AI_PK';
$table = $this->normalizeIdentifier($table);
$autoincrementIdentifierName = $this->getAutoincrementIdentifierName($table);
$identitySequenceName = $this->getIdentitySequenceName(
$table->isQuoted() ? $table->getQuotedName($this) : $table->getName(),
''
);
$sql[] = 'DROP TRIGGER ' . $trigger;
$sql[] = $this->getDropSequenceSQL($table.'_SEQ');
return array(
'DROP TRIGGER ' . $autoincrementIdentifierName,
$this->getDropSequenceSQL($identitySequenceName),
$this->getDropConstraintSQL($autoincrementIdentifierName, $table->getQuotedName($this)),
);
}
$indexName = $table . '_AI_PK';
$sql[] = $this->getDropConstraintSQL($indexName, $table);
/**
* Normalizes the given identifier.
*
* Uppercases the given identifier if it is not quoted by intention
* to reflect Oracle's internal auto uppercasing strategy of unquoted identifiers.
*
* @param string $name The identifier to normalize.
*
* @return Identifier The normalized identifier.
*/
private function normalizeIdentifier($name)
{
$identifier = new Identifier($name);
return $sql;
return $identifier->isQuoted() ? $identifier : new Identifier(strtoupper($name));
}
/**
* Returns the autoincrement primary key identifier name for the given table identifier.
*
* Quotes the autoincrement primary key identifier name
* if the given table name is quoted by intention.
*
* @param Identifier $table The table identifier to return the autoincrement primary key identifier name for.
*
* @return string
*/
private function getAutoincrementIdentifierName(Identifier $table)
{
$identifierName = $table->getName() . '_AI_PK';
return $table->isQuoted()
? $this->quoteSingleIdentifier($identifierName)
: $identifierName;
}
/**
......@@ -540,7 +587,7 @@ END;';
*/
public function getListTableForeignKeysSQL($table)
{
$table = strtoupper($table);
$table = $table = $this->normalizeIdentifier($table);
return "SELECT alc.constraint_name,
alc.DELETE_RULE,
......@@ -559,7 +606,7 @@ LEFT JOIN user_cons_columns r_cols
AND cols.position = r_cols.position
WHERE alc.constraint_name = cols.constraint_name
AND alc.constraint_type = 'R'
AND alc.table_name = '".$table."'
AND alc.table_name = '" . $table->getName() . "'
ORDER BY alc.constraint_name ASC, cols.position ASC";
}
......@@ -568,8 +615,9 @@ LEFT JOIN user_cons_columns r_cols
*/
public function getListTableConstraintsSQL($table)
{
$table = strtoupper($table);
return 'SELECT * FROM user_constraints WHERE table_name = \'' . $table . '\'';
$table = $this->normalizeIdentifier($table);
return "SELECT * FROM user_constraints WHERE table_name = '" . $table->getName() . "'";
}
/**
......@@ -577,22 +625,22 @@ LEFT JOIN user_cons_columns r_cols
*/
public function getListTableColumnsSQL($table, $database = null)
{
$table = strtoupper($table);
$table = $this->normalizeIdentifier($table);
$tabColumnsTableName = "user_tab_columns";
$colCommentsTableName = "user_col_comments";
$ownerCondition = '';
if (null !== $database) {
$database = strtoupper($database);
$database = $this->normalizeIdentifier($database);
$tabColumnsTableName = "all_tab_columns";
$colCommentsTableName = "all_col_comments";
$ownerCondition = "AND c.owner = '".$database."'";
$ownerCondition = "AND c.owner = '" . $database->getName() . "'";
}
return "SELECT c.*, d.comments FROM $tabColumnsTableName c ".
"INNER JOIN " . $colCommentsTableName . " d ON d.TABLE_NAME = c.TABLE_NAME AND d.COLUMN_NAME = c.COLUMN_NAME ".
"WHERE c.table_name = '" . $table . "' ".$ownerCondition." ORDER BY c.column_name";
"WHERE c.table_name = '" . $table->getName() . "' ".$ownerCondition." ORDER BY c.column_name";
}
/**
......@@ -800,7 +848,18 @@ LEFT JOIN user_cons_columns r_cols
*/
public function getIdentitySequenceName($tableName, $columnName)
{
return $tableName . '_' . $columnName . '_SEQ';
$table = new Identifier($tableName);
// No usage of column name to preserve BC compatibility with <2.5
$identitySequenceName = $table->getName() . '_SEQ';
if ($table->isQuoted()) {
$identitySequenceName = '"' . $identitySequenceName . '"';
}
$identitySequenceIdentifier = $this->normalizeIdentifier($identitySequenceName);
return $identitySequenceIdentifier->getQuotedName($this);
}
/**
......
......@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Types\Type;
/**
* Oracle Schema Manager.
*
......@@ -36,7 +38,7 @@ class OracleSchemaManager extends AbstractSchemaManager
{
$view = \array_change_key_case($view, CASE_LOWER);
return new View($view['view_name'], $view['text']);
return new View($this->getQuotedIdentifierName($view['view_name']), $view['text']);
}
/**
......@@ -58,7 +60,7 @@ class OracleSchemaManager extends AbstractSchemaManager
{
$table = \array_change_key_case($table, CASE_LOWER);
return $table['table_name'];
return $this->getQuotedIdentifierName($table['table_name']);
}
/**
......@@ -84,7 +86,7 @@ class OracleSchemaManager extends AbstractSchemaManager
$buffer['non_unique'] = ($tableIndex['is_unique'] == 0) ? true : false;
}
$buffer['key_name'] = $keyName;
$buffer['column_name'] = $tableIndex['column_name'];
$buffer['column_name'] = $this->getQuotedIdentifierName($tableIndex['column_name']);
$indexBuffer[] = $buffer;
}
......@@ -207,7 +209,7 @@ class OracleSchemaManager extends AbstractSchemaManager
'platformDetails' => array(),
);
return new Column($tableColumn['column_name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
return new Column($this->getQuotedIdentifierName($tableColumn['column_name']), Type::getType($type), $options);
}
/**
......@@ -224,22 +226,26 @@ class OracleSchemaManager extends AbstractSchemaManager
}
$list[$value['constraint_name']] = array(
'name' => $value['constraint_name'],
'name' => $this->getQuotedIdentifierName($value['constraint_name']),
'local' => array(),
'foreign' => array(),
'foreignTable' => $value['references_table'],
'onDelete' => $value['delete_rule'],
);
}
$list[$value['constraint_name']]['local'][$value['position']] = $value['local_column'];
$list[$value['constraint_name']]['foreign'][$value['position']] = $value['foreign_column'];
$localColumn = $this->getQuotedIdentifierName($value['local_column']);
$foreignColumn = $this->getQuotedIdentifierName($value['foreign_column']);
$list[$value['constraint_name']]['local'][$value['position']] = $localColumn;
$list[$value['constraint_name']]['foreign'][$value['position']] = $foreignColumn;
}
$result = array();
foreach ($list as $constraint) {
$result[] = new ForeignKeyConstraint(
array_values($constraint['local']), $constraint['foreignTable'],
array_values($constraint['foreign']), $constraint['name'],
array_values($constraint['local']), $this->getQuotedIdentifierName($constraint['foreignTable']),
array_values($constraint['foreign']), $this->getQuotedIdentifierName($constraint['name']),
array('onDelete' => $constraint['onDelete'])
);
}
......@@ -254,7 +260,11 @@ class OracleSchemaManager extends AbstractSchemaManager
{
$sequence = \array_change_key_case($sequence, CASE_LOWER);
return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['min_value']);
return new Sequence(
$this->getQuotedIdentifierName($sequence['sequence_name']),
$sequence['increment_by'],
$sequence['min_value']
);
}
/**
......@@ -323,4 +333,23 @@ class OracleSchemaManager extends AbstractSchemaManager
parent::dropTable($name);
}
/**
* Returns the quoted representation of the given identifier name.
*
* Quotes non-uppercase identifiers explicitly to preserve case
* and thus make references to the particular identifier work.
*
* @param string $identifier The identifier to quote.
*
* @return string The quoted identifier.
*/
private function getQuotedIdentifierName($identifier)
{
if (preg_match('/[a-z]/', $identifier)) {
return $this->_platform->quoteIdentifier($identifier);
}
return $identifier;
}
}
......@@ -183,7 +183,7 @@ class Table extends AbstractAsset
*/
public function dropIndex($indexName)
{
$indexName = strtolower($indexName);
$indexName = $this->normalizeIdentifier($indexName);
if ( ! $this->hasIndex($indexName)) {
throw SchemaException::indexDoesNotExist($indexName, $this->_name);
}
......@@ -222,8 +222,8 @@ class Table extends AbstractAsset
*/
public function renameIndex($oldIndexName, $newIndexName = null)
{
$oldIndexName = strtolower($oldIndexName);
$normalizedNewIndexName = strtolower($newIndexName);
$oldIndexName = $this->normalizeIdentifier($oldIndexName);
$normalizedNewIndexName = $this->normalizeIdentifier($newIndexName);
if ($oldIndexName === $normalizedNewIndexName) {
return $this;
......@@ -287,7 +287,7 @@ class Table extends AbstractAsset
*/
private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = array(), array $options = array())
{
if (preg_match('(([^a-zA-Z0-9_]+))', $indexName)) {
if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) {
throw SchemaException::indexNameInvalid($indexName);
}
......@@ -362,7 +362,7 @@ class Table extends AbstractAsset
*/
public function dropColumn($columnName)
{
$columnName = strtolower($columnName);
$columnName = $this->normalizeIdentifier($columnName);
unset($this->_columns[$columnName]);
return $this;
......@@ -469,7 +469,7 @@ class Table extends AbstractAsset
protected function _addColumn(Column $column)
{
$columnName = $column->getName();
$columnName = strtolower($columnName);
$columnName = $this->normalizeIdentifier($columnName);
if (isset($this->_columns[$columnName])) {
throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
......@@ -497,7 +497,7 @@ class Table extends AbstractAsset
}
$indexName = $indexCandidate->getName();
$indexName = strtolower($indexName);
$indexName = $this->normalizeIdentifier($indexName);
if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $indexCandidate->isPrimary())) {
throw SchemaException::indexAlreadyExists($indexName, $this->_name);
......@@ -535,7 +535,7 @@ class Table extends AbstractAsset
array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength()
);
}
$name = strtolower($name);
$name = $this->normalizeIdentifier($name);
$this->_fkConstraints[$name] = $constraint;
// add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request.
......@@ -553,7 +553,7 @@ class Table extends AbstractAsset
*/
public function hasForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
$constraintName = $this->normalizeIdentifier($constraintName);
return isset($this->_fkConstraints[$constraintName]);
}
......@@ -569,7 +569,7 @@ class Table extends AbstractAsset
*/
public function getForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
$constraintName = $this->normalizeIdentifier($constraintName);
if (!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
}
......@@ -588,7 +588,7 @@ class Table extends AbstractAsset
*/
public function removeForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
$constraintName = $this->normalizeIdentifier($constraintName);
if (!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
}
......@@ -631,7 +631,7 @@ class Table extends AbstractAsset
*/
public function hasColumn($columnName)
{
$columnName = $this->trimQuotes(strtolower($columnName));
$columnName = $this->normalizeIdentifier($columnName);
return isset($this->_columns[$columnName]);
}
......@@ -647,7 +647,7 @@ class Table extends AbstractAsset
*/
public function getColumn($columnName)
{
$columnName = strtolower($this->trimQuotes($columnName));
$columnName = $this->normalizeIdentifier($columnName);
if ( ! $this->hasColumn($columnName)) {
throw SchemaException::columnDoesNotExist($columnName, $this->_name);
}
......@@ -704,7 +704,7 @@ class Table extends AbstractAsset
*/
public function hasIndex($indexName)
{
$indexName = strtolower($indexName);
$indexName = $this->normalizeIdentifier($indexName);
return (isset($this->_indexes[$indexName]));
}
......@@ -720,7 +720,7 @@ class Table extends AbstractAsset
*/
public function getIndex($indexName)
{
$indexName = strtolower($indexName);
$indexName = $this->normalizeIdentifier($indexName);
if ( ! $this->hasIndex($indexName)) {
throw SchemaException::indexDoesNotExist($indexName, $this->_name);
}
......@@ -814,4 +814,18 @@ class Table extends AbstractAsset
$this->_fkConstraints[$k]->setLocalTable($this);
}
}
/**
* Normalizes a given identifier.
*
* Trims quotes and lowercases the given identifier.
*
* @param string $identifier The identifier to normalize.
*
* @return string The normalized identifier.
*/
private function normalizeIdentifier($identifier)
{
return $this->trimQuotes(strtolower($identifier));
}
}
......@@ -102,4 +102,115 @@ class OracleSchemaManagerTest extends SchemaManagerFunctionalTestCase
$this->assertContains('c##test_create_database', $databases);
}
/**
* @group DBAL-831
*/
public function testListTableDetailsWithDifferentIdentifierQuotingRequirements()
{
$primaryTableName = '"Primary_Table"';
$offlinePrimaryTable = new Schema\Table($primaryTableName);
$offlinePrimaryTable->addColumn(
'"Id"',
'integer',
array('autoincrement' => true, 'comment' => 'Explicit casing.')
);
$offlinePrimaryTable->addColumn('select', 'integer', array('comment' => 'Reserved keyword.'));
$offlinePrimaryTable->addColumn('foo', 'integer', array('comment' => 'Implicit uppercasing.'));
$offlinePrimaryTable->addColumn('BAR', 'integer');
$offlinePrimaryTable->addColumn('"BAZ"', 'integer');
$offlinePrimaryTable->addIndex(array('select'), 'from');
$offlinePrimaryTable->addIndex(array('foo'), 'foo_index');
$offlinePrimaryTable->addIndex(array('BAR'), 'BAR_INDEX');
$offlinePrimaryTable->addIndex(array('"BAZ"'), 'BAZ_INDEX');
$offlinePrimaryTable->setPrimaryKey(array('"Id"'));
$foreignTableName = 'foreign';
$offlineForeignTable = new Schema\Table($foreignTableName);
$offlineForeignTable->addColumn('id', 'integer', array('autoincrement' => true));
$offlineForeignTable->addColumn('"Fk"', 'integer');
$offlineForeignTable->addIndex(array('"Fk"'), '"Fk_index"');
$offlineForeignTable->addForeignKeyConstraint(
$primaryTableName,
array('"Fk"'),
array('"Id"'),
array(),
'"Primary_Table_Fk"'
);
$offlineForeignTable->setPrimaryKey(array('id'));
$this->_sm->tryMethod('dropTable', $foreignTableName);
$this->_sm->tryMethod('dropTable', $primaryTableName);
$this->_sm->createTable($offlinePrimaryTable);
$this->_sm->createTable($offlineForeignTable);
$onlinePrimaryTable = $this->_sm->listTableDetails($primaryTableName);
$onlineForeignTable = $this->_sm->listTableDetails($foreignTableName);
$platform = $this->_sm->getDatabasePlatform();
// Primary table assertions
$this->assertSame($primaryTableName, $onlinePrimaryTable->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasColumn('"Id"'));
$this->assertSame('"Id"', $onlinePrimaryTable->getColumn('"Id"')->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasPrimaryKey());
$this->assertSame(array('"Id"'), $onlinePrimaryTable->getPrimaryKey()->getQuotedColumns($platform));
$this->assertTrue($onlinePrimaryTable->hasColumn('select'));
$this->assertSame('"select"', $onlinePrimaryTable->getColumn('select')->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasColumn('foo'));
$this->assertSame('FOO', $onlinePrimaryTable->getColumn('foo')->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasColumn('BAR'));
$this->assertSame('BAR', $onlinePrimaryTable->getColumn('BAR')->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasColumn('"BAZ"'));
$this->assertSame('BAZ', $onlinePrimaryTable->getColumn('"BAZ"')->getQuotedName($platform));
$this->assertTrue($onlinePrimaryTable->hasIndex('from'));
$this->assertTrue($onlinePrimaryTable->getIndex('from')->hasColumnAtPosition('"select"'));
$this->assertSame(array('"select"'), $onlinePrimaryTable->getIndex('from')->getQuotedColumns($platform));
$this->assertTrue($onlinePrimaryTable->hasIndex('foo_index'));
$this->assertTrue($onlinePrimaryTable->getIndex('foo_index')->hasColumnAtPosition('foo'));
$this->assertSame(array('FOO'), $onlinePrimaryTable->getIndex('foo_index')->getQuotedColumns($platform));
$this->assertTrue($onlinePrimaryTable->hasIndex('BAR_INDEX'));
$this->assertTrue($onlinePrimaryTable->getIndex('BAR_INDEX')->hasColumnAtPosition('BAR'));
$this->assertSame(array('BAR'), $onlinePrimaryTable->getIndex('BAR_INDEX')->getQuotedColumns($platform));
$this->assertTrue($onlinePrimaryTable->hasIndex('BAZ_INDEX'));
$this->assertTrue($onlinePrimaryTable->getIndex('BAZ_INDEX')->hasColumnAtPosition('"BAZ"'));
$this->assertSame(array('BAZ'), $onlinePrimaryTable->getIndex('BAZ_INDEX')->getQuotedColumns($platform));
// Foreign table assertions
$this->assertTrue($onlineForeignTable->hasColumn('id'));
$this->assertSame('ID', $onlineForeignTable->getColumn('id')->getQuotedName($platform));
$this->assertTrue($onlineForeignTable->hasPrimaryKey());
$this->assertSame(array('ID'), $onlineForeignTable->getPrimaryKey()->getQuotedColumns($platform));
$this->assertTrue($onlineForeignTable->hasColumn('"Fk"'));
$this->assertSame('"Fk"', $onlineForeignTable->getColumn('"Fk"')->getQuotedName($platform));
$this->assertTrue($onlineForeignTable->hasIndex('"Fk_index"'));
$this->assertTrue($onlineForeignTable->getIndex('"Fk_index"')->hasColumnAtPosition('"Fk"'));
$this->assertSame(array('"Fk"'), $onlineForeignTable->getIndex('"Fk_index"')->getQuotedColumns($platform));
$this->assertTrue($onlineForeignTable->hasForeignKey('"Primary_Table_Fk"'));
$this->assertSame(
$primaryTableName,
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignTableName($platform)
);
$this->assertSame(
array('"Fk"'),
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedLocalColumns($platform)
);
$this->assertSame(
array('"Id"'),
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignColumns($platform)
);
}
}
......@@ -235,8 +235,8 @@ class OraclePlatformTest extends AbstractPlatformTestCase
$targets = array(
"CREATE TABLE {$tableName} ({$columnName} NUMBER(10) NOT NULL)",
"DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = '{$tableName}' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN EXECUTE IMMEDIATE 'ALTER TABLE {$tableName} ADD CONSTRAINT {$tableName}_AI_PK PRIMARY KEY ({$columnName})'; END IF; END;",
"CREATE SEQUENCE {$tableName}_{$columnName}_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1",
"CREATE TRIGGER {$tableName}_AI_PK BEFORE INSERT ON {$tableName} FOR EACH ROW DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN SELECT {$tableName}_{$columnName}_SEQ.NEXTVAL INTO :NEW.{$columnName} FROM DUAL; IF (:NEW.{$columnName} IS NULL OR :NEW.{$columnName} = 0) THEN SELECT {$tableName}_{$columnName}_SEQ.NEXTVAL INTO :NEW.{$columnName} FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = '{$tableName}_{$columnName}_SEQ'; SELECT :NEW.{$columnName} INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT {$tableName}_{$columnName}_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; END IF; END;"
"CREATE SEQUENCE {$tableName}_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1",
"CREATE TRIGGER {$tableName}_AI_PK BEFORE INSERT ON {$tableName} FOR EACH ROW DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN SELECT {$tableName}_SEQ.NEXTVAL INTO :NEW.{$columnName} FROM DUAL; IF (:NEW.{$columnName} IS NULL OR :NEW.{$columnName} = 0) THEN SELECT {$tableName}_SEQ.NEXTVAL INTO :NEW.{$columnName} FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = '{$tableName}_SEQ'; SELECT :NEW.{$columnName} INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT {$tableName}_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; END IF; END;"
);
$statements = $this->_platform->getCreateTableSQL($table);
//strip all the whitespace from the statements
......@@ -392,10 +392,14 @@ class OraclePlatformTest extends AbstractPlatformTestCase
/**
* @group DBAL-563
* @group DBAL-831
*/
public function testReturnsIdentitySequenceName()
{
$this->assertSame('mytable_mycolumn_SEQ', $this->_platform->getIdentitySequenceName('mytable', 'mycolumn'));
$this->assertSame('MYTABLE_SEQ', $this->_platform->getIdentitySequenceName('mytable', 'mycolumn'));
$this->assertSame('"mytable_SEQ"', $this->_platform->getIdentitySequenceName('"mytable"', 'mycolumn'));
$this->assertSame('MYTABLE_SEQ', $this->_platform->getIdentitySequenceName('mytable', '"mycolumn"'));
$this->assertSame('"mytable_SEQ"', $this->_platform->getIdentitySequenceName('"mytable"', '"mycolumn"'));
}
/**
......@@ -502,4 +506,43 @@ class OraclePlatformTest extends AbstractPlatformTestCase
'ALTER TABLE foo RENAME COLUMN bar TO baz',
);
}
/**
* @dataProvider getReturnsDropAutoincrementSQL
* @group DBAL-831
*/
public function testReturnsDropAutoincrementSQL($table, $expectedSql)
{
$this->assertSame($expectedSql, $this->_platform->getDropAutoincrementSql($table));
}
public function getReturnsDropAutoincrementSQL()
{
return array(
array(
'myTable',
array(
'DROP TRIGGER MYTABLE_AI_PK',
'DROP SEQUENCE MYTABLE_SEQ',
'ALTER TABLE MYTABLE DROP CONSTRAINT MYTABLE_AI_PK',
)
),
array(
'"myTable"',
array(
'DROP TRIGGER "myTable_AI_PK"',
'DROP SEQUENCE "myTable_SEQ"',
'ALTER TABLE "myTable" DROP CONSTRAINT "myTable_AI_PK"',
)
),
array(
'table',
array(
'DROP TRIGGER TABLE_AI_PK',
'DROP SEQUENCE TABLE_SEQ',
'ALTER TABLE "TABLE" DROP CONSTRAINT TABLE_AI_PK',
)
),
);
}
}
......@@ -623,4 +623,76 @@ class TableTest extends \Doctrine\Tests\DbalTestCase
$table->renameIndex('idx_id', 'idx_foo');
}
/**
* @dataProvider getNormalizesAssetNames
* @group DBAL-831
*/
public function testNormalizesColumnNames($assetName)
{
$table = new Table('test');
$table->addColumn($assetName, 'integer');
$table->addIndex(array($assetName), $assetName);
$table->addForeignKeyConstraint('test', array($assetName), array($assetName), array(), $assetName);
$this->assertTrue($table->hasColumn($assetName));
$this->assertTrue($table->hasColumn('foo'));
$this->assertInstanceOf('Doctrine\DBAL\Schema\Column', $table->getColumn($assetName));
$this->assertInstanceOf('Doctrine\DBAL\Schema\Column', $table->getColumn('foo'));
$this->assertTrue($table->hasIndex($assetName));
$this->assertTrue($table->hasIndex('foo'));
$this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getIndex($assetName));
$this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getIndex('foo'));
$this->assertTrue($table->hasForeignKey($assetName));
$this->assertTrue($table->hasForeignKey('foo'));
$this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $table->getForeignKey($assetName));
$this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $table->getForeignKey('foo'));
$table->renameIndex($assetName, $assetName);
$this->assertTrue($table->hasIndex($assetName));
$this->assertTrue($table->hasIndex('foo'));
$table->renameIndex($assetName, 'foo');
$this->assertTrue($table->hasIndex($assetName));
$this->assertTrue($table->hasIndex('foo'));
$table->renameIndex('foo', $assetName);
$this->assertTrue($table->hasIndex($assetName));
$this->assertTrue($table->hasIndex('foo'));
$table->renameIndex($assetName, 'bar');
$this->assertFalse($table->hasIndex($assetName));
$this->assertFalse($table->hasIndex('foo'));
$this->assertTrue($table->hasIndex('bar'));
$table->renameIndex('bar', $assetName);
$table->dropColumn($assetName);
$table->dropIndex($assetName);
$table->removeForeignKey($assetName);
$this->assertFalse($table->hasColumn($assetName));
$this->assertFalse($table->hasColumn('foo'));
$this->assertFalse($table->hasIndex($assetName));
$this->assertFalse($table->hasIndex('foo'));
$this->assertFalse($table->hasForeignKey($assetName));
$this->assertFalse($table->hasForeignKey('foo'));
}
public function getNormalizesAssetNames()
{
return array(
array('foo'),
array('FOO'),
array('`foo`'),
array('`FOO`'),
array('"foo"'),
array('"FOO"'),
array('"foo"'),
array('"FOO"'),
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment