Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix #DBAL-615 - ALTER with reserved keywords #379

Closed
wants to merge 1 commit into from

8 participants

@Thinkscape

PR #302 introduced platform quoting for manipulation of PK, FK and indexes. Alter queries are left unquoted, which means that ALTER with table names that happen to be reserved platform keywords, will fail.
For example:

ALTER TABLE order DROP FOREIGN KEY FK_F5299398D5289B7F;
ALTER TABLE set DROP FOREIGN KEY FK_E61425DC1BF22D93;
ALTER TABLE storage ADD CONSTRAINT FK_547A1B3487068541 FOREIGN KEY (`addressId`) REFERENCES `address` (`id`);

http://www.doctrine-project.org/jira/browse/DBAL-615

After merging changes from this PR, the above together with MySQL platform becomes :

ALTER TABLE `order` DROP FOREIGN KEY FK_F5299398D5289B7F;
ALTER TABLE `set` DROP FOREIGN KEY FK_E61425DC1BF22D93;
ALTER TABLE `storage` ADD CONSTRAINT FK_547A1B3487068541 FOREIGN KEY (`addressId`) REFERENCES `address` (`id`);
@doctrinebot
Collaborator

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DBAL-616

We use Jira to track the state of pull requests and the versions they got
included in.

@beberlei
Owner

We don't auto quote in Platforms. You need to put the quoted data in there yourself. Quoting introduces case-sensitivity issues, which is why we don't do this by default.

@beberlei beberlei closed this
@Thinkscape

@beberlei The problem is with quoting identifiers not data.

And for identifiers, your statement is not true - we do a lot of quoting and quote-trimming

ALTER table produced by schema tool currently ignores QuoteStrategy, while other statements (like adding/dropping indexes) do quote identifiers.

Unless you meant something else... please elaborate.

@Thinkscape

btw: I've given a thought about case-sensitivity - that's why we have (bool)Schema\Table::$_quoted (defined in AbstractAsset) and that's why 2.3 introduced QuoteStrategyInterface to handle this (Platforms already provide identifier quoting facilities).

SchemaTool already uses QuoteStrategies extensively ... however ALTER queries end up having unquoted names regardless of the Strategy (because it's just string concat).

@Thinkscape

I've got a good example to back it up.

Here's what schema-tool:update generated for me:

ALTER TABLE order ADD `datePickup` DATETIME DEFAULT NULL;
ALTER TABLE set DROP FOREIGN KEY FK_E61425DC2E74F1A4;
ALTER TABLE set ADD CONSTRAINT FK_E61425DCF8BF42CD FOREIGN KEY (`orderId`) 
    REFERENCES `order` (`id`) ON DELETE CASCADE;
ALTER TABLE set ADD CONSTRAINT FK_E61425DC2E74F1A4 FOREIGN KEY (`storageId`) 
    REFERENCES `storage` (`id`) ON DELETE SET NULL;

Notice the inconsistencies here - see how referenced columns and tables are quoted automatically (i.e. storage), while the main tables' names are not.

@yellow1912

I can also report the exact same issue, Doctrine is ignoring my quotes around the order table when doing alter.

@Ocramius
Owner

@Thinkscape that's an inconsistency we had for a long time... quoting should be opt-in in DBAL as well

@Thinkscape

@Ocramius hmm.. I get it...

... but why doesn't quoting strategies work as they're supposed to? The moment I've enabled a "quote-all" strategy, all hell broke loose! Schema tool was basically broken, couldn't even compare annotations with db schemas, the whole ORM went berserk and I had dozens of other bugs throughout the code. I've also noticed, that there's tons of quote-unquote-quote with hard-coded stuff like:

 $identifier = trim($identifier, "'`");

I've noticed that ORM keeps quoting and then un-quoting identifiers, depending on what it needs to do at any particular moment. Because of that, if you have a "quote all" strategy, schema comparisons stop working. Apparently it's because, quoting strategies are not used consistently (sometimes they are, sometimes it's a trim like above and sometimes it's manually sniffing for (bool)$field->quoted and such :\ )

@Thinkscape

Simplest reproduce scenario:

  • Download EagerQuoteStrategy.php
  • Use it as quoting strategy
  • Create a schema with tables set (as in set of elements) and order (because we're simulating an e-commerce system)
  • Run schema tool - try to do update, or comparison or something
@stof

@Thinkscape I would advice you to avoid using reserved keyword as table names (remember that table names don't need to be the same than the entity short class name).

@Ocramius
Owner

Yeah, reserved keywords = PITA.

As far as it concerns quoting strategies, if we can ALL the quoting opt-in in DBAL then the code in ORM should also be simplified by a lot, and we'd get rid of all these problems as well...

@Thinkscape

@stof I know that. There are also other usage patterns, such as matching container/table names with your model names, which is what's being used in this example. Quoting is a mechanism for properly forming SQL queries regardless of particular platform namespace.

Other example could be something like ITEMS - it might not be a reserved keyword, but in MySQL 6 or newest Oracledb it might become a reserved keyword.

The point is - ORM and/or DBAL should produce platform-neutral queries and not be picky about anything.

As far as it concerns quoting strategies, if we can ALL the quoting opt-in in DBAL then the code in ORM should also be simplified by a lot, and we'd get rid of all these problems as well...

Exactly - as in the example above. Quoting is the best way to ensure that current and future SQL queries will work, regardless of platform and its version. The same applies to quoting data in php, html, json, xml and other formats and meta-formats. If you create any form of abstraction, better to quote it all in the most secure and safe way possible.

@stof

@Thinkscape the issue is that quoting all identifiers is a way to reduce the platform interoperability of queries, because the behavior of quoted identifiers is a huge mess accross platforms: http://www.alberton.info/dbms_identifiers_and_case_sensitivity.html#.UI_knoYY3YI
This is why the default behavior of the ORM is to avoid the quoting

@Thinkscape

Some examples of edge cases with keywords: The word user is reserved in PostgreSQL among others, authorization, preorder, diagnostics are reserved in TS-SQL, client, names, comparisons are reserved in db2 etc.

(The list changes with each version)

@Thinkscape

This is why the default behavior of the ORM is to avoid the quoting

Hmm.. fair argument. However I could point out the "using mixed-case in table names is PITA" argument. If all your tables were lowercased, there's no problem.

@Thinkscape

Except for case (in)sensitivity, is there any other argument for not-quoting identifiers ?

@Ocramius
Owner

@Thinkscape usually not, but we've been bitten back by it every.single.time we tried to quote stuff by default.

@stof

@Thinkscape the issue is that we cannot expect all our users to use lowercased identifiers (if it were the case, we would not have faced so much issues when trying to quote identifiers by default).
The issue with the using mixed-case in table names is PITA argument, is that these people can give the using reserved keywords in table names is PITA argument in response, and we cannot make everyone happy for this.
As mixed cased table names are working in Doctrine currently, changing to the other camp needs to wait until Doctrine 3.0 for BC reasons

@Thinkscape

we cannot make everyone happy for this.

I do agree, but current behavior with implicit quoting "some" identifiers, silent quoting in some queries, while throwing SQL errors in other gave me, and possibly others, a lot of headache... not mentioning hours spent in debugger going line after line in ORM and DBAL.

It's not true that "not quoting" is saving us work. The "not quoting" behavior of doctrine 2.* actually means tens of lines of code more, to make it work!

As mixed cased table names are working in Doctrine currently,

Meh... that's not entirely true.

I.e. for MySQL, it only works if you've got case-insensitive filesystem etc. (as per the article you've mentioned). It's basically relying on a feature-bug, or inconsistency in some DBMS that give silent success with miss-spelled identifier names...

In case you've developed your app on a Mac (with case-insensitive system by default) and then deployed on Linux server (with Ext* which is case-sensitive) you are going to hit a wall. Doctrine is not going to help with that nor should it.

changing to the other camp needs to wait until Doctrine 3.0 for BC reasons

yeah :-(

Both practices are PITA... I've noticed doctrine 2 team has done bigger changes in the past (i.e. I've just notice onUpdate removal among other stuff).

I believe that it's not ORM or DBAL's job to work around bad practices and use feature-bugs. ORM should blindly obey definitions, safely quote values and identifiers, leave "magic" to DBMS. If a user happens to have case-insensitive MySQL 5 running on M$ Windows and uses mixedCapsTableNames without any consistency in userland code --- that is his/her problem.

Marco also mentioned the fact, that removing a lot of this magic quoting and keyword dodging could slim-down the library and enhance performance, which is always good :+1:

btw: what's current status on 3.0 ?

@Thinkscape

btw: we can still make the behavior opt-in (configurable) by using something like quoting strategies.... so if someone really really wants to use case insensitivity (or the other way around) he/she should be able to use different strategy. That would mean cleaning up ORM and DBAL to use quoting strategies properly and consistently.

@justin-schroeder

@Thinkscape I realize this is an old discussion, but I wanted to thank you for plugging for a more robust quote strategy for doctrine. In my view its a huge limitation of ORM, and almost reason enough to ditch it for something else. In an age where semantics are (or should be) king, and performance is the new commodity, having to structure your database tables to avoid a litany of reserved words reeks of old-world smell.

Have you succeeded in getting your EagerQuoteStrategy to work with the schema tools?

@Thinkscape

@justin-schroeder Yes, it worked for most operations although it wasn't perfect. I've spend about 10h alone fixing schema-tool (and related classes) which were main offenders and were duplicating quoting mechanics. It goes a bit deeper and there's bits and pieces throughout the whole thing that are inconsistent with each other.

Basically what happened is: classes that were actually with the quoting bug (and someone decided that particular functionality deserves to be fixed) were monkey patched by manually injecting a hard-coded quote char or something like that. Then there were other classes that would then receive the quoted stuff, so they were "unquoting" - yes, they were actually trim()-ing previously concatenated identifier.

@rjmunro
  1. Always quoting in all major databases is absolutely consistent.
    • It is always case sensitive.
    • MySQL has a bug when run on case insensitive filesystems, where it uses table names as filenames on disc and therefore treats them case insensitively
  2. Not quoting behaves differently in different engines and causes issues with reserved words.
    • Some engines upper case the table names
    • Some lower case the table names

I can see how sometimes when you are quickly writing an sql query in a mysql terminal, you might leave out the quotes to save typing, particularly if you have a keyboard layout where the backticks are hard to reach, but if you are writing any kind of code to talk to a database, particularly a library, missing out the quotes is surely a terrible idea.

The only problem is going to be handling the transition. Maybe something that checks the case of tables in the database after an SQL error and retries.

@stof

@rjmunro please read the blog post I linked in #379 (comment)

@Thinkscape

@stof the article mentioned there actually proves my points above - not quoting only masks the problem when someone develops an application with mysql on a case-insensitive filesystem and then tries to install it on case-sensitive filesystem.

If you're trying to sell the idea that "not quoting is good because it's more portable", that is basically promoting ambiguity and a "bug-feature" of mysql. Each and every modern RDBS (including sqlite) has identifier quoting implemented and ORM should not be opinionated on any naming style, convention, language or character set (some RDBS allow unicode identifiers such as khoai tây).

ATM unfortunately doctrine 2.* is opinionated, forces this or misbehaves otherwise, which was the primary focus of this PR.

@Ocramius
Owner

Note that mysql is really not the biggest issue here. IIRC, pgsql reports identifiers with different (inconsistent) casing in different parts of its API.

That's why we didn't get around quoting by default in first place.

@Thinkscape

@Ocramius assuming this is true, can't this be worked around by fetching identifiers from a single (consistent) part of the API ?

There's a lot counter-examples too - as a typical exercise I always recommend configuring D2 with DB2 and trying to use Entity\Name with table names which, surprise surprise, is reserved on this platform ...

@Ocramius
Owner

@Ocramius assuming this is true, can't this be worked around by fetching identifiers from a single (consistent) part of the API ?

there is none - describe table does what it wants :-)

As for corner-cases, we actually thought about simply creating a no-op quoting strategy that just throws exceptions in case of reserved keywords.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
4 lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php
@@ -396,7 +396,7 @@ public function getAlterTableSQL(TableDiff $diff)
$queryParts = array();
if ($diff->newName !== false) {
- $queryParts[] = 'RENAME TO ' . $diff->newName;
+ $queryParts[] = 'RENAME TO ' . $this->quoteSingleIdentifier($diff->newName);
}
foreach ($diff->addedColumns as $column) {
@@ -446,7 +446,7 @@ public function getAlterTableSQL(TableDiff $diff)
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if (count($queryParts) > 0) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . implode(", ", $queryParts);
}
$sql = array_merge(
$this->getPreAlterTableIndexForeignKeySQL($diff),
View
4 lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
@@ -527,7 +527,7 @@ public function getAlterTableSQL(TableDiff $diff)
$columnSql = array();
$queryParts = array();
if ($diff->newName !== false) {
- $queryParts[] = 'RENAME TO ' . $diff->newName;
+ $queryParts[] = 'RENAME TO ' . $this->quoteSingleIdentifier($diff->newName);
}
foreach ($diff->addedColumns as $column) {
@@ -577,7 +577,7 @@ public function getAlterTableSQL(TableDiff $diff)
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if (count($queryParts) > 0) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . implode(", ", $queryParts);
}
$sql = array_merge(
$this->getPreAlterTableIndexForeignKeySQL($diff),
View
15 lib/Doctrine/DBAL/Platforms/OraclePlatform.php
@@ -613,7 +613,8 @@ public function getAlterTableSQL(TableDiff $diff)
}
if (count($fields)) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ADD (' . implode(', ', $fields) . ')';
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' ADD (' . implode(', ', $fields) . ')';
}
$fields = array();
@@ -648,7 +649,8 @@ public function getAlterTableSQL(TableDiff $diff)
}
if (count($fields)) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' MODIFY (' . implode(', ', $fields) . ')';
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' MODIFY (' . implode(', ', $fields) . ')';
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
@@ -656,7 +658,8 @@ public function getAlterTableSQL(TableDiff $diff)
continue;
}
- $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getQuotedName($this);
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getQuotedName($this);
}
$fields = array();
@@ -669,14 +672,16 @@ public function getAlterTableSQL(TableDiff $diff)
}
if (count($fields)) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' DROP (' . implode(', ', $fields).')';
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' DROP (' . implode(', ', $fields).')';
}
$tableSql = array();
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if ($diff->newName !== false) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' RENAME TO ' . $this->quoteSingleIdentifier($diff->newName);
}
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
View
21 lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php
@@ -413,7 +413,7 @@ public function getAlterTableSQL(TableDiff $diff)
}
$query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
if ($comment = $this->getColumnComment($column)) {
$commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
}
@@ -425,7 +425,7 @@ public function getAlterTableSQL(TableDiff $diff)
}
$query = 'DROP ' . $column->getQuotedName($this);
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
foreach ($diff->changedColumns as $columnDiff) {
@@ -442,17 +442,17 @@ public function getAlterTableSQL(TableDiff $diff)
// here was a server version check before, but DBAL API does not support this anymore.
$query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSqlDeclaration($column->toArray(), $this);
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
if ($columnDiff->hasChanged('default')) {
$query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray());
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
if ($columnDiff->hasChanged('notnull')) {
$query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL';
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
if ($columnDiff->hasChanged('autoincrement')) {
@@ -463,11 +463,11 @@ public function getAlterTableSQL(TableDiff $diff)
$sql[] = "CREATE SEQUENCE " . $seqName;
$sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->name . "))";
$query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')";
- $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
+ $sql[] = "ALTER TABLE " . $this->quoteSingleIdentifier($diff->name) . " " . $query;
} else {
// Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have
$query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT";
- $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
+ $sql[] = "ALTER TABLE " . $this->quoteSingleIdentifier($diff->name) . " " . $query;
}
}
@@ -481,7 +481,7 @@ public function getAlterTableSQL(TableDiff $diff)
if ($columnDiff->hasChanged('length')) {
$query = 'ALTER ' . $column->getName() . ' TYPE ' . $column->getType()->getSqlDeclaration($column->toArray(), $this);
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
}
@@ -490,14 +490,15 @@ public function getAlterTableSQL(TableDiff $diff)
continue;
}
- $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this);
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) .
+ ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this);
}
$tableSql = array();
if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
if ($diff->newName !== false) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' RENAME TO ' . $diff->newName;
}
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
View
2  lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
@@ -467,7 +467,7 @@ public function getAlterTableSQL(TableDiff $diff)
}
foreach ($queryParts as $query) {
- $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
+ $sql[] = 'ALTER TABLE ' . $this->quoteSingleIdentifier($diff->name) . ' ' . $query;
}
$sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff));
View
29 tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php
@@ -220,6 +220,9 @@ public function getGenerateConstraintForeignKeySql(ForeignKeyConstraint $fk)
abstract public function getGenerateAlterTableSql();
+ /**
+ * @group DBAL-374
+ */
public function testGeneratesTableAlterationSql()
{
$expectedSql = $this->getGenerateAlterTableSql();
@@ -370,6 +373,7 @@ public function testCreateTableColumnComments()
/**
* @group DBAL-42
+ * @group DBAL-374
*/
public function testAlterTableColumnComments()
{
@@ -443,6 +447,7 @@ public function testQuotedColumnInPrimaryKeyPropagation()
abstract protected function getQuotedColumnInPrimaryKeySQL();
abstract protected function getQuotedColumnInIndexSQL();
abstract protected function getQuotedColumnInForeignKeySQL();
+ abstract protected function getQuotedIdentifiersInAlterSQL();
/**
* @group DBAL-374
@@ -496,6 +501,30 @@ public function testQuotedColumnInForeignKeyPropagation()
}
/**
+ * @group DBAL-615
+ */
+ public function testQuotedIdentifiersInAlterQueries()
+ {
+ $table1 = new Table('`quoted`');
+ $table1->addColumn('create', 'string');
+
+ $table2 = new Table('`quoted`');
+ $table2->addColumn('order', 'string');
+
+ $diff = new TableDiff('quoted');
+ $diff->removedColumns = array(
+ $table1->getColumn('create')
+ );
+ $diff->addedColumns = array(
+ $table2->getColumn('order')
+ );
+ $diff->fromTable = $table1;
+
+ $sql = $this->_platform->getAlterTableSQL($diff);
+ $this->assertEquals($this->getQuotedIdentifiersInAlterSQL(), $sql);
+ }
+
+ /**
* @expectedException \Doctrine\DBAL\DBALException
*/
public function testGetCreateSchemaSQL()
View
11 tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php
@@ -47,7 +47,7 @@ public function getGenerateTableWithMultiColumnUniqueIndexSql()
public function getGenerateAlterTableSql()
{
return array(
- "ALTER TABLE mytable RENAME TO userlist, ADD quota INT DEFAULT NULL, DROP foo, CHANGE bar baz VARCHAR(255) DEFAULT 'def' NOT NULL, CHANGE bloo bloo TINYINT(1) DEFAULT '0' NOT NULL"
+ "ALTER TABLE `mytable` RENAME TO `userlist`, ADD quota INT DEFAULT NULL, DROP foo, CHANGE bar baz VARCHAR(255) DEFAULT 'def' NOT NULL, CHANGE bloo bloo TINYINT(1) DEFAULT '0' NOT NULL"
);
}
@@ -209,7 +209,7 @@ public function getCreateTableColumnCommentsSQL()
public function getAlterTableColumnCommentsSQL()
{
- return array("ALTER TABLE mytable ADD quota INT NOT NULL COMMENT 'A comment', CHANGE foo foo VARCHAR(255) NOT NULL, CHANGE bar baz VARCHAR(255) NOT NULL COMMENT 'B comment'");
+ return array("ALTER TABLE `mytable` ADD quota INT NOT NULL COMMENT 'A comment', CHANGE foo foo VARCHAR(255) NOT NULL, CHANGE bar baz VARCHAR(255) NOT NULL COMMENT 'B comment'");
}
public function getCreateTableColumnTypeCommentsSQL()
@@ -248,6 +248,13 @@ protected function getQuotedColumnInIndexSQL()
);
}
+ protected function getQuotedIdentifiersInAlterSQL()
+ {
+ return array(
+ 'ALTER TABLE `quoted` ADD `order` VARCHAR(255) NOT NULL, DROP `create`'
+ );
+ }
+
protected function getQuotedColumnInForeignKeySQL()
{
return array(
View
20 tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php
@@ -75,10 +75,10 @@ public function getGenerateTableWithMultiColumnUniqueIndexSql()
public function getGenerateAlterTableSql()
{
return array(
- 'ALTER TABLE mytable ADD (quota NUMBER(10) DEFAULT NULL)',
- "ALTER TABLE mytable MODIFY (baz VARCHAR2(255) DEFAULT 'def' NOT NULL, bloo NUMBER(1) DEFAULT '0' NOT NULL)",
- "ALTER TABLE mytable DROP (foo)",
- "ALTER TABLE mytable RENAME TO userlist",
+ 'ALTER TABLE "mytable" ADD (quota NUMBER(10) DEFAULT NULL)',
+ "ALTER TABLE \"mytable\" MODIFY (baz VARCHAR2(255) DEFAULT 'def' NOT NULL, bloo NUMBER(1) DEFAULT '0' NOT NULL)",
+ 'ALTER TABLE "mytable" DROP (foo)',
+ 'ALTER TABLE "mytable" RENAME TO "userlist"',
);
}
@@ -267,7 +267,7 @@ public function getCreateTableColumnTypeCommentsSQL()
public function getAlterTableColumnCommentsSQL()
{
return array(
- "ALTER TABLE mytable ADD (quota NUMBER(10) NOT NULL)",
+ 'ALTER TABLE "mytable" ADD (quota NUMBER(10) NOT NULL)',
"COMMENT ON COLUMN mytable.quota IS 'A comment'",
"COMMENT ON COLUMN mytable.foo IS ''",
"COMMENT ON COLUMN mytable.baz IS 'B comment'",
@@ -291,6 +291,14 @@ protected function getQuotedColumnInPrimaryKeySQL()
return array('CREATE TABLE "quoted" ("create" VARCHAR2(255) NOT NULL, PRIMARY KEY("create"))');
}
+ protected function getQuotedIdentifiersInAlterSQL()
+ {
+ return array(
+ 'ALTER TABLE "quoted" ADD ("order" VARCHAR2(255) NOT NULL)',
+ 'ALTER TABLE "quoted" DROP ("create")'
+ );
+ }
+
protected function getQuotedColumnInIndexSQL()
{
return array(
@@ -326,7 +334,7 @@ public function testAlterTableNotNULL()
);
$expectedSql = array(
- "ALTER TABLE mytable MODIFY (foo VARCHAR2(255) DEFAULT 'bla', baz VARCHAR2(255) DEFAULT 'bla' NOT NULL)",
+ "ALTER TABLE \"mytable\" MODIFY (foo VARCHAR2(255) DEFAULT 'bla', baz VARCHAR2(255) DEFAULT 'bla' NOT NULL)",
);
$this->assertEquals($expectedSql, $this->_platform->getAlterTableSQL($tableDiff));
}
View
28 tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php
@@ -28,15 +28,15 @@ public function getGenerateTableWithMultiColumnUniqueIndexSql()
public function getGenerateAlterTableSql()
{
return array(
- 'ALTER TABLE mytable ADD quota INT DEFAULT NULL',
- 'ALTER TABLE mytable DROP foo',
- 'ALTER TABLE mytable ALTER bar TYPE VARCHAR(255)',
- "ALTER TABLE mytable ALTER bar SET DEFAULT 'def'",
- 'ALTER TABLE mytable ALTER bar SET NOT NULL',
- 'ALTER TABLE mytable ALTER bloo TYPE BOOLEAN',
- "ALTER TABLE mytable ALTER bloo SET DEFAULT 'false'",
- 'ALTER TABLE mytable ALTER bloo SET NOT NULL',
- 'ALTER TABLE mytable RENAME TO userlist',
+ 'ALTER TABLE "mytable" ADD quota INT DEFAULT NULL',
+ 'ALTER TABLE "mytable" DROP foo',
+ 'ALTER TABLE "mytable" ALTER bar TYPE VARCHAR(255)',
+ "ALTER TABLE \"mytable\" ALTER bar SET DEFAULT 'def'",
+ 'ALTER TABLE "mytable" ALTER bar SET NOT NULL',
+ 'ALTER TABLE "mytable" ALTER bloo TYPE BOOLEAN',
+ "ALTER TABLE \"mytable\" ALTER bloo SET DEFAULT 'false'",
+ 'ALTER TABLE "mytable" ALTER bloo SET NOT NULL',
+ 'ALTER TABLE "mytable" RENAME TO userlist',
);
}
@@ -252,7 +252,7 @@ public function getCreateTableColumnCommentsSQL()
public function getAlterTableColumnCommentsSQL()
{
return array(
- "ALTER TABLE mytable ADD quota INT NOT NULL",
+ 'ALTER TABLE "mytable" ADD quota INT NOT NULL',
"COMMENT ON COLUMN mytable.quota IS 'A comment'",
"COMMENT ON COLUMN mytable.foo IS NULL",
"COMMENT ON COLUMN mytable.baz IS 'B comment'",
@@ -292,6 +292,14 @@ protected function getQuotedColumnInForeignKeySQL()
);
}
+ protected function getQuotedIdentifiersInAlterSQL()
+ {
+ return array(
+ 'ALTER TABLE "quoted" ADD "order" VARCHAR(255) NOT NULL',
+ 'ALTER TABLE "quoted" DROP "create"'
+ );
+ }
+
/**
* @group DBAL-457
*/
View
19 tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php
@@ -28,11 +28,11 @@ public function getGenerateTableWithMultiColumnUniqueIndexSql()
public function getGenerateAlterTableSql()
{
return array(
- 'ALTER TABLE mytable ADD quota INT',
- 'ALTER TABLE mytable DROP COLUMN foo',
- 'ALTER TABLE mytable ALTER COLUMN baz NVARCHAR(255) NOT NULL',
- "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_78240498 DEFAULT 'def' FOR baz",
- 'ALTER TABLE mytable ALTER COLUMN bloo BIT NOT NULL',
+ 'ALTER TABLE [mytable] ADD quota INT',
+ 'ALTER TABLE [mytable] DROP COLUMN foo',
+ 'ALTER TABLE [mytable] ALTER COLUMN baz NVARCHAR(255) NOT NULL',
+ "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_78240498 DEFAULT 'def' FOR baz",
+ 'ALTER TABLE [mytable] ALTER COLUMN bloo BIT NOT NULL',
"sp_RENAME 'mytable', 'userlist'",
"DECLARE @sql NVARCHAR(MAX) = N''; " .
"SELECT @sql += N'EXEC sp_rename N''' + dc.name + ''', N''' " .
@@ -317,4 +317,13 @@ protected function getQuotedColumnInForeignKeySQL()
'ALTER TABLE [quoted] ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ([create], foo, [bar]) REFERENCES [foo-bar] ([create], bar, [foo-bar])',
);
}
+
+ protected function getQuotedIdentifiersInAlterSQL()
+ {
+ return array(
+ 'ALTER TABLE [quoted] ADD [order] NVARCHAR(255) NOT NULL',
+ 'ALTER TABLE [quoted] DROP COLUMN [create]'
+ );
+ }
+
}
View
12 tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php
@@ -302,4 +302,16 @@ protected function getQuotedColumnInForeignKeySQL()
'CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE)',
);
}
+
+ protected function getQuotedIdentifiersInAlterSQL()
+ {
+ return array(
+ 'CREATE TEMPORARY TABLE __temp__quoted AS SELECT "create" FROM "quoted"',
+ 'DROP TABLE "quoted"',
+ 'CREATE TABLE quoted ("create" VARCHAR(255) NOT NULL, "order" VARCHAR(255) NOT NULL)',
+ 'INSERT INTO quoted ("create") SELECT "create" FROM __temp__quoted',
+ 'DROP TABLE __temp__quoted'
+ );
+ }
+
}
Something went wrong with that request. Please try again.