MySqlPlatform.php 23.9 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 416 417

        $optionStrings = array();

        if (isset($options['comment'])) {
418
            $optionStrings['comment'] = 'COMMENT = ' . $options['comment'];
419 420 421 422 423 424 425 426 427
        }
        if (isset($options['charset'])) {
            $optionStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
            if (isset($options['collate'])) {
                $optionStrings['charset'] .= ' COLLATE ' . $options['collate'];
            }
        }

        // get the type of the table
428
        if (isset($options['engine'])) {
429
            $optionStrings[] = 'ENGINE = ' . $options['engine'];
430 431 432
        } else {
            // default to innodb
            $optionStrings[] = 'ENGINE = InnoDB';
433
        }
434

435 436 437 438 439 440
        if ( ! empty($optionStrings)) {
            $query.= ' '.implode(' ', $optionStrings);
        }
        $sql[] = $query;

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

446 447
        return $sql;
    }
448

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

463
        foreach ($diff->addedColumns AS $fieldName => $column) {
464 465
            if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
                continue;
466 467
            }

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

473
        foreach ($diff->removedColumns AS $column) {
474 475
            if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
                continue;
476 477
            }

478
            $queryParts[] =  'DROP ' . $column->getQuotedName($this);
479 480
        }

481
        foreach ($diff->changedColumns AS $columnDiff) {
482 483
            if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
                continue;
484 485
            }

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

494
        foreach ($diff->renamedColumns AS $oldColumnName => $column) {
495 496
            if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
                continue;
497 498
            }

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

505
        $sql = array();
506
        $tableSql = array();
507

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

        return array_merge($sql, $tableSql, $columnSql);
520
    }
521

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
    /**
     * 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
     */
548
    public function getIntegerTypeDeclarationSQL(array $field)
549
    {
550
        return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
551 552 553
    }

    /** @override */
554
    public function getBigIntTypeDeclarationSQL(array $field)
555
    {
556
        return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
557 558 559
    }

    /** @override */
560
    public function getSmallIntTypeDeclarationSQL(array $field)
561
    {
562
        return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field);
563 564 565
    }

    /** @override */
566
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
567
    {
568
        $autoinc = '';
569
        if ( ! empty($columnDef['autoincrement'])) {
570 571
            $autoinc = ' AUTO_INCREMENT';
        }
572
        $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
573

574
        return $unsigned . $autoinc;
575
    }
576

577 578 579 580
    /**
     * Return the FOREIGN KEY query section dealing with non-standard options
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
     *
581
     * @param ForeignKeyConstraint $foreignKey
582 583 584
     * @return string
     * @override
     */
585
    public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
586 587
    {
        $query = '';
588 589
        if ($foreignKey->hasOption('match')) {
            $query .= ' MATCH ' . $foreignKey->getOption('match');
590
        }
591
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
592 593
        return $query;
    }
594

595
    /**
596
     * Gets the SQL to drop an index of a table.
597
     *
598 599
     * @param Index $index           name of the index to be dropped
     * @param string|Table $table          name of table that should be used in method
600 601
     * @override
     */
602
    public function getDropIndexSQL($index, $table=null)
603
    {
604 605 606 607 608
        if($index instanceof Index) {
            $indexName = $index->getQuotedName($this);
        } else if(is_string($index)) {
            $indexName = $index;
        } else {
609
            throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.');
610
        }
611

612
        if($table instanceof Table) {
613
            $table = $table->getQuotedName($this);
614
        } else if(!is_string($table)) {
615
            throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.');
616
        }
617

618
        if ($index instanceof Index && $index->isPrimary()) {
619
            // mysql primary keys are always named "PRIMARY",
620 621 622
            // so we cannot use them in statements because of them being keyword.
            return $this->getDropPrimaryKeySQL($table);
        }
623

624 625
        return 'DROP INDEX ' . $indexName . ' ON ' . $table;
    }
626

627 628
    /**
     * @param Index $index
629
     * @param Table $table
630 631 632 633
     */
    protected function getDropPrimaryKeySQL($table)
    {
        return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY';
634
    }
635

636
    public function getSetTransactionIsolationSQL($level)
romanb's avatar
romanb committed
637
    {
638
        return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level);
romanb's avatar
romanb committed
639
    }
640 641

    /**
642
     * Get the platform name for this instance.
643 644 645 646 647 648 649
     *
     * @return string
     */
    public function getName()
    {
        return 'mysql';
    }
650

651 652 653 654
    public function getReadLockSQL()
    {
        return 'LOCK IN SHARE MODE';
    }
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675

    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',
676 677 678
            'float'         => 'float',
            'double'        => 'float',
            'real'          => 'float',
679 680 681
            'decimal'       => 'decimal',
            'numeric'       => 'decimal',
            'year'          => 'date',
682 683 684 685
            'longblob'      => 'blob',
            'blob'          => 'blob',
            'mediumblob'    => 'blob',
            'tinyblob'      => 'blob',
686 687
        );
    }
688 689 690 691 692

    public function getVarcharMaxLength()
    {
        return 65535;
    }
693

694 695 696 697
    protected function getReservedKeywordsClass()
    {
        return 'Doctrine\DBAL\Platforms\Keywords\MySQLKeywords';
    }
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718

    /**
     * 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;
    }
719 720 721 722 723 724 725 726

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