Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Dbal 831 #707

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 94 additions & 35 deletions lib/Doctrine/DBAL/Platforms/OraclePlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,10 @@ public function getListDatabasesSQL()
*/
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() . "'";
}

/**
Expand Down Expand Up @@ -415,7 +417,7 @@ protected function _getCreateTableSQL($table, array $columns, array $options = a
*/
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, " .
Expand All @@ -424,7 +426,8 @@ public function getListTableIndexesSQL($table, $currentDatabase = null)
" 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";
}

/**
Expand Down Expand Up @@ -468,45 +471,49 @@ public function getDropViewSQL($name)
*/
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;
Expand All @@ -517,30 +524,70 @@ public function getCreateAutoincrementSql($name, $table, $start = 1)
}

/**
* @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;
}

/**
* {@inheritDoc}
*/
public function getListTableForeignKeysSQL($table)
{
$table = strtoupper($table);
$table = $table = $this->normalizeIdentifier($table);

return "SELECT alc.constraint_name,
alc.DELETE_RULE,
Expand All @@ -559,7 +606,7 @@ public function getListTableForeignKeysSQL($table)
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";
}

Expand All @@ -568,31 +615,32 @@ public function getListTableForeignKeysSQL($table)
*/
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() . "'";
}

/**
* {@inheritDoc}
*/
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";
}

/**
Expand Down Expand Up @@ -800,7 +848,18 @@ public function usesSequenceEmulatedIdentityColumns()
*/
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);
}

/**
Expand Down
49 changes: 39 additions & 10 deletions lib/Doctrine/DBAL/Schema/OracleSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Types\Type;

/**
* Oracle Schema Manager.
*
Expand All @@ -36,7 +38,7 @@ protected function _getPortableViewDefinition($view)
{
$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']);
}

/**
Expand All @@ -58,7 +60,7 @@ protected function _getPortableTableDefinition($table)
{
$table = \array_change_key_case($table, CASE_LOWER);

return $table['table_name'];
return $this->getQuotedIdentifierName($table['table_name']);
}

/**
Expand All @@ -84,7 +86,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
$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;
}

Expand Down Expand Up @@ -207,7 +209,7 @@ protected function _getPortableTableColumnDefinition($tableColumn)
'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);
}

/**
Expand All @@ -224,22 +226,26 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys)
}

$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'])
);
}
Expand All @@ -254,7 +260,11 @@ protected function _getPortableSequenceDefinition($sequence)
{
$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']
);
}

/**
Expand Down Expand Up @@ -323,4 +333,23 @@ public function dropTable($name)

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;
}
}
Loading