MySqlPlatform.php 25.3 KB
Newer Older
1
<?php
romanb's avatar
romanb committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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 LGPL. For more information, see
17
 * <http://www.doctrine-project.org>.
romanb's avatar
romanb committed
18
 */
19

20
namespace Doctrine\DBAL\Platforms;
21

22
use Doctrine\DBAL\DBALException,
23 24
    Doctrine\DBAL\Schema\TableDiff,
    Doctrine\DBAL\Schema\Index,
25
    Doctrine\DBAL\Schema\Table;
26

27 28
/**
 * The MySqlPlatform provides the behavior, features and SQL dialect of the
29 30
 * MySQL database platform. This platform represents a MySQL 5.0 or greater platform that
 * uses the InnoDB storage engine.
31 32 33
 *
 * @since 2.0
 * @author Roman Borschel <roman@code-factory.org>
34
 * @author Benjamin Eberlei <kontakt@beberlei.de>
35
 * @todo Rename: MySQLPlatform
36
 */
37
class MySqlPlatform extends AbstractPlatform
38
{
romanb's avatar
romanb committed
39 40 41 42 43 44 45 46 47
    /**
     * Gets the character used for identifier quoting.
     *
     * @return string
     * @override
     */
    public function getIdentifierQuoteCharacter()
    {
        return '`';
48
    }
49

50
    /**
romanb's avatar
romanb committed
51
     * Returns the regular expression operator.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
     *
     * @return string
     * @override
     */
    public function getRegexpExpression()
    {
        return 'RLIKE';
    }

    /**
     * Returns global unique identifier
     *
     * @return string to get global unique identifier
     * @override
     */
    public function getGuidExpression()
    {
        return 'UUID()';
    }

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
    /**
     * returns the position of the first occurrence of substring $substr in string $str
     *
     * @param string $substr    literal string to find
     * @param string $str       literal string
     * @param int    $pos       position to start at, beginning of string by default
     * @return integer
     */
    public function getLocateExpression($str, $substr, $startPos = false)
    {
        if ($startPos == false) {
            return 'LOCATE(' . $substr . ', ' . $str . ')';
        } else {
            return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')';
        }
    }

89 90 91 92 93 94 95 96 97 98 99 100 101 102
    /**
     * Returns a series of strings concatinated
     *
     * concat() accepts an arbitrary number of parameters. Each parameter
     * must contain an expression or an array with expressions.
     *
     * @param string|array(string) strings that will be concatinated.
     * @override
     */
    public function getConcatExpression()
    {
        $args = func_get_args();
        return 'CONCAT(' . join(', ', (array) $args) . ')';
    }
103 104 105 106 107 108 109 110

    public function getDateDiffExpression($date1, $date2)
    {
        return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')';
    }

    public function getDateAddDaysExpression($date, $days)
    {
111
        return 'DATE_ADD(' . $date . ', INTERVAL ' . $days . ' DAY)';
112 113 114 115
    }

    public function getDateSubDaysExpression($date, $days)
    {
116
        return 'DATE_SUB(' . $date . ', INTERVAL ' . $days . ' DAY)';
117 118 119 120
    }

    public function getDateAddMonthExpression($date, $months)
    {
121
        return 'DATE_ADD(' . $date . ', INTERVAL ' . $months . ' MONTH)';
122 123 124 125
    }

    public function getDateSubMonthExpression($date, $months)
    {
126
        return 'DATE_SUB(' . $date . ', INTERVAL ' . $months . ' MONTH)';
127
    }
128

129
    public function getListDatabasesSQL()
130 131 132 133
    {
        return 'SHOW DATABASES';
    }

134
    public function getListTableConstraintsSQL($table)
135
    {
136
        return 'SHOW INDEX FROM ' . $table;
137 138
    }

139
    /**
140
     * Two approaches to listing the table indexes. The information_schema is
141
     * prefered, because it doesn't cause problems with SQL keywords such as "order" or "table".
142
     *
143 144 145 146 147
     * @param string $table
     * @param string $currentDatabase
     * @return string
     */
    public function getListTableIndexesSQL($table, $currentDatabase = null)
148
    {
149 150 151 152
        if ($currentDatabase) {
            return "SELECT TABLE_NAME AS `Table`, NON_UNIQUE AS Non_Unique, INDEX_NAME AS Key_name, ".
                   "SEQ_IN_INDEX AS Seq_in_index, COLUMN_NAME AS Column_Name, COLLATION AS Collation, ".
                   "CARDINALITY AS Cardinality, SUB_PART AS Sub_Part, PACKED AS Packed, " .
153
                   "NULLABLE AS `Null`, INDEX_TYPE AS Index_Type, COMMENT AS Comment " .
154 155 156 157
                   "FROM information_schema.STATISTICS WHERE TABLE_NAME = '" . $table . "' AND TABLE_SCHEMA = '" . $currentDatabase . "'";
        } else {
            return 'SHOW INDEX FROM ' . $table;
        }
158 159
    }

160
    public function getListViewsSQL($database)
161
    {
162
        return "SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = '".$database."'";
163 164
    }

165
    public function getListTableForeignKeysSQL($table, $database = null)
166
    {
167 168 169
        $sql = "SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ".
               "k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ".
               "FROM information_schema.key_column_usage k /*!50116 ".
170
               "INNER JOIN information_schema.referential_constraints c ON ".
171
               "  c.constraint_name = k.constraint_name AND ".
172
               "  c.table_name = '$table' */ WHERE k.table_name = '$table'";
173

174
        if ($database) {
175
            $sql .= " AND k.table_schema = '$database' /*!50116 AND c.constraint_schema = '$database' */";
176 177
        }

178
        $sql .= " AND k.`REFERENCED_COLUMN_NAME` is not NULL";
179 180 181 182

        return $sql;
    }

183
    public function getCreateViewSQL($name, $sql)
184 185 186 187
    {
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
    }

188
    public function getDropViewSQL($name)
189 190 191 192
    {
        return 'DROP VIEW '. $name;
    }

193
    /**
194 195 196
     * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
     *
     * @params array $field
197
     */
198
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
199 200
    {
        return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
201
                : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
202
    }
203

204
    /** @override */
205
    public function getClobTypeDeclarationSQL(array $field)
206
    {
207
        if ( ! empty($field['length']) && is_numeric($field['length'])) {
208 209 210 211 212 213 214 215 216 217 218
            $length = $field['length'];
            if ($length <= 255) {
                return 'TINYTEXT';
            } else if ($length <= 65532) {
                return 'TEXT';
            } else if ($length <= 16777215) {
                return 'MEDIUMTEXT';
            }
        }
        return 'LONGTEXT';
    }
219

220 221 222
    /**
     * @override
     */
223
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
224
    {
225
        if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) {
226 227 228 229
            return 'TIMESTAMP';
        } else {
            return 'DATETIME';
        }
230
    }
231

232 233 234
    /**
     * @override
     */
235
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
236 237 238
    {
        return 'DATE';
    }
239

240 241 242
    /**
     * @override
     */
243
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
244 245
    {
        return 'TIME';
246
    }
247

248 249 250
    /**
     * @override
     */
251
    public function getBooleanTypeDeclarationSQL(array $field)
252 253 254 255
    {
        return 'TINYINT(1)';
    }

256 257 258 259 260 261 262 263 264 265 266 267
    /**
     * Obtain DBMS specific SQL code portion needed to set the COLLATION
     * of a field declaration to be used in statements like CREATE TABLE.
     *
     * @param string $collation   name of the collation
     * @return string  DBMS specific SQL code portion needed to set the COLLATION
     *                 of a field declaration.
     */
    public function getCollationFieldDeclaration($collation)
    {
        return 'COLLATE ' . $collation;
    }
268

269 270 271 272 273 274 275 276 277 278 279 280
    /**
     * Whether the platform prefers identity columns for ID generation.
     * MySql prefers "autoincrement" identity columns since sequences can only
     * be emulated with a table.
     *
     * @return boolean
     * @override
     */
    public function prefersIdentityColumns()
    {
        return true;
    }
281

romanb's avatar
romanb committed
282 283 284 285 286 287 288 289 290 291
    /**
     * Whether the platform supports identity columns.
     * MySql supports this through AUTO_INCREMENT columns.
     *
     * @return boolean
     * @override
     */
    public function supportsIdentityColumns()
    {
        return true;
292 293 294 295 296
    }

    public function supportsInlineColumnComments()
    {
        return true;
romanb's avatar
romanb committed
297
    }
298

299
    public function getShowDatabasesSQL()
300 301 302
    {
        return 'SHOW DATABASES';
    }
303

304
    public function getListTablesSQL()
305
    {
306
        return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'";
307
    }
308

309
    public function getListTableColumnsSQL($table, $database = null)
310
    {
311 312 313 314 315 316 317 318
        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 CollactionName ".
                   "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $database . "' AND TABLE_NAME = '" . $table . "'";
        } else {
            return 'DESCRIBE ' . $table;
        }
319 320
    }

321 322 323 324 325 326 327
    /**
     * create a new database
     *
     * @param string $name name of the database that should be created
     * @return string
     * @override
     */
328
    public function getCreateDatabaseSQL($name)
329
    {
330
        return 'CREATE DATABASE ' . $name;
331
    }
332

333 334 335 336 337 338 339
    /**
     * drop an existing database
     *
     * @param string $name name of the database that should be dropped
     * @return string
     * @override
     */
340
    public function getDropDatabaseSQL($name)
341
    {
342
        return 'DROP DATABASE ' . $name;
343
    }
344

345 346 347
    /**
     * create a new table
     *
348 349
     * @param string $tableName   Name of the database that should be created
     * @param array $columns  Associative array that contains the definition of each field of the new table
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
     *                       The indexes of the array entries are the names of the fields of the table an
     *                       the array entry values are associative arrays like those that are meant to be
     *                       passed with the field definitions to get[Type]Declaration() functions.
     *                          array(
     *                              'id' => array(
     *                                  'type' => 'integer',
     *                                  'unsigned' => 1
     *                                  'notnull' => 1
     *                                  'default' => 0
     *                              ),
     *                              'name' => array(
     *                                  'type' => 'text',
     *                                  'length' => 12
     *                              ),
     *                              'password' => array(
     *                                  'type' => 'text',
     *                                  'length' => 12
     *                              )
     *                          );
     * @param array $options  An associative array of table options:
     *                          array(
     *                              'comment' => 'Foo',
     *                              'charset' => 'utf8',
     *                              'collate' => 'utf8_unicode_ci',
374 375 376 377 378 379 380
     *                              'engine' => 'innodb',
     *                              'foreignKeys' => array(
     *                                  new ForeignKeyConstraint(),
     *                                  new ForeignKeyConstraint(),
     *                                  new ForeignKeyConstraint(),
     *                                  // etc
     *                              )
381 382 383 384 385
     *                          );
     *
     * @return void
     * @override
     */
386
    protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
387
    {
388
        $queryFields = $this->getColumnDeclarationListSQL($columns);
389

390
        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
391
            foreach ($options['uniqueConstraints'] as $index => $definition) {
392
                $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition);
393
            }
394 395 396 397 398
        }

        // add all indexes
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
            foreach($options['indexes'] as $index => $definition) {
399
                $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
400 401 402 403 404
            }
        }

        // attach all primary keys
        if (isset($options['primary']) && ! empty($options['primary'])) {
405
            $keyColumns = array_unique(array_values($options['primary']));
406 407 408 409 410 411 412
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
        }

        $query = 'CREATE ';
        if (!empty($options['temporary'])) {
            $query .= 'TEMPORARY ';
        }
413
        $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') ';
414 415

        if (isset($options['comment'])) {
416
            $query .= 'COMMENT = ' . $options['comment'] . ' ';
417
        }
418 419 420

        if ( ! isset($options['charset'])) {
            $options['charset'] = 'utf8';
421 422
        }

423 424
        if ( ! isset($options['collate'])) {
            $options['collate'] = 'utf8_general_ci';
425
        }
426

427 428 429 430 431
        $query .= 'DEFAULT CHARACTER SET ' . $options['charset'];
        $query .= ' COLLATE ' . $options['collate'];

        if ( ! isset($options['engine'])) {
            $options['engine'] = 'InnoDB';
432
        }
433 434
        $query .= ' ENGINE = ' . $options['engine'];

435 436 437
        $sql[] = $query;

        if (isset($options['foreignKeys'])) {
438
            foreach ((array) $options['foreignKeys'] as $definition) {
439
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
440 441
            }
        }
442

443 444
        return $sql;
    }
445

446
    /**
447
     * Gets the SQL to alter an existing table.
448
     *
449 450
     * @param TableDiff $diff
     * @return array
451
     */
452
    public function getAlterTableSQL(TableDiff $diff)
453
    {
454
        $columnSql = array();
455 456 457
        $queryParts = array();
        if ($diff->newName !== false) {
            $queryParts[] =  'RENAME TO ' . $diff->newName;
458 459
        }

460
        foreach ($diff->addedColumns as $column) {
461 462
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
                continue;
463 464
            }

465 466 467
            $columnArray = $column->toArray();
            $columnArray['comment'] = $this->getColumnComment($column);
            $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
468 469
        }

470
        foreach ($diff->removedColumns as $column) {
471 472
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
                continue;
473 474
            }

475
            $queryParts[] =  'DROP ' . $column->getQuotedName($this);
476 477
        }

478
        foreach ($diff->changedColumns as $columnDiff) {
479 480
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
                continue;
481 482
            }

483 484
            /* @var $columnDiff Doctrine\DBAL\Schema\ColumnDiff */
            $column = $columnDiff->column;
485 486
            $columnArray = $column->toArray();
            $columnArray['comment'] = $this->getColumnComment($column);
487
            $queryParts[] =  'CHANGE ' . ($columnDiff->oldColumnName) . ' '
488
                    . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
489 490
        }

491
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
492 493
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
                continue;
494 495
            }

496 497
            $columnArray = $column->toArray();
            $columnArray['comment'] = $this->getColumnComment($column);
498
            $queryParts[] =  'CHANGE ' . $oldColumnName . ' '
499
                    . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray);
500 501
        }

502
        $sql = array();
503
        $tableSql = array();
504

505
        if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
506 507 508 509 510 511 512 513
            if (count($queryParts) > 0) {
                $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts);
            }
            $sql = array_merge(
                $this->getPreAlterTableIndexForeignKeySQL($diff),
                $sql,
                $this->getPostAlterTableIndexForeignKeySQL($diff)
            );
514
        }
515 516

        return array_merge($sql, $tableSql, $columnSql);
517
    }
518

519 520 521 522 523 524 525 526 527 528 529
    /**
     * Fix for DROP/CREATE index after foreign key change from OneToOne to ManyToOne
     *
     * @param TableDiff $diff
     * @return array
     */
    protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
    {
        $sql = array();
        $table = $diff->name;

530
        foreach ($diff->removedIndexes as $remKey => $remIndex) {
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

            foreach ($diff->addedIndexes as $addKey => $addIndex) {
                if ($remIndex->getColumns() == $addIndex->getColumns()) {

                    $columns = $addIndex->getColumns();
                    $type = '';
                    if ($addIndex->isUnique()) {
                        $type = 'UNIQUE ';
                    }

                    $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', ';
                    $query .= 'ADD ' . $type . 'INDEX ' . $addIndex->getName();
                    $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')';

                    $sql[] = $query;

                    unset($diff->removedIndexes[$remKey]);
                    unset($diff->addedIndexes[$addKey]);

                    break;
                }
            }
        }

        $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff));

        return $sql;
    }


561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    /**
     * @override
     */
    protected function getCreateIndexSQLFlags(Index $index)
    {
        $type = '';
        if ($index->isUnique()) {
            $type .= 'UNIQUE ';
        } else if ($index->hasFlag('fulltext')) {
            $type .= 'FULLTEXT ';
        }

        return $type;
    }


577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
    /**
     * Obtain DBMS specific SQL code portion needed to declare an integer type
     * field to be used in statements like CREATE TABLE.
     *
     * @param string  $name   name the field to be declared.
     * @param string  $field  associative array with the name of the properties
     *                        of the field being declared as array indexes.
     *                        Currently, the types of supported field
     *                        properties are as follows:
     *
     *                       unsigned
     *                        Boolean flag that indicates whether the field
     *                        should be declared as unsigned integer if
     *                        possible.
     *
     *                       default
     *                        Integer value to be used as default for this
     *                        field.
     *
     *                       notnull
     *                        Boolean flag that indicates whether this field is
     *                        constrained to not be set to null.
     * @return string  DBMS specific SQL code portion that should be used to
     *                 declare the specified field.
     * @override
     */
603
    public function getIntegerTypeDeclarationSQL(array $field)
604
    {
605
        return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
606 607 608
    }

    /** @override */
609
    public function getBigIntTypeDeclarationSQL(array $field)
610
    {
611
        return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
612 613 614
    }

    /** @override */
615
    public function getSmallIntTypeDeclarationSQL(array $field)
616
    {
617
        return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
618 619 620
    }

    /** @override */
621
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
622
    {
623
        $autoinc = '';
624
        if ( ! empty($columnDef['autoincrement'])) {
625 626
            $autoinc = ' AUTO_INCREMENT';
        }
627
        $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
628

629
        return $unsigned . $autoinc;
630
    }
631

632 633 634 635
    /**
     * Return the FOREIGN KEY query section dealing with non-standard options
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
     *
636
     * @param ForeignKeyConstraint $foreignKey
637 638 639
     * @return string
     * @override
     */
640
    public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
641 642
    {
        $query = '';
643 644
        if ($foreignKey->hasOption('match')) {
            $query .= ' MATCH ' . $foreignKey->getOption('match');
645
        }
646
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
647 648
        return $query;
    }
649

650
    /**
651
     * Gets the SQL to drop an index of a table.
652
     *
653 654
     * @param Index $index           name of the index to be dropped
     * @param string|Table $table          name of table that should be used in method
655 656
     * @override
     */
657
    public function getDropIndexSQL($index, $table=null)
658
    {
659 660 661 662 663
        if($index instanceof Index) {
            $indexName = $index->getQuotedName($this);
        } else if(is_string($index)) {
            $indexName = $index;
        } else {
664
            throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
665
        }
666

667
        if($table instanceof Table) {
668
            $table = $table->getQuotedName($this);
669
        } else if(!is_string($table)) {
670
            throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
671
        }
672

673
        if ($index instanceof Index && $index->isPrimary()) {
674
            // mysql primary keys are always named "PRIMARY",
675 676 677
            // so we cannot use them in statements because of them being keyword.
            return $this->getDropPrimaryKeySQL($table);
        }
678

679 680
        return 'DROP INDEX ' . $indexName . ' ON ' . $table;
    }
681

682 683
    /**
     * @param Index $index
684
     * @param Table $table
685 686 687 688
     */
    protected function getDropPrimaryKeySQL($table)
    {
        return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY';
689
    }
690

691
    public function getSetTransactionIsolationSQL($level)
romanb's avatar
romanb committed
692
    {
693
        return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
romanb's avatar
romanb committed
694
    }
695 696

    /**
697
     * Get the platform name for this instance.
698 699 700 701 702 703 704
     *
     * @return string
     */
    public function getName()
    {
        return 'mysql';
    }
705

706 707 708 709
    public function getReadLockSQL()
    {
        return 'LOCK IN SHARE MODE';
    }
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

    protected function initializeDoctrineTypeMappings()
    {
        $this->doctrineTypeMapping = array(
            'tinyint'       => 'boolean',
            'smallint'      => 'smallint',
            'mediumint'     => 'integer',
            'int'           => 'integer',
            'integer'       => 'integer',
            'bigint'        => 'bigint',
            'tinytext'      => 'text',
            'mediumtext'    => 'text',
            'longtext'      => 'text',
            'text'          => 'text',
            'varchar'       => 'string',
            'string'        => 'string',
            'char'          => 'string',
            'date'          => 'date',
            'datetime'      => 'datetime',
            'timestamp'     => 'datetime',
            'time'          => 'time',
731 732 733
            'float'         => 'float',
            'double'        => 'float',
            'real'          => 'float',
734 735 736
            'decimal'       => 'decimal',
            'numeric'       => 'decimal',
            'year'          => 'date',
737 738 739 740
            'longblob'      => 'blob',
            'blob'          => 'blob',
            'mediumblob'    => 'blob',
            'tinyblob'      => 'blob',
741
            'binary'        => 'blob',
742
            'varbinary'     => 'blob',
743 744
        );
    }
745 746 747 748 749

    public function getVarcharMaxLength()
    {
        return 65535;
    }
750

751 752 753 754
    protected function getReservedKeywordsClass()
    {
        return 'Doctrine\DBAL\Platforms\Keywords\MySQLKeywords';
    }
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775

    /**
     * Get SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction.
     *
     * MySQL commits a transaction implicitly when DROP TABLE is executed, however not
     * if DROP TEMPORARY TABLE is executed.
     *
     * @throws \InvalidArgumentException
     * @param $table
     * @return string
     */
    public function getDropTemporaryTableSQL($table)
    {
        if ($table instanceof \Doctrine\DBAL\Schema\Table) {
            $table = $table->getQuotedName($this);
        } else if(!is_string($table)) {
            throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
        }

        return 'DROP TEMPORARY TABLE ' . $table;
    }
776 777 778 779 780 781 782 783

    /**
     * Gets the SQL Snippet used to declare a BLOB column type.
     */
    public function getBlobTypeDeclarationSQL(array $field)
    {
        return 'LONGBLOB';
    }
784
}