Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added support for column collation #245

Merged
merged 3 commits into from

11 participants

Martin Hasoň doctrinebot Guilherme Blanco Benjamin Eberlei Christian Morgan Marco Pivetta Anne-Julia Scheuermann Christophe Coevoet Fred Steve Müller Till!
Martin Hasoň

No description provided.

doctrinebot
Collaborator

Hello,

thank you for positing this Pull Request. I have automatically opened an issue on our Jira Bug Tracker for you with the details of this Pull-Request. See the Link:

http://doctrine-project.org/jira/browse/DBAL-409

lib/Doctrine/DBAL/Schema/Column.php
@@ -303,6 +312,11 @@ public function getDefault()
return $this->_default;
}
+ public function getCollation()
Marco Pivetta Owner
Ocramius added a note

Missing comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
@@ -234,6 +236,21 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns)
}
}
+ // inspect column collation
+ $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
+ $createSql = isset($createSql[0]['sql']) ? $createSql[0]['sql'] : '';
+ foreach ($list as $columnName => $column) {
Marco Pivetta Owner
Ocramius added a note

Missing newline before foreach

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...sts/DBAL/Functional/Schema/MySqlSchemaManagerTest.php
((5 lines not shown))
+
+ protected function getColumnCollation()
Marco Pivetta Owner
Ocramius added a note

Missing comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...Functional/Schema/SchemaManagerFunctionalTestCase.php
@@ -652,4 +670,9 @@ public function testListForeignKeysComposite()
$this->assertEquals(array('id', 'foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns()));
$this->assertEquals(array('id', 'other_id'), array_map('strtolower', $fkeys[0]->getForeignColumns()));
}
+
+ protected function getColumnCollation()
Marco Pivetta Owner
Ocramius added a note

This method name should start with test

Martin Hasoň
hason added a note

No. This method returns data or marks test as skipped.

Marco Pivetta Owner
Ocramius added a note

Aha, thought it was a test

Christophe Coevoet
stof added a note

then please add some phpdoc to explain it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php
((5 lines not shown))
+}
Marco Pivetta Owner
Ocramius added a note

Restore newline

Martin Hasoň
hason added a note

Doesn't respect PSR?

Marco Pivetta Owner
Ocramius added a note

Ah, my bad :) Confused with the inverse

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php
@@ -117,6 +117,15 @@ public function getDateSubMonthExpression($date, $months)
/**
* {@inheritDoc}
+ * @todo Add support for PostgreSql >= 9.1
Guilherme Blanco Owner

Merge is gonna happen when this is done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Column.php
@@ -103,14 +108,7 @@ class Column extends AbstractAsset
*
* @param string $columnName
* @param \Doctrine\DBAL\Types\Type $type
- * @param int $length
- * @param bool $notNull
- * @param mixed $default
- * @param bool $unsigned
- * @param bool $fixed
- * @param int $precision
- * @param int $scale
- * @param array $platformOptions
+ * @param array $options
*/
public function __construct($columnName, Type $type, array $options=array())
Guilherme Blanco Owner

Missing spaces around =.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Column.php
@@ -103,14 +108,7 @@ class Column extends AbstractAsset
*
* @param string $columnName
Guilherme Blanco Owner

Docblock comments should be aligned

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Column.php
@@ -231,6 +229,17 @@ public function setDefault($default)
/**
*
+ * @param string $collation
+ * @return Column
+ */
+ public function setCollation($collation)
+ {
+ $this->_collation = $collation;
+ return $this;
Guilherme Blanco Owner

Missing break line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Column.php
@@ -231,6 +229,17 @@ public function setDefault($default)
/**
*
Guilherme Blanco Owner

Please add documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Column.php
@@ -231,6 +229,17 @@ public function setDefault($default)
/**
*
+ * @param string $collation
+ * @return Column
Guilherme Blanco Owner

Line break between param and return

Guilherme Blanco Owner

Also, please provide FQCN for Column

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Guilherme Blanco

Patch seems good.
Still missing remaining drivers to deal with collation.
Patch could be merged once they're done.

Benjamin Eberlei
Owner

Please dont add a new method getCollation()/setcollation() but use the options instead. Collatoin is sometihng database specific.

Martin Hasoň

@beberlei, @adrienbrault Yours opinion?

.../Event/Listeners/PostgreSqlColumnCollationSupport.php
@@ -0,0 +1,54 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Christophe Coevoet
stof added a note

Wrong indentation of the license header

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
.../DBAL/Events/PostgreSqlColumnCollationSupportTest.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Doctrine\Tests\DBAL\Events;
+
+use Doctrine\Tests\DbalTestCase;
+use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
+use Doctrine\DBAL\Event\Listeners\PostgreSqlColumnCollationSupport;
+use Doctrine\DBAL\Event\ConnectionEventArgs;
+use Doctrine\DBAL\Events;
+
+require_once __DIR__ . '/../../TestInit.php';
Christophe Coevoet
stof added a note

This line is not needed as it is the PHPUnit bootstrap script

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Martin Hasoň

ping

Christian Morgan

Any chance this is going to make it into 2.4?

Marco Pivetta
Owner

@caponica hardly - we're in RC: only bugfixes I suppose...

Christian Morgan

Wasn't sure where we're at with 2.4. What more needs to be done to this one to make it ready for acceptance?

(i.e. if I can help just let me know how!)

Anne-Julia Scheuermann

Is there a state on this PR when it is going to be released?

Christian Morgan

Not that I've heard of, but lets hope it's soon!

.../Event/Listeners/PostgreSqlColumnCollationSupport.php
((26 lines not shown))
+/**
+ * PostgreSql Event Subscriber which detects support for column collation.
+ *
+ * @since 2.4
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ */
+class PostgreSqlColumnCollationSupport implements EventSubscriber
+{
+ /**
+ * @param ConnectionEventArgs $args
+ * @return void
+ */
+ public function postConnect(ConnectionEventArgs $args)
+ {
+ $connection = $args->getConnection();
+ $result = $connection->exec('SELECT VERSION()');
Guilherme Blanco Owner

Align = signs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
.../Event/Listeners/PostgreSqlColumnCollationSupport.php
((27 lines not shown))
+ * PostgreSql Event Subscriber which detects support for column collation.
+ *
+ * @since 2.4
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ */
+class PostgreSqlColumnCollationSupport implements EventSubscriber
+{
+ /**
+ * @param ConnectionEventArgs $args
+ * @return void
+ */
+ public function postConnect(ConnectionEventArgs $args)
+ {
+ $connection = $args->getConnection();
+ $result = $connection->exec('SELECT VERSION()');
+ if (preg_match('([\d.]+)', $result, $match)) {
Guilherme Blanco Owner

Missing line break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
.../Event/Listeners/PostgreSqlColumnCollationSupport.php
((28 lines not shown))
+ *
+ * @since 2.4
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ */
+class PostgreSqlColumnCollationSupport implements EventSubscriber
+{
+ /**
+ * @param ConnectionEventArgs $args
+ * @return void
+ */
+ public function postConnect(ConnectionEventArgs $args)
+ {
+ $connection = $args->getConnection();
+ $result = $connection->exec('SELECT VERSION()');
+ if (preg_match('([\d.]+)', $result, $match)) {
+ $args->getDatabasePlatform()->setColumnCollationSupport((bool) version_compare($match[0], '9.1', '>='));
Guilherme Blanco Owner

I really don't know if we should either have separate platforms for each version (like we have for SQL Server) or if we just do this check.
@doctrine/team-doctrine2 what's you opinion guys?

Steve Müller Collaborator

I like the idea of separating different versions into different platforms when behaviour changes. This is cleaner IMO as for example selecting the current version via SQL and then switching behaviour in the methods. Also this is easier to maintain and keeps clean code. Although I don't know if this would cause BC breaks...

Martin Hasoň
hason added a note

What name should I choose? PostgreSql91Patform or PostgreSQL91Platform or anything else?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
@@ -290,6 +290,8 @@ public function getBooleanTypeDeclarationSQL(array $field)
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
+ * @deprecated Deprecated since version 2.4, Use {@link self::getColumnCollationDeclarationSQL()} instead.
Guilherme Blanco Owner

2.5 now... =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php
@@ -34,6 +34,12 @@
class PostgreSqlPlatform extends AbstractPlatform
{
/**
+ * PostgreSQL introduces support for column collation in 9.1.
Guilherme Blanco Owner

Inline:

/**
 * @var boolean PostgreSQL introduces support for column collation in 9.1. 
 */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((10 lines not shown))
- if ($column1->getNotnull() != $column2->getNotnull()) {
- $changedProperties[] = 'notnull';
- }
-
- if ($column1->getDefault() != $column2->getDefault()) {
- $changedProperties[] = 'default';
- }
-
- if ($column1->getUnsigned() != $column2->getUnsigned()) {
- $changedProperties[] = 'unsigned';
+ $changedProperties = array();
+ foreach (array('type', 'notnull', 'default', 'unsigned', 'autoincrement') as $property) {
Guilherme Blanco Owner

Missing line break between assignment and loop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((10 lines not shown))
- if ($column1->getNotnull() != $column2->getNotnull()) {
- $changedProperties[] = 'notnull';
- }
-
- if ($column1->getDefault() != $column2->getDefault()) {
- $changedProperties[] = 'default';
- }
-
- if ($column1->getUnsigned() != $column2->getUnsigned()) {
- $changedProperties[] = 'unsigned';
+ $changedProperties = array();
+ foreach (array('type', 'notnull', 'default', 'unsigned', 'autoincrement') as $property) {
+ if ($properties1[$property] != $properties2[$property]) {
Guilherme Blanco Owner

!==

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Guilherme Blanco guilhermeblanco commented on the diff
lib/Doctrine/DBAL/Schema/Comparator.php
((35 lines not shown))
if ($length1 != $length2) {
$changedProperties[] = 'length';
}
- if ($column1->getFixed() != $column2->getFixed()) {
+ if ($properties1['fixed'] != $properties2['fixed']) {
Guilherme Blanco Owner

!==

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((41 lines not shown))
$changedProperties[] = 'fixed';
}
- }
-
- if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
- if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
+ } elseif ($properties1['type'] instanceof \Doctrine\DBAL\Types\DecimalType) {
+ if (($properties1['precision'] ?: 10) != ($properties2['precision'] ?: 10)) {
Guilherme Blanco Owner

!==

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((26 lines not shown))
}
- if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
+ if ($properties1['type'] instanceof \Doctrine\DBAL\Types\StringType) {
Guilherme Blanco Owner

Shouldn't we add the Type namespace at the top of the file and just use Type\StringType here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Guilherme Blanco guilhermeblanco commented on the diff
lib/Doctrine/DBAL/Schema/Comparator.php
((49 lines not shown))
$changedProperties[] = 'precision';
}
- if ($column1->getScale() != $column2->getScale()) {
+ if ($properties1['scale'] != $properties2['scale']) {
Guilherme Blanco Owner

!==

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Guilherme Blanco guilhermeblanco commented on the diff
lib/Doctrine/DBAL/Schema/Comparator.php
((61 lines not shown))
// only allow to delete comment if its set to '' not to null.
- if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) {
+ if ($properties1['comment'] !== null && $properties1['comment'] != $properties2['comment']) {
Guilherme Blanco Owner

!== on second check

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Christian Morgan

Isn't it easier just to edit the files than post so many comments? :)

Guilherme Blanco guilhermeblanco commented on the diff
lib/Doctrine/DBAL/Schema/Comparator.php
((73 lines not shown))
- foreach ($commonKeys as $key) {
- if ($options1[$key] !== $options2[$key]) {
+ foreach (array_merge(array_keys($customOptions1), array_keys($customOptions2)) as $key) {
+ if ( ! array_key_exists($key, $properties1) || ! array_key_exists($key, $properties2)) {
Guilherme Blanco Owner

That seems ugly/slow. array_key_exists should be replaced with isset IMHO.

Martin Hasoň
hason added a note

I can not replace it because null can be a valid value.

Guilherme Blanco Owner

Of course you can! =)

if ( ! (isset($properties1[$key]) || array_key_exists($key, $porperties1)) || ! (isset($properties2[$key]) || array_key_exists($key, $properties2))) {
Christophe Coevoet
stof added a note

@guilhermeblanco The difference between isset and array_key_exists is only significant when you have XDebug enabled AFAIK (because XDebug slows down function call but isset() is not a function call)

Guilherme Blanco Owner

@stof it is, as I've discussed a lot with Ilia during last year's Confoo (and resulted in his post: http://ilia.ws/archives/247-Performance-Analysis-of-isset-vs-array_key_exists.html )
Most of the time, you're running schema updates in development, with xdebug enabled... so... =)

Benjamin Eberlei Owner

This is completly irrelevant because it is used in development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
((8 lines not shown))
$column = new Column($tableColumn['name'], Type::getType($type), $options);
- $column->setPlatformOptions($platformOptions);
+
+ if (isset($tableColumn['collation']) && $tableColumn['collation'] != 'NULL') {
Guilherme Blanco Owner

!==

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
@@ -234,6 +237,17 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns)
}
}
+ // inspect column collation
+ $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
+ $createSql = isset($createSql[0]['sql']) ? $createSql[0]['sql'] : '';
+
+ foreach ($list as $columnName => $column) {
+ $type = $column->getType();
+ if ($type instanceof \Doctrine\DBAL\Types\StringType || $type instanceof \Doctrine\DBAL\Types\TextType) {
Guilherme Blanco Owner

Missing line break.
I also would extend the suggestion made earlier to use the Types and just consume Types\StringType et al. here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Guilherme Blanco

@caponica indeed if I wouldn't be just reviewing the PR.

Guilherme Blanco

@hason can you please rebase with master?

Christophe Coevoet

Isn't it easier just to edit the files than post so many comments? :)

No, because it would require having write access to the fork of @hason (or creating a new PR each time one of us is reviewing the PR whihc would be a huge mess)

Fred

Hello all,

How to set the collation with the @Column annotation then ..? (i need fo eg. : utf8_bin)
Thanks

Martin Hasoň

@FredoVelcro @Column(options = {collation = "utf8_bin"})

Fred

@hason got this error

/**
     * @var string
     * @ORM\Column(type="string", length = 100, options = {collation = "utf8_bin"})
     */
    protected $name;

[Doctrine\Common\Annotations\AnnotationException]
[Semantical Error] Couldn't find constant collation, property MyBundle\Entity\MyEntity::$name.

Martin Hasoň

@FredoVelcro Try to use quotes:

    /**
     * @var string
     * @ORM\Column(type="string", length=100, options={"collation"="utf8_bin"})
     */
    protected $name;
Fred

@hason done, but does not update the field when updating the schema... ( i sue Symfony2.4 with "doctrine/orm": "~2.2,>=2.2.3")

Guilherme Blanco

@FredoVelcro that will always happen since options is driver specific and cannot be properly controlled by Doctrine schema comparator.

Fred

ah...so how to update the schema ..??

Guilherme Blanco

@FredoVelcro unfortunately, this would always have to be by hand.
You can use a data migration script for that. =)

Fred

too bad..

Martin Hasoň

@guilhermeblanco, @FredoVelcro If you use my branch, so it works as you expect:

composer.json:

{
    "require": {
        "doctrine/orm": "~2.2,>=2.2.3",
        "doctrine/dbal": "dev-column_collation as 2.4"
    },

    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/hason/dbal"
        }
    ]
}

cli-config.php:

<?php
require __DIR__.'/vendor/autoload.php';

use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;

$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__.'/src'), true);

$conn = array(
    'driver' => 'pdo_mysql',
    'user' => 'root',
    '̈́password' => '',
    'dbname' => 'orm_test',
);

$entityManager = EntityManager::create($conn, $config);

return ConsoleRunner::createHelperSet($entityManager);

src/Product.php:

<?php
/**
 * @Entity @Table(name="products")
 **/
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;

    /** @Column(type="string", options={"collation"="utf8_general_ci"}) **/
    protected $name;
}

$ vendor/bin/doctrine vendor/bin/doctrine orm:schema-tool:update --dump-sql
ALTER TABLE products CHANGE name name VARCHAR(255) NOT NULL COLLATE utf8_general_ci;
Fred

oh yeah man cool ! :) thks a lot :)
will your branch be merged into the master repo (as i use Symfony2 encapsulation) ?

Martin Hasoň

@guilhermeblanco @beberlei rebased with master, ping

Benjamin Eberlei
Owner

@deeky666 ping

lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php
@@ -76,7 +76,7 @@ private function _constructPdoDsn(array $params)
*/
public function getDatabasePlatform()
{
- return new \Doctrine\DBAL\Platforms\PostgreSqlPlatform();
+ return new \Doctrine\DBAL\Platforms\PostgreSql91Platform();
Benjamin Eberlei Owner

This is a BC Break, please change back to the old platform. Developers need to select the platform themselves.

Martin Hasoň
hason added a note

Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Benjamin Eberlei beberlei commented on the diff
lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
@@ -236,6 +241,18 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns)
}
}
+ // inspect column collation
+ $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
Benjamin Eberlei Owner

Is it really necessary to execute another query here?

Martin Hasoň
hason added a note

Yes. SQLite does not have a function to obtain a column collation. I have to parse a sql query to create a table.

Benjamin Eberlei Owner

That i undrestand, but cant you get this SQL from the previous query already?

Martin Hasoň
hason added a note

Where is the previous query? I do not know where to find it.

Steve Müller Collaborator

I think what @beberlei means is that you should select it as an additional column in SqlitePlatform::getListTableColumnsSQL() to avoid having to query here again.

Martin Hasoň
hason added a note

How do I combine SELECT and PRAGMA into one query?

Steve Müller Collaborator

Hm. Didn't know Sqlite uses PRAGMA command for this :(. Don't think there is a way to combine these statements then. So we could either leave it the way it is now or switch to completely parse table details from the SELECT statement. Don't know really...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php
@@ -51,7 +51,7 @@ public function testToArray()
'unsigned' => true,
'autoincrement' => false,
'columnDefinition' => null,
- 'comment' => null,
+ 'comment' => '',
Benjamin Eberlei Owner

Why?

Martin Hasoň
hason added a note

Because '' !== null (null is a platform specific value for empty comment '') and the comparator generates unnecessary differences and thus also redundant sql.

Steve Müller Collaborator

IMO we should evaluate it to null when retrieving from the database

Martin Hasoň
hason added a note

The database retrieves an empty string '', not null. See api doc for AbstractSchemaManager::removeDoctrineTypeFromComment.

Steve Müller Collaborator

Yes but you can check for an empty string after AbstractSchemaManager::removeDoctrineTypeFromComment and evaluate to null. IMO we should leave the Column::getComment() API to allow null values. Otherwise it is inconsistent. See how you pass the comment to the Column instance in MySQLSchemaManager for example. If the column comment is not set you pass null so subsequent calls to Column::getComment() still return null although the API says it only returns string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steve Müller deeky666 commented on the diff
lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
@@ -2244,7 +2244,7 @@ public function getColumnCharsetDeclarationSQL($charset)
*/
public function getColumnCollationDeclarationSQL($collation)
{
- return '';
+ return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
Steve Müller Collaborator

This is inconsistent to other driver specific features like sequences, create database, create schema etc. where all relevant methods throw a DBALException. Do we want to break this here?

Martin Hasoň
hason added a note

Your suggestion is a BC break.

Steve Müller Collaborator

Ah yes haven't seen that it is used in favour of a deprecated method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steve Müller
Collaborator

What about Oracle support?

Martin Hasoň

@deeky666 I have no experience with Oracle

Steve Müller
Collaborator

@hason Forget about it, Oracle doesn't support column collations. I was confused by the documentation which actually showed the MySQL docs.

Steve Müller
Collaborator

@hason I think you have to rebase again, the PR cannot be merged anymore.

Till!

What's the status of this PR?

lib/Doctrine/DBAL/Schema/Comparator.php
((19 lines not shown))
- if ($column1->getUnsigned() != $column2->getUnsigned()) {
- $changedProperties[] = 'unsigned';
+ foreach (array('type', 'notnull', 'default', 'unsigned', 'autoincrement') as $property) {
+ if ($properties1[$property] !== $properties2[$property]) {
Steve Müller Collaborator

The strict comparison here changes the behaviour of the comparator. I don't know what side effects this creates. I would leave the loose comparison here. One example: You create a column with default value 0 (integer). Afterwards you reverse engineer the column from database and eventually it returns 0 as string. Then using strict comparison will generate unecessary changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((35 lines not shown))
if ($length1 != $length2) {
$changedProperties[] = 'length';
}
- if ($column1->getFixed() != $column2->getFixed()) {
+ if ($properties1['fixed'] !== $properties2['fixed']) {
Steve Müller Collaborator

Loose comparison IMO. See above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((41 lines not shown))
$changedProperties[] = 'fixed';
}
- }
-
- if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
- if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
+ } elseif ($properties1['type'] instanceof Types\DecimalType) {
+ if (($properties1['precision'] ?: 10) !== ($properties2['precision'] ?: 10)) {
Steve Müller Collaborator

Loose comparison IMO. See above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((49 lines not shown))
$changedProperties[] = 'precision';
}
- if ($column1->getScale() != $column2->getScale()) {
+ if ($properties1['scale'] !== $properties2['scale']) {
Steve Müller Collaborator

Loose comparison IMO. See above. And newline before if block please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/DBAL/Schema/Comparator.php
((61 lines not shown))
// only allow to delete comment if its set to '' not to null.
- if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) {
+ if ($properties1['comment'] !== null && $properties1['comment'] !== $properties2['comment']) {
Steve Müller Collaborator

Loose comparison IMO. See above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Steve Müller
Collaborator

@kimhemsoe I guess Drizzle also supports column collations. Can you maybe investigate and add support for it? This would make the support complete over all platforms.

Christian Morgan

@deeky666 Isn't it better to get this released with support for some platforms then add others later as enhancements? I know it's tantalising to be close to complete support, but I don't think it's a requirement.

Steve Müller deeky666 referenced this pull request in hason/dbal
Merged

Add column collation support for Drizzle #1

Steve Müller
Collaborator

@caponica Don't worry. I have done a PR hason#1 in @hason DBAL repo to add support for this :)

Martin Hasoň

@beberlei @deeky666 Updated and rebased. Any chance to merge?

...rine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php
((10 lines not shown))
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\DBAL\Platforms\Keywords;
+
+/**
+ * PostgreSQL 9.1 reserved keywords list.
+ *
+ * @author Martin HasOoň <martin.hason@gmail.com>
Steve Müller Collaborator
deeky666 added a note

There something wrong here with your name ;) Awesome work on the keywords btw. You read my thoughts :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...rine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php
((32 lines not shown))
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'PostgreSQL91';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @link http://www.postgresql.org/docs/9.1/static/sql-keywords-appendix.html
+ */
+ protected function getKeywords()
+ {
+ return array_merge(
+ array_diff(parent::getKeywords(), array(
Steve Müller Collaborator
deeky666 added a note

Can you tell me which versions you compared 9.1 to? It seems we have never defined what version the base PostgreSqlPlatform is related to so it's rather tricky to make a diff here. Maybe I would go and take the approach I did for PostgreSQL92Keywords before your rebase and just list all of them to be safe.

Steve Müller Collaborator
deeky666 added a note

Also can you please add the kewords class to DBAL/Tools/Console/Command/ReservedWordsCommand?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Martin Hasoň

@beberlei @guilhermeblanco @Ocramius The oldest PR begs you to merge :)

Guilherme Blanco guilhermeblanco merged commit 5b8f4f0 into from
Martin Hasoň hason deleted the branch
Till!

Late to this, just wanted to say thanks for getting this in!

Marco Pivetta Ocramius referenced this pull request in zf-fr/zfr-oauth2-server
Merged

Allow case-sensitive check for token #4

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.
Showing with 649 additions and 188 deletions.
  1. +1 −0  docs/en/reference/platforms.rst
  2. +11 −1 lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
  3. +119 −1 lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php
  4. +148 −0 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php
  5. +3 −101 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL92Keywords.php
  6. +15 −6 lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
  7. +65 −0 lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php
  8. +1 −1  lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php
  9. +10 −10 lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
  10. +8 −0 lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
  11. +35 −43 lib/Doctrine/DBAL/Schema/Comparator.php
  12. +9 −2 lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php
  13. +10 −2 lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php
  14. +9 −1 lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php
  15. +4 −5 lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
  16. +30 −0 lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
  17. +1 −0  lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php
  18. +21 −1 tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php
  19. +19 −0 tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php
  20. +9 −9 tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php
  21. +20 −5 tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php
  22. +21 −0 tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php
  23. +34 −0 tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php
  24. +46 −0 tests/Doctrine/Tests/DBAL/Schema/SqliteSchemaManagerTest.php
1  docs/en/reference/platforms.rst
View
@@ -53,6 +53,7 @@ PostgreSQL
^^^^^^^^^^
- ``PostgreSqlPlatform`` for all versions.
+- ``PostgreSQL91Platform`` for version 9.1 and above.
- ``PostgreSQL92Platform`` for version 9.2 and above.
SAP Sybase SQL Anywhere
12 lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
View
@@ -2317,7 +2317,7 @@ public function getColumnCharsetDeclarationSQL($charset)
*/
public function getColumnCollationDeclarationSQL($collation)
{
- return '';
+ return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : '';
Steve Müller Collaborator

This is inconsistent to other driver specific features like sequences, create database, create schema etc. where all relevant methods throw a DBALException. Do we want to break this here?

Martin Hasoň
hason added a note

Your suggestion is a BC break.

Steve Müller Collaborator

Ah yes haven't seen that it is used in favour of a deprecated method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
/**
@@ -2949,6 +2949,16 @@ public function supportsViews()
}
/**
+ * Does this platform support column collation?
+ *
+ * @return boolean
+ */
+ public function supportsColumnCollation()
+ {
+ return false;
+ }
+
+ /**
* Gets the format string, as accepted by the date() function, that describes
* the format of a stored datetime value of this platform.
*
120 lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php
View
@@ -231,6 +231,116 @@ public function getDropDatabaseSQL($name)
/**
* {@inheritDoc}
*/
+ protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
+ {
+ $queryFields = $this->getColumnDeclarationListSQL($columns);
+
+ if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
+ foreach ($options['uniqueConstraints'] as $index => $definition) {
+ $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition);
+ }
+ }
+
+ // add all indexes
+ if (isset($options['indexes']) && ! empty($options['indexes'])) {
+ foreach($options['indexes'] as $index => $definition) {
+ $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
+ }
+ }
+
+ // attach all primary keys
+ if (isset($options['primary']) && ! empty($options['primary'])) {
+ $keyColumns = array_unique(array_values($options['primary']));
+ $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
+ }
+
+ $query = 'CREATE ';
+
+ if (!empty($options['temporary'])) {
+ $query .= 'TEMPORARY ';
+ }
+
+ $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') ';
+ $query .= $this->buildTableOptions($options);
+ $query .= $this->buildPartitionOptions($options);
+
+ $sql[] = $query;
+
+ if (isset($options['foreignKeys'])) {
+ foreach ((array) $options['foreignKeys'] as $definition) {
+ $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
+ }
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Build SQL for table options
+ *
+ * @param array $options
+ *
+ * @return string
+ */
+ private function buildTableOptions(array $options)
+ {
+ if (isset($options['table_options'])) {
+ return $options['table_options'];
+ }
+
+ $tableOptions = array();
+
+ // Collate
+ if ( ! isset($options['collate'])) {
+ $options['collate'] = 'utf8_unicode_ci';
+ }
+
+ $tableOptions[] = sprintf('COLLATE %s', $options['collate']);
+
+ // Engine
+ if ( ! isset($options['engine'])) {
+ $options['engine'] = 'InnoDB';
+ }
+
+ $tableOptions[] = sprintf('ENGINE = %s', $options['engine']);
+
+ // Auto increment
+ if (isset($options['auto_increment'])) {
+ $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']);
+ }
+
+ // Comment
+ if (isset($options['comment'])) {
+ $comment = trim($options['comment'], " '");
+
+ $tableOptions[] = sprintf("COMMENT = '%s' ", str_replace("'", "''", $comment));
+ }
+
+ // Row format
+ if (isset($options['row_format'])) {
+ $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']);
+ }
+
+ return implode(' ', $tableOptions);
+ }
+
+ /**
+ * Build SQL for partition options.
+ *
+ * @param array $options
+ *
+ * @return string
+ */
+ private function buildPartitionOptions(array $options)
+ {
+ return (isset($options['partition_options']))
+ ? ' ' . $options['partition_options']
+ : '';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public function getListDatabasesSQL()
{
return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'";
@@ -264,7 +374,7 @@ public function getListTableColumnsSQL($table, $database = null)
}
return "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT," .
- " NUMERIC_PRECISION, NUMERIC_SCALE" .
+ " NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME" .
" FROM DATA_DICTIONARY.COLUMNS" .
" WHERE TABLE_SCHEMA=" . $database . " AND TABLE_NAME = '" . $table . "'";
}
@@ -334,6 +444,14 @@ public function supportsViews()
}
/**
+ * {@inheritdoc}
+ */
+ public function supportsColumnCollation()
+ {
+ return true;
+ }
+
+ /**
* {@inheritDoc}
*/
public function getDropIndexSQL($index, $table=null)
148 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php
View
@@ -0,0 +1,148 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\DBAL\Platforms\Keywords;
+
+/**
+ * PostgreSQL 9.1 reserved keywords list.
+ *
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ * @author Steve Müller <st.mueller@dzh-online.de>
+ * @link www.doctrine-project.org
+ * @since 2.5
+ */
+class PostgreSQL91Keywords extends PostgreSQLKeywords
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'PostgreSQL91';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @link http://www.postgresql.org/docs/9.1/static/sql-keywords-appendix.html
+ */
+ protected function getKeywords()
+ {
+ return array(
+ 'ALL',
+ 'ANALYSE',
+ 'ANALYZE',
+ 'AND',
+ 'ANY',
+ 'ARRAY',
+ 'AS',
+ 'ASC',
+ 'ASYMMETRIC',
+ 'AUTHORIZATION',
+ 'BINARY',
+ 'BOTH',
+ 'CASE',
+ 'CAST',
+ 'CHECK',
+ 'COLLATE',
+ 'COLUMN',
+ 'CONCURRENTLY',
+ 'CONSTRAINT',
+ 'CREATE',
+ 'CROSS',
+ 'CURRENT_CATALOG',
+ 'CURRENT_DATE',
+ 'CURRENT_ROLE',
+ 'CURRENT_SCHEMA',
+ 'CURRENT_TIME',
+ 'CURRENT_TIMESTAMP',
+ 'CURRENT_USER',
+ 'DEFAULT',
+ 'DEFERRABLE',
+ 'DESC',
+ 'DISTINCT',
+ 'DO',
+ 'ELSE',
+ 'END',
+ 'EXCEPT',
+ 'FALSE',
+ 'FETCH',
+ 'FOR',
+ 'FOREIGN',
+ 'FREEZE',
+ 'FROM',
+ 'FULL',
+ 'GRANT',
+ 'GROUP',
+ 'HAVING',
+ 'ILIKE',
+ 'IN',
+ 'INITIALLY',
+ 'INNER',
+ 'INTERSECT',
+ 'INTO',
+ 'IS',
+ 'ISNULL',
+ 'JOIN',
+ 'LEADING',
+ 'LEFT',
+ 'LIKE',
+ 'LIMIT',
+ 'LOCALTIME',
+ 'LOCALTIMESTAMP',
+ 'NATURAL',
+ 'NOT',
+ 'NOTNULL',
+ 'NULL',
+ 'OFFSET',
+ 'ON',
+ 'ONLY',
+ 'OR',
+ 'ORDER',
+ 'OUTER',
+ 'OVER',
+ 'OVERLAPS',
+ 'PLACING',
+ 'PRIMARY',
+ 'REFERENCES',
+ 'RETURNING',
+ 'RIGHT',
+ 'SELECT',
+ 'SESSION_USER',
+ 'SIMILAR',
+ 'SOME',
+ 'SYMMETRIC',
+ 'TABLE',
+ 'THEN',
+ 'TO',
+ 'TRAILING',
+ 'TRUE',
+ 'UNION',
+ 'UNIQUE',
+ 'USER',
+ 'USING',
+ 'VARIADIC',
+ 'VERBOSE',
+ 'WHEN',
+ 'WHERE',
+ 'WINDOW',
+ 'WITH',
+ );
+ }
+}
104 lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL92Keywords.php
View
@@ -26,7 +26,7 @@
* @link www.doctrine-project.org
* @since 2.5
*/
-class PostgreSQL92Keywords extends PostgreSQLKeywords
+class PostgreSQL92Keywords extends PostgreSQL91Keywords
{
/**
* {@inheritdoc}
@@ -43,106 +43,8 @@ public function getName()
*/
protected function getKeywords()
{
- return array(
- 'ALL',
- 'ANALYSE',
- 'ANALYZE',
- 'AND',
- 'ANY',
- 'ARRAY',
- 'AS',
- 'ASC',
- 'ASYMMETRIC',
- 'AUTHORIZATION',
- 'BINARY',
- 'BOTH',
- 'CASE',
- 'CAST',
- 'CHECK',
- 'COLLATE',
+ return array_merge(parent::getKeywords(), array(
'COLLATION',
- 'COLUMN',
- 'CONCURRENTLY',
- 'CONSTRAINT',
- 'CREATE',
- 'CROSS',
- 'CURRENT_CATALOG',
- 'CURRENT_DATE',
- 'CURRENT_ROLE',
- 'CURRENT_SCHEMA',
- 'CURRENT_TIME',
- 'CURRENT_TIMESTAMP',
- 'CURRENT_USER',
- 'DEFAULT',
- 'DEFERRABLE',
- 'DESC',
- 'DISTINCT',
- 'DO',
- 'ELSE',
- 'END',
- 'EXCEPT',
- 'FALSE',
- 'FETCH',
- 'FOR',
- 'FOREIGN',
- 'FREEZE',
- 'FROM',
- 'FULL',
- 'GRANT',
- 'GROUP',
- 'HAVING',
- 'ILIKE',
- 'IN',
- 'INITIALLY',
- 'INNER',
- 'INTERSECT',
- 'INTO',
- 'IS',
- 'ISNULL',
- 'JOIN',
- 'LEADING',
- 'LEFT',
- 'LIKE',
- 'LIMIT',
- 'LOCALTIME',
- 'LOCALTIMESTAMP',
- 'NATURAL',
- 'NOT',
- 'NOTNULL',
- 'NULL',
- 'OFFSET',
- 'ON',
- 'ONLY',
- 'OR',
- 'ORDER',
- 'OUTER',
- 'OVER',
- 'OVERLAPS',
- 'PLACING',
- 'PRIMARY',
- 'REFERENCES',
- 'RETURNING',
- 'RIGHT',
- 'SELECT',
- 'SESSION_USER',
- 'SIMILAR',
- 'SOME',
- 'SYMMETRIC',
- 'TABLE',
- 'THEN',
- 'TO',
- 'TRAILING',
- 'TRUE',
- 'UNION',
- 'UNIQUE',
- 'USER',
- 'USING',
- 'VARIADIC',
- 'VERBOSE',
- 'WHEN',
- 'WHERE',
- 'WINDOW',
- 'WITH',
- );
+ ));
}
}
21 lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
View
@@ -334,6 +334,8 @@ public function getBooleanTypeDeclarationSQL(array $field)
* Obtain DBMS specific SQL code portion needed to set the COLLATION
* of a field declaration to be used in statements like CREATE TABLE.
*
+ * @deprecated Deprecated since version 2.5, Use {@link self::getColumnCollationDeclarationSQL()} instead.
+ *
* @param string $collation name of the collation
*
* @return string DBMS specific SQL code portion needed to set the COLLATION
@@ -341,7 +343,7 @@ public function getBooleanTypeDeclarationSQL(array $field)
*/
public function getCollationFieldDeclaration($collation)
{
- return 'COLLATE ' . $collation;
+ return $this->getColumnCollationDeclarationSQL($collation);
}
/**
@@ -376,6 +378,11 @@ public function supportsInlineColumnComments()
/**
* {@inheritDoc}
*/
+ public function supportsColumnCollation()
+ {
+ return true;
+ }
+
public function getListTablesSQL()
{
return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'";
@@ -387,13 +394,15 @@ public function getListTablesSQL()
public function getListTableColumnsSQL($table, $database = null)
{
if ($database) {
- return "SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ".
- "COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, " .
- "CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS CollationName ".
- "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $database . "' AND TABLE_NAME = '" . $table . "'";
+ $database = "'" . $database . "'";
+ } else {
+ $database = 'DATABASE()';
}
- return 'DESCRIBE ' . $table;
+ return "SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ".
+ "COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, " .
+ "CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS Collation ".
+ "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = " . $database . " AND TABLE_NAME = '" . $table . "'";
}
/**
65 lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php
View
@@ -0,0 +1,65 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\DBAL\Platforms;
+
+/**
+ * Provides the behavior, features and SQL dialect of the PostgreSQL 9.1 database platform.
+ *
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ * @link www.doctrine-project.org
+ * @since 2.5
+ */
+class PostgreSQL91Platform extends PostgreSqlPlatform
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function supportsColumnCollation()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getReservedKeywordsClass()
+ {
+ return 'Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getColumnCollationDeclarationSQL($collation)
+ {
+ return 'COLLATE ' . $this->quoteSingleIdentifier($collation);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getListTableColumnsSQL($table, $database = null)
+ {
+ $sql = parent::getListTableColumnsSQL($table, $database);
+ $parts = explode('AS complete_type,', $sql, 2);
+
+ return $parts[0].'AS complete_type, (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,'.$parts[1];
+ }
+}
2  lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php
View
@@ -26,7 +26,7 @@
* @link www.doctrine-project.org
* @since 2.5
*/
-class PostgreSQL92Platform extends PostgreSqlPlatform
+class PostgreSQL92Platform extends PostgreSQL91Platform
{
/**
* {@inheritdoc}
20 lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
View
@@ -142,6 +142,14 @@ public function getDefaultSchemaName()
/**
* {@inheritDoc}
*/
+ public function supportsColumnCollation()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public function hasNativeGuidType()
{
return true;
@@ -1440,14 +1448,6 @@ public function getDefaultValueDeclarationSQL($field)
/**
* {@inheritdoc}
- */
- public function getColumnCollationDeclarationSQL($collation)
- {
- return 'COLLATE ' . $collation;
- }
-
- /**
- * {@inheritdoc}
*
* Modifies column declaration order as it differs in Microsoft SQL Server.
*/
@@ -1456,8 +1456,8 @@ public function getColumnDeclarationSQL($name, array $field)
if (isset($field['columnDefinition'])) {
$columnDef = $this->getCustomTypeDeclarationSQL($field);
} else {
- $collation = (isset($field['collate']) && $field['collate']) ?
- ' ' . $this->getColumnCollationDeclarationSQL($field['collate']) : '';
+ $collation = (isset($field['collation']) && $field['collation']) ?
+ ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : '';
$notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
8 lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
View
@@ -481,6 +481,14 @@ public function supportsIdentityColumns()
/**
* {@inheritDoc}
*/
+ public function supportsColumnCollation()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public function getName()
{
return 'sqlite';
78 lib/Doctrine/DBAL/Schema/Comparator.php
View
@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
+use Doctrine\DBAL\Types;
+
/**
* Compares two Schemas and return an instance of SchemaDiff.
*
@@ -365,82 +367,72 @@ public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint
*/
public function diffColumn(Column $column1, Column $column2)
{
+ $properties1 = $column1->toArray();
+ $properties2 = $column2->toArray();
+
$changedProperties = array();
- if ($column1->getType() != $column2->getType()) {
- $changedProperties[] = 'type';
- }
- if ($column1->getNotnull() != $column2->getNotnull()) {
- $changedProperties[] = 'notnull';
+ foreach (array('type', 'notnull', 'unsigned', 'autoincrement') as $property) {
+ if ($properties1[$property] != $properties2[$property]) {
+ $changedProperties[] = $property;
+ }
}
-
- $column1Default = $column1->getDefault();
- $column2Default = $column2->getDefault();
-
- if ($column1Default != $column2Default ||
+
+ if ($properties1['default'] != $properties2['default'] ||
// Null values need to be checked additionally as they tell whether to create or drop a default value.
// null != 0, null != false, null != '' etc. This affects platform's table alteration SQL generation.
- (null === $column1Default && null !== $column2Default) ||
- (null === $column2Default && null !== $column1Default)
+ (null === $properties1['default'] && null !== $properties2['default']) ||
+ (null === $properties2['default'] && null !== $properties1['default'])
) {
$changedProperties[] = 'default';
}
- if ($column1->getUnsigned() != $column2->getUnsigned()) {
- $changedProperties[] = 'unsigned';
- }
-
- $column1Type = $column1->getType();
-
- if ($column1Type instanceof \Doctrine\DBAL\Types\StringType ||
- $column1Type instanceof \Doctrine\DBAL\Types\BinaryType
- ) {
+ if ($properties1['type'] instanceof Types\StringType || $properties1['type'] instanceof Types\BinaryType) {
// check if value of length is set at all, default value assumed otherwise.
- $length1 = $column1->getLength() ?: 255;
- $length2 = $column2->getLength() ?: 255;
+ $length1 = $properties1['length'] ?: 255;
+ $length2 = $properties2['length'] ?: 255;
if ($length1 != $length2) {
$changedProperties[] = 'length';
}
- if ($column1->getFixed() != $column2->getFixed()) {
+ if ($properties1['fixed'] != $properties2['fixed']) {
Guilherme Blanco Owner

!==

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$changedProperties[] = 'fixed';
}
- }
-
- if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
- if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
+ } elseif ($properties1['type'] instanceof Types\DecimalType) {
+ if (($properties1['precision'] ?: 10) != ($properties2['precision'] ?: 10)) {
$changedProperties[] = 'precision';
}
- if ($column1->getScale() != $column2->getScale()) {
+ if ($properties1['scale'] != $properties2['scale']) {
Guilherme Blanco Owner

!==

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$changedProperties[] = 'scale';
}
}
- if ($column1->getAutoincrement() != $column2->getAutoincrement()) {
- $changedProperties[] = 'autoincrement';
- }
-
// only allow to delete comment if its set to '' not to null.
- if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) {
+ if ($properties1['comment'] !== null && $properties1['comment'] != $properties2['comment']) {
Guilherme Blanco Owner

!== on second check

Martin Hasoň
hason added a note

@deeky666 has different opinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$changedProperties[] = 'comment';
}
- $options1 = $column1->getCustomSchemaOptions();
- $options2 = $column2->getCustomSchemaOptions();
-
- $commonKeys = array_keys(array_intersect_key($options1, $options2));
+ $customOptions1 = $column1->getCustomSchemaOptions();
+ $customOptions2 = $column2->getCustomSchemaOptions();
- foreach ($commonKeys as $key) {
- if ($options1[$key] !== $options2[$key]) {
+ foreach (array_merge(array_keys($customOptions1), array_keys($customOptions2)) as $key) {
+ if ( ! array_key_exists($key, $properties1) || ! array_key_exists($key, $properties2)) {
Guilherme Blanco Owner

That seems ugly/slow. array_key_exists should be replaced with isset IMHO.

Martin Hasoň
hason added a note

I can not replace it because null can be a valid value.

Guilherme Blanco Owner

Of course you can! =)

if ( ! (isset($properties1[$key]) || array_key_exists($key, $porperties1)) || ! (isset($properties2[$key]) || array_key_exists($key, $properties2))) {
Christophe Coevoet
stof added a note

@guilhermeblanco The difference between isset and array_key_exists is only significant when you have XDebug enabled AFAIK (because XDebug slows down function call but isset() is not a function call)

Guilherme Blanco Owner

@stof it is, as I've discussed a lot with Ilia during last year's Confoo (and resulted in his post: http://ilia.ws/archives/247-Performance-Analysis-of-isset-vs-array_key_exists.html )
Most of the time, you're running schema updates in development, with xdebug enabled... so... =)

Benjamin Eberlei Owner

This is completly irrelevant because it is used in development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $changedProperties[] = $key;
+ } elseif ($properties1[$key] !== $properties2[$key]) {
$changedProperties[] = $key;
}
}
- $diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1));
+ $platformOptions1 = $column1->getPlatformOptions();
+ $platformOptions2 = $column2->getPlatformOptions();
- $changedProperties = array_merge($changedProperties, $diffKeys);
+ foreach (array_keys(array_intersect_key($platformOptions1, $platformOptions2)) as $key) {
+ if ($properties1[$key] !== $properties2[$key]) {
+ $changedProperties[] = $key;
+ }
+ }
- return $changedProperties;
+ return array_unique($changedProperties);
}
/**
11 lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php
View
@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
+use Doctrine\DBAL\Types\Type;
+
/**
* Schema manager for the Drizzle RDBMS.
*
@@ -31,7 +33,6 @@ class DrizzleSchemaManager extends AbstractSchemaManager
*/
protected function _getPortableTableColumnDefinition($tableColumn)
{
- $tableName = $tableColumn['COLUMN_NAME'];
$dbType = strtolower($tableColumn['DATA_TYPE']);
$type = $this->_platform->getDoctrineTypeMapping($dbType);
@@ -48,7 +49,13 @@ protected function _getPortableTableColumnDefinition($tableColumn)
'comment' => (isset($tableColumn['COLUMN_COMMENT']) ? $tableColumn['COLUMN_COMMENT'] : null),
);
- return new Column($tableName, \Doctrine\DBAL\Types\Type::getType($type), $options);
+ $column = new Column($tableColumn['COLUMN_NAME'], Type::getType($type), $options);
+
+ if ( ! empty($tableColumn['COLLATION_NAME'])) {
+ $column->setPlatformOption('collation', $tableColumn['COLLATION_NAME']);
+ }
+
+ return $column;
}
/**
12 lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php
View
@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
+use Doctrine\DBAL\Types\Type;
+
/**
* Schema manager for the MySql RDBMS.
*
@@ -168,7 +170,7 @@ protected function _getPortableTableColumnDefinition($tableColumn)
'scale' => null,
'precision' => null,
'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false),
- 'comment' => (isset($tableColumn['comment'])) ? $tableColumn['comment'] : null
+ 'comment' => isset($tableColumn['comment']) ? $tableColumn['comment'] : null,
);
if ($scale !== null && $precision !== null) {
@@ -176,7 +178,13 @@ protected function _getPortableTableColumnDefinition($tableColumn)
$options['precision'] = $precision;
}
- return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
+ $column = new Column($tableColumn['field'], Type::getType($type), $options);
+
+ if (isset($tableColumn['collation'])) {
+ $column->setPlatformOption('collation', $tableColumn['collation']);
+ }
+
+ return $column;
}
/**
10 lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php
View
@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
+use Doctrine\DBAL\Types\Type;
+
/**
* PostgreSQL Schema Manager.
*
@@ -402,6 +404,12 @@ protected function _getPortableTableColumnDefinition($tableColumn)
'comment' => $tableColumn['comment'],
);
- return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
+ $column = new Column($tableColumn['field'], Type::getType($type), $options);
+
+ if (isset($tableColumn['collation']) && !empty($tableColumn['collation'])) {
+ $column->setPlatformOption('collation', $tableColumn['collation']);
+ }
+
+ return $column;
}
}
9 lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
View
@@ -99,12 +99,11 @@ protected function _getPortableTableColumnDefinition($tableColumn)
'comment' => $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null,
);
- $platformOptions = array(
- 'collate' => $tableColumn['collation'] == 'NULL' ? null : $tableColumn['collation']
- );
-
$column = new Column($tableColumn['name'], Type::getType($type), $options);
- $column->setPlatformOptions($platformOptions);
+
+ if (isset($tableColumn['collation']) && $tableColumn['collation'] !== 'NULL') {
+ $column->setPlatformOption('collation', $tableColumn['collation']);
+ }
return $column;
}
30 lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
View
@@ -20,6 +20,8 @@
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\Types\StringType;
+use Doctrine\DBAL\Types\TextType;
/**
* Sqlite SchemaManager.
@@ -217,8 +219,11 @@ protected function _getPortableTableIndexDefinition($tableIndex)
protected function _getPortableTableColumnList($table, $database, $tableColumns)
{
$list = parent::_getPortableTableColumnList($table, $database, $tableColumns);
+
+ // find column with autoincrement
$autoincrementColumn = null;
$autoincrementCount = 0;
+
foreach ($tableColumns as $tableColumn) {
if ('0' != $tableColumn['pk']) {
$autoincrementCount++;
@@ -236,6 +241,18 @@ protected function _getPortableTableColumnList($table, $database, $tableColumns)
}
}
+ // inspect column collation
+ $createSql = $this->_conn->fetchAll("SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = 'table' AND name = '$table'");
Benjamin Eberlei Owner

Is it really necessary to execute another query here?

Martin Hasoň
hason added a note

Yes. SQLite does not have a function to obtain a column collation. I have to parse a sql query to create a table.

Benjamin Eberlei Owner

That i undrestand, but cant you get this SQL from the previous query already?

Martin Hasoň
hason added a note

Where is the previous query? I do not know where to find it.

Steve Müller Collaborator

I think what @beberlei means is that you should select it as an additional column in SqlitePlatform::getListTableColumnsSQL() to avoid having to query here again.

Martin Hasoň
hason added a note

How do I combine SELECT and PRAGMA into one query?

Steve Müller Collaborator

Hm. Didn't know Sqlite uses PRAGMA command for this :(. Don't think there is a way to combine these statements then. So we could either leave it the way it is now or switch to completely parse table details from the SELECT statement. Don't know really...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $createSql = isset($createSql[0]['sql']) ? $createSql[0]['sql'] : '';
+
+ foreach ($list as $columnName => $column) {
+ $type = $column->getType();
+
+ if ($type instanceof StringType || $type instanceof TextType) {
+ $column->setPlatformOption('collation', $this->parseColumnCollationFromSQL($columnName, $createSql) ?: 'BINARY');
+ }
+ }
+
return $list;
}
@@ -393,4 +410,17 @@ private function getTableDiffForAlterForeignKey(ForeignKeyConstraint $foreignKey
return $tableDiff;
}
+
+ private function parseColumnCollationFromSQL($column, $sql)
+ {
+ if (preg_match(
+ '{(?:'.preg_quote($column).'|'.preg_quote($this->_platform->quoteSingleIdentifier($column)).')
+ [^,(]+(?:\([^()]+\)[^,]*)?
+ (?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*
+ COLLATE\s+["\']?([^\s,"\')]+)}isx', $sql, $match)) {
+ return $match[1];
+ }
+
+ return false;
+ }
}
1  lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php
View
@@ -40,6 +40,7 @@ class ReservedWordsCommand extends Command
'sqlserver2012' => 'Doctrine\DBAL\Platforms\Keywords\SQLServer2012Keywords',
'sqlite' => 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords',
'pgsql' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords',
+ 'pgsql91' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQL91Keywords',
'pgsql92' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQL92Keywords',
'oracle' => 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords',
'db2' => 'Doctrine\DBAL\Platforms\Keywords\DB2Keywords',
22 tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php
View
@@ -2,6 +2,8 @@
namespace Doctrine\Tests\DBAL\Functional\Schema;
+use Doctrine\DBAL\Schema\Table;
+
require_once __DIR__ . '/../../../TestInit.php';
class DrizzleSchemaManagerTest extends SchemaManagerFunctionalTestCase
@@ -10,7 +12,7 @@ public function testListTableWithBinary()
{
$tableName = 'test_binary_table';
- $table = new \Doctrine\DBAL\Schema\Table($tableName);
+ $table = new Table($tableName);
$table->addColumn('id', 'integer');
$table->addColumn('column_varbinary', 'binary', array());
$table->addColumn('column_binary', 'binary', array('fixed' => true));
@@ -26,4 +28,22 @@ public function testListTableWithBinary()
$this->assertInstanceOf('Doctrine\DBAL\Types\BinaryType', $table->getColumn('column_binary')->getType());
$this->assertFalse($table->getColumn('column_binary')->getFixed());
}
+
+ public function testColumnCollation()
+ {
+ $table = new Table('test_collation');
+ $table->addOption('collate', $collation = 'utf8_unicode_ci');
+ $table->addColumn('id', 'integer');
+ $table->addColumn('text', 'text');
+ $table->addColumn('foo', 'text')->setPlatformOption('collation', 'utf8_swedish_ci');
+ $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci');
+ $this->_sm->dropAndCreateTable($table);
+
+ $columns = $this->_sm->listTableColumns('test_collation');
+
+ $this->assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions());
+ $this->assertEquals('utf8_unicode_ci', $columns['text']->getPlatformOption('collation'));
+ $this->assertEquals('utf8_swedish_ci', $columns['foo']->getPlatformOption('collation'));
+ $this->assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation'));
+ }
}
19 tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php
View
@@ -153,4 +153,23 @@ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes()
$this->assertNull($onlineTable->getColumn('def_blob_null')->getDefault());
$this->assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull());
}
+
+ public function testColumnCollation()
+ {
+ $table = new Table('test_collation');
+ $table->addOption('collate', $collation = 'latin1_swedish_ci');
+ $table->addOption('charset', 'latin1');
+ $table->addColumn('id', 'integer');
+ $table->addColumn('text', 'text');
+ $table->addColumn('foo', 'text')->setPlatformOption('collation', 'latin1_swedish_ci');
+ $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci');
+ $this->_sm->dropAndCreateTable($table);
+
+ $columns = $this->_sm->listTableColumns('test_collation');
+
+ $this->assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions());
+ $this->assertEquals('latin1_swedish_ci', $columns['text']->getPlatformOption('collation'));
+ $this->assertEquals('latin1_swedish_ci', $columns['foo']->getPlatformOption('collation'));
+ $this->assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation'));
+ }
}
18 tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php
View
@@ -10,10 +10,10 @@
class SQLServerSchemaManagerTest extends SchemaManagerFunctionalTestCase
{
- protected function getPlatformName()
- {
- return "mssql";
- }
+ protected function getPlatformName()
+ {
+ return "mssql";
+ }
/**
* @group DBAL-255
@@ -35,22 +35,22 @@ public function testDropColumnConstraints()
$this->assertEquals(1, count($columns));
}
- public function testCollationCharset()
+ public function testColumnCollation()
{
- $table = new \Doctrine\DBAL\Schema\Table($tableName = 'test_collation_charset');
+ $table = new \Doctrine\DBAL\Schema\Table($tableName = 'test_collation');
$column = $table->addColumn($columnName = 'test', 'string');
$this->_sm->dropAndCreateTable($table);
$columns = $this->_sm->listTableColumns($tableName);
- $this->assertTrue($columns[$columnName]->hasPlatformOption('collate')); // SQL Server should report a default collation on the column
+ $this->assertTrue($columns[$columnName]->hasPlatformOption('collation')); // SQL Server should report a default collation on the column
- $column->setPlatformOption('collate', $collation = 'Icelandic_CS_AS');
+ $column->setPlatformOption('collation', $collation = 'Icelandic_CS_AS');
$this->_sm->dropAndCreateTable($table);
$columns = $this->_sm->listTableColumns($tableName);
- $this->assertEquals($collation, $columns[$columnName]->getPlatformOption('collate'));
+ $this->assertEquals($collation, $columns[$columnName]->getPlatformOption('collation'));
}
public function testDefaultContraints()
25 tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php
View
@@ -2,8 +2,6 @@
namespace Doctrine\Tests\DBAL\Functional\Schema;
-use Doctrine\DBAL\Schema\ForeignKeyConstraint;
-
use Doctrine\DBAL\Schema;
require_once __DIR__ . '/../../../TestInit.php';
@@ -62,17 +60,34 @@ public function testListForeignKeysFromExistingDatabase()
);
$expected = array(
- new ForeignKeyConstraint(array('log'), 'log', array(null), 'FK_3',
+ new Schema\ForeignKeyConstraint(array('log'), 'log', array(null), 'FK_3',
array('onUpdate' => 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false)),
- new ForeignKeyConstraint(array('parent'), 'user', array('id'), '1',
+ new Schema\ForeignKeyConstraint(array('parent'), 'user', array('id'), '1',
array('onUpdate' => 'NO ACTION', 'onDelete' => 'CASCADE', 'deferrable' => false, 'deferred' => false)),
- new ForeignKeyConstraint(array('page'), 'page', array('key'), 'FK_1',
+ new Schema\ForeignKeyConstraint(array('page'), 'page', array('key'), 'FK_1',
array('onUpdate' => 'NO ACTION', 'onDelete' => 'NO ACTION', 'deferrable' => true, 'deferred' => true)),
);
$this->assertEquals($expected, $this->_sm->listTableForeignKeys('user'));
}
+ public function testColumnCollation()
+ {
+ $table = new Schema\Table('test_collation');
+ $table->addColumn('id', 'integer');
+ $table->addColumn('text', 'text');
+ $table->addColumn('foo', 'text')->setPlatformOption('collation', 'BINARY');
+ $table->addColumn('bar', 'text')->setPlatformOption('collation', 'NOCASE');
+ $this->_sm->dropAndCreateTable($table);
+
+ $columns = $this->_sm->listTableColumns('test_collation');
+
+ $this->assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions());
+ $this->assertEquals('BINARY', $columns['text']->getPlatformOption('collation'));
+ $this->assertEquals('BINARY', $columns['foo']->getPlatformOption('collation'));
+ $this->assertEquals('NOCASE', $columns['bar']->getPlatformOption('collation'));
+ }
+
public function testListTableWithBinary()
{
$tableName = 'test_binary_table';
21 tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php
View
@@ -0,0 +1,21 @@
+<?php
+
+namespace Doctrine\Tests\DBAL\Platforms;
+
+use Doctrine\DBAL\Platforms\PostgreSQL91Platform;
+
+class PostgreSql91PlatformTest extends PostgreSqlPlatformTest
+{
+ public function createPlatform()
+ {
+ return new PostgreSQL91Platform();
+ }
+
+ public function testColumnCollationDeclarationSQL()
+ {
+ $this->assertEquals(
+ 'COLLATE "en_US.UTF-8"',
+ $this->_platform->getColumnCollationDeclarationSQL('en_US.UTF-8')
+ );
+ }
+}
34 tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php
View
@@ -1001,4 +1001,38 @@ public function assertSchemaSequenceChangeCount($diff, $newSequenceCount=0, $cha
$this->assertEquals($changeSequenceCount, count($diff->changedSequences), "Expected number of changed sequences is wrong.");
$this->assertEquals($removeSequenceCount, count($diff->removedSequences), "Expected number of removed sequences is wrong.");
}
+
+ public function testDiffColumnPlatformOptions()
+ {
+ $column1 = new Column('foo', Type::getType('string'), array('platformOptions' => array('foo' => 'foo', 'bar' => 'bar')));
+ $column2 = new Column('foo', Type::getType('string'), array('platformOptions' => array('foo' => 'foo', 'foobar' => 'foobar')));
+ $column3 = new Column('foo', Type::getType('string'), array('platformOptions' => array('foo' => 'foo', 'bar' => 'rab')));
+ $column4 = new Column('foo', Type::getType('string'));
+
+ $comparator = new Comparator();
+
+ $this->assertEquals(array(), $comparator->diffColumn($column1, $column2));
+ $this->assertEquals(array(), $comparator->diffColumn($column2, $column1));
+ $this->assertEquals(array('bar'), $comparator->diffColumn($column1, $column3));
+ $this->assertEquals(array('bar'), $comparator->diffColumn($column3, $column1));
+ $this->assertEquals(array(), $comparator->diffColumn($column1, $column4));
+ $this->assertEquals(array(), $comparator->diffColumn($column4, $column1));
+ }
+
+ public function testComplexDiffColumn()
+ {
+ $column1 = new Column('foo', Type::getType('string'), array(
+ 'platformOptions' => array('foo' => 'foo'),
+ 'customSchemaOptions' => array('foo' => 'bar'),
+ ));
+
+ $column2 = new Column('foo', Type::getType('string'), array(
+ 'platformOptions' => array('foo' => 'bar'),