Unverified Commit baa454c9 authored by belgattitude's avatar belgattitude Committed by Luís Cobucci

Updated mariadb 10.2 support

parent edfbda15
...@@ -21,7 +21,7 @@ before_install: ...@@ -21,7 +21,7 @@ before_install:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available" - mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
before_script: before_script:
- if [[ "$DB" == "mysql" || "$DB" == "mysqli" || "$DB" == "mariadb" ]]; then mysql < tests/travis/create-mysql-schema.sql; fi; - if [[ "$DB" == "mysql" || "$DB" == "mysqli" || "$DB" == *"mariadb"* ]]; then mysql < tests/travis/create-mysql-schema.sql; fi;
install: install:
- travis_retry composer -n install - travis_retry composer -n install
...@@ -103,6 +103,40 @@ jobs: ...@@ -103,6 +103,40 @@ jobs:
addons: addons:
mariadb: 10.1 mariadb: 10.1
- stage: Test
php: 7.1
env: DB=mariadb MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test
php: 7.2
env: DB=mariadb MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test
php: nightly
env: DB=mariadb MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test
php: 7.1
env: DB=mariadb.mysqli MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test
php: 7.2
env: DB=mariadb.mysqli MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test
php: nightly
env: DB=mariadb.mysqli MARIADB_VERSION=10.2
addons:
mariadb: 10.2
- stage: Test - stage: Test
php: 7.1 php: 7.1
env: DB=pgsql POSTGRESQL_VERSION=9.2 env: DB=pgsql POSTGRESQL_VERSION=9.2
......
...@@ -22,6 +22,8 @@ namespace Doctrine\DBAL\Driver; ...@@ -22,6 +22,8 @@ namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
use Doctrine\DBAL\Platforms\MySQL57Platform; use Doctrine\DBAL\Platforms\MySQL57Platform;
use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\MySqlSchemaManager; use Doctrine\DBAL\Schema\MySqlSchemaManager;
...@@ -123,35 +125,72 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver, ...@@ -123,35 +125,72 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver,
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return AbstractPlatform|MariaDb1027Platform|MySQL57Platform|MySqlPlatform
* @throws DBALException
*/ */
public function createDatabasePlatformForVersion($version) public function createDatabasePlatformForVersion($version): AbstractPlatform
{ {
if ( ! preg_match('/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/', $version, $versionParts)) { if (false !== stripos($version, 'mariadb')) {
$versionNumber = $this->getMariaDbMysqlVersionNumber($version);
if (version_compare($versionNumber, '10.2.7', '>=')) {
return new MariaDb1027Platform();
}
} else {
$versionNumber = $this->getOracleMysqlVersionNumber($version);
if (version_compare($versionNumber, '5.7.9', '>=')) {
return new MySQL57Platform();
}
}
return $this->getDatabasePlatform();
}
/**
* Get a normalized 'version number' from the server string
* returned by Oracle MySQL servers.
*
* @param string $versionString Version string returned by the driver, i.e. '5.7.10'
* @throws DBALException
*/
private function getOracleMysqlVersionNumber(string $versionString): string
{
if (!preg_match('/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/', $versionString, $versionParts)) {
throw DBALException::invalidPlatformVersionSpecified( throw DBALException::invalidPlatformVersionSpecified(
$version, $versionString,
'<major_version>.<minor_version>.<patch_version>' '<major_version>.<minor_version>.<patch_version>'
); );
} }
if (false !== stripos($version, 'mariadb')) {
return $this->getDatabasePlatform();
}
$majorVersion = $versionParts['major']; $majorVersion = $versionParts['major'];
$minorVersion = isset($versionParts['minor']) ? $versionParts['minor'] : 0; $minorVersion = $versionParts['minor'] ?? 0;
$patchVersion = isset($versionParts['patch']) ? $versionParts['patch'] : null; $patchVersion = $versionParts['patch'] ?? null;
if ('5' === $majorVersion && '7' === $minorVersion && null === $patchVersion) { if ('5' === $majorVersion && '7' === $minorVersion && null === $patchVersion) {
$patchVersion = '9'; $patchVersion = '9';
} }
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
}
if (version_compare($version, '5.7.9', '>=')) { /**
return new MySQL57Platform(); * Detect MariaDB server version, including hack for some mariadb distributions
* that starts with the prefix '5.5.5-'
*
* @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial'
* @throws DBALException
*/
private function getMariaDbMysqlVersionNumber(string $versionString): string
{
$version = str_replace('5.5.5-', '', $versionString);
if (!preg_match('/^(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/', strtolower($version), $versionParts)) {
throw DBALException::invalidPlatformVersionSpecified(
$version,
'(mariadb-)?<major_version>.<minor_version>.<patch_version>'
);
} }
return $this->getDatabasePlatform(); return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
} }
/** /**
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
namespace Doctrine\DBAL\Driver\DrizzlePDOMySql; namespace Doctrine\DBAL\Driver\DrizzlePDOMySql;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\DrizzlePlatform; use Doctrine\DBAL\Platforms\DrizzlePlatform;
use Doctrine\DBAL\Schema\DrizzleSchemaManager; use Doctrine\DBAL\Schema\DrizzleSchemaManager;
...@@ -47,7 +48,7 @@ class Driver extends \Doctrine\DBAL\Driver\PDOMySql\Driver ...@@ -47,7 +48,7 @@ class Driver extends \Doctrine\DBAL\Driver\PDOMySql\Driver
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function createDatabasePlatformForVersion($version) public function createDatabasePlatformForVersion($version): AbstractPlatform
{ {
return $this->getDatabasePlatform(); return $this->getDatabasePlatform();
} }
......
...@@ -94,9 +94,18 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar ...@@ -94,9 +94,18 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* The server version detection includes a special case for MariaDB
* to support '5.5.5-' prefixed versions introduced in Maria 10+
* @link https://jira.mariadb.org/browse/MDEV-4088
*/ */
public function getServerVersion() public function getServerVersion()
{ {
$serverInfos = $this->_conn->get_server_info();
if (false !== stripos($serverInfos, 'mariadb')) {
return $serverInfos;
}
$majorVersion = floor($this->_conn->server_version / 10000); $majorVersion = floor($this->_conn->server_version / 10000);
$minorVersion = floor(($this->_conn->server_version - $majorVersion * 10000) / 100); $minorVersion = floor(($this->_conn->server_version - $majorVersion * 10000) / 100);
$patchVersion = floor($this->_conn->server_version - $majorVersion * 10000 - $minorVersion * 100); $patchVersion = floor($this->_conn->server_version - $majorVersion * 10000 - $minorVersion * 100);
......
...@@ -2281,32 +2281,32 @@ abstract class AbstractPlatform ...@@ -2281,32 +2281,32 @@ abstract class AbstractPlatform
$default = $field['default']; $default = $field['default'];
if ( ! isset($field['type'])) { if ( ! isset($field['type'])) {
return " DEFAULT '" . $default . "'"; return ' DEFAULT ' . $this->quoteStringLiteral($default);
} }
$type = $field['type']; $type = $field['type'];
if ($type instanceof Types\PhpIntegerMappingType) { if ($type instanceof Types\PhpIntegerMappingType) {
return " DEFAULT " . $default; return ' DEFAULT ' . $default;
} }
if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) { if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) {
return " DEFAULT " . $this->getCurrentTimestampSQL(); return ' DEFAULT ' . $this->getCurrentTimestampSQL();
} }
if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) { if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) {
return " DEFAULT " . $this->getCurrentTimeSQL(); return ' DEFAULT ' . $this->getCurrentTimeSQL();
} }
if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) { if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) {
return " DEFAULT " . $this->getCurrentDateSQL(); return ' DEFAULT ' . $this->getCurrentDateSQL();
} }
if ($type instanceof Types\BooleanType) { if ($type instanceof Types\BooleanType) {
return " DEFAULT '" . $this->convertBooleans($default) . "'"; return " DEFAULT '" . $this->convertBooleans($default) . "'";
} }
return " DEFAULT '" . $default . "'"; return ' DEFAULT ' . $this->quoteStringLiteral($default);
} }
/** /**
......
<?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;
/**
* MariaDb reserved keywords list.
* @link https://mariadb.com/kb/en/the-mariadb-library/reserved-words/
*/
final class MariaDb102Keywords extends MySQLKeywords
{
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'MariaDb102';
}
/**
* {@inheritdoc}
*/
protected function getKeywords(): array
{
return [
'ACCESSIBLE',
'ADD',
'ALL',
'ALTER',
'ANALYZE',
'AND',
'AS',
'ASC',
'ASENSITIVE',
'BEFORE',
'BETWEEN',
'BIGINT',
'BINARY',
'BLOB',
'BOTH',
'BY',
'CALL',
'CASCADE',
'CASE',
'CHANGE',
'CHAR',
'CHARACTER',
'CHECK',
'COLLATE',
'COLUMN',
'CONDITION',
'CONSTRAINT',
'CONTINUE',
'CONVERT',
'CREATE',
'CROSS',
'CURRENT_DATE',
'CURRENT_TIME',
'CURRENT_TIMESTAMP',
'CURRENT_USER',
'CURSOR',
'DATABASE',
'DATABASES',
'DAY_HOUR',
'DAY_MICROSECOND',
'DAY_MINUTE',
'DAY_SECOND',
'DEC',
'DECIMAL',
'DECLARE',
'DEFAULT',
'DELAYED',
'DELETE',
'DESC',
'DESCRIBE',
'DETERMINISTIC',
'DISTINCT',
'DISTINCTROW',
'DIV',
'DOUBLE',
'DROP',
'DUAL',
'EACH',
'ELSE',
'ELSEIF',
'ENCLOSED',
'ESCAPED',
'EXISTS',
'EXIT',
'EXPLAIN',
'FALSE',
'FETCH',
'FLOAT',
'FLOAT4',
'FLOAT8',
'FOR',
'FORCE',
'FOREIGN',
'FROM',
'FULLTEXT',
'GENERATED',
'GET',
'GENERAL',
'GRANT',
'GROUP',
'HAVING',
'HIGH_PRIORITY',
'HOUR_MICROSECOND',
'HOUR_MINUTE',
'HOUR_SECOND',
'IF',
'IGNORE',
'IGNORE_SERVER_IDS',
'IN',
'INDEX',
'INFILE',
'INNER',
'INOUT',
'INSENSITIVE',
'INSERT',
'INT',
'INT1',
'INT2',
'INT3',
'INT4',
'INT8',
'INTEGER',
'INTERVAL',
'INTO',
'IO_AFTER_GTIDS',
'IO_BEFORE_GTIDS',
'IS',
'ITERATE',
'JOIN',
'KEY',
'KEYS',
'KILL',
'LEADING',
'LEAVE',
'LEFT',
'LIKE',
'LIMIT',
'LINEAR',
'LINES',
'LOAD',
'LOCALTIME',
'LOCALTIMESTAMP',
'LOCK',
'LONG',
'LONGBLOB',
'LONGTEXT',
'LOOP',
'LOW_PRIORITY',
'MASTER_BIND',
'MASTER_HEARTBEAT_PERIOD',
'MASTER_SSL_VERIFY_SERVER_CERT',
'MATCH',
'MAXVALUE',
'MEDIUMBLOB',
'MEDIUMINT',
'MEDIUMTEXT',
'MIDDLEINT',
'MINUTE_MICROSECOND',
'MINUTE_SECOND',
'MOD',
'MODIFIES',
'NATURAL',
'NO_WRITE_TO_BINLOG',
'NOT',
'NULL',
'NUMERIC',
'ON',
'OPTIMIZE',
'OPTIMIZER_COSTS',
'OPTION',
'OPTIONALLY',
'OR',
'ORDER',
'OUT',
'OUTER',
'OUTFILE',
'PARTITION',
'PRECISION',
'PRIMARY',
'PROCEDURE',
'PURGE',
'RANGE',
'READ',
'READ_WRITE',
'READS',
'REAL',
'RECURSIVE',
'REFERENCES',
'REGEXP',
'RELEASE',
'RENAME',
'REPEAT',
'REPLACE',
'REQUIRE',
'RESIGNAL',
'RESTRICT',
'RETURN',
'REVOKE',
'RIGHT',
'RLIKE',
'ROWS',
'SCHEMA',
'SCHEMAS',
'SECOND_MICROSECOND',
'SELECT',
'SENSITIVE',
'SEPARATOR',
'SET',
'SHOW',
'SIGNAL',
'SLOW',
'SMALLINT',
'SPATIAL',
'SPECIFIC',
'SQL',
'SQL_BIG_RESULT',
'SQL_CALC_FOUND_ROWS',
'SQL_SMALL_RESULT',
'SQLEXCEPTION',
'SQLSTATE',
'SQLWARNING',
'SSL',
'STARTING',
'STORED',
'STRAIGHT_JOIN',
'TABLE',
'TERMINATED',
'THEN',
'TINYBLOB',
'TINYINT',
'TINYTEXT',
'TO',
'TRAILING',
'TRIGGER',
'TRUE',
'UNDO',
'UNION',
'UNIQUE',
'UNLOCK',
'UNSIGNED',
'UPDATE',
'USAGE',
'USE',
'USING',
'UTC_DATE',
'UTC_TIME',
'UTC_TIMESTAMP',
'VALUES',
'VARBINARY',
'VARCHAR',
'VARCHARACTER',
'VARYING',
'VIRTUAL',
'WHEN',
'WHERE',
'WHILE',
'WITH',
'WRITE',
'XOR',
'YEAR_MONTH',
'ZEROFILL',
];
}
}
<?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;
use Doctrine\DBAL\Types\BlobType;
use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\TextType;
use Doctrine\DBAL\Types\Type;
/**
* Provides the behavior, features and SQL dialect of the MariaDB 10.2 (10.2.7 GA) database platform.
*
* @author Vanvelthem Sébastien
* @link www.doctrine-project.org
*/
final class MariaDb1027Platform extends MySqlPlatform
{
/**
* {@inheritdoc}
*/
public function hasNativeJsonType(): bool
{
return true;
}
/**
* {@inheritdoc}
* @link https://mariadb.com/kb/en/library/json-data-type/
*/
public function getJsonTypeDeclarationSQL(array $field): string
{
return 'JSON';
}
/**
* {@inheritdoc}
*/
protected function getReservedKeywordsClass(): string
{
return Keywords\MariaDb102Keywords::class;
}
/**
* {@inheritdoc}
*/
protected function initializeDoctrineTypeMappings(): void
{
parent::initializeDoctrineTypeMappings();
$this->doctrineTypeMapping['json'] = Type::JSON;
}
/**
* @inheritdoc
*
* Since MariaDB 10.2.1 blob and text columns can have a default value.
* @link https://mariadb.com/kb/en/library/blob-and-text-data-types/
*/
protected function isDefaultValueSupportedForType(Type $field): bool
{
return true;
}
}
...@@ -26,6 +26,7 @@ use Doctrine\DBAL\Schema\Table; ...@@ -26,6 +26,7 @@ use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\BlobType; use Doctrine\DBAL\Types\BlobType;
use Doctrine\DBAL\Types\TextType; use Doctrine\DBAL\Types\TextType;
use Doctrine\DBAL\Types\Type;
/** /**
* The MySqlPlatform provides the behavior, features and SQL dialect of the * The MySqlPlatform provides the behavior, features and SQL dialect of the
...@@ -459,13 +460,24 @@ class MySqlPlatform extends AbstractPlatform ...@@ -459,13 +460,24 @@ class MySqlPlatform extends AbstractPlatform
return $sql; return $sql;
} }
/**
* Tells whether a field type supports declaration of a default value.
*
* MySQL (as of 5.7.19) does not support default values for Blob and Text
* columns while MariaDB 10.2.1 does.
*/
protected function isDefaultValueSupportedForType(Type $field): bool
{
return !($field instanceof TextType || $field instanceof BlobType);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getDefaultValueDeclarationSQL($field) public function getDefaultValueDeclarationSQL($field)
{ {
// Unset the default value if the given field definition does not allow default values. // Unset the default value if the given field type does not allow default values.
if ($field['type'] instanceof TextType || $field['type'] instanceof BlobType) { if (!$this->isDefaultValueSupportedForType($field['type'])) {
$field['default'] = null; $field['default'] = null;
} }
...@@ -583,7 +595,8 @@ class MySqlPlatform extends AbstractPlatform ...@@ -583,7 +595,8 @@ class MySqlPlatform extends AbstractPlatform
// Don't propagate default value changes for unsupported column types. // Don't propagate default value changes for unsupported column types.
if ($columnDiff->hasChanged('default') && if ($columnDiff->hasChanged('default') &&
count($columnDiff->changedProperties) === 1 && count($columnDiff->changedProperties) === 1 &&
($columnArray['type'] instanceof TextType || $columnArray['type'] instanceof BlobType) !$this->isDefaultValueSupportedForType($columnArray['type'])
//($columnArray['type'] instanceof TextType || $columnArray['type'] instanceof BlobType)
) { ) {
continue; continue;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
namespace Doctrine\DBAL\Schema; namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
...@@ -67,7 +68,7 @@ class MySqlSchemaManager extends AbstractSchemaManager ...@@ -67,7 +68,7 @@ class MySqlSchemaManager extends AbstractSchemaManager
{ {
foreach ($tableIndexes as $k => $v) { foreach ($tableIndexes as $k => $v) {
$v = array_change_key_case($v, CASE_LOWER); $v = array_change_key_case($v, CASE_LOWER);
if ($v['key_name'] == 'PRIMARY') { if ($v['key_name'] === 'PRIMARY') {
$v['primary'] = true; $v['primary'] = true;
} else { } else {
$v['primary'] = false; $v['primary'] = false;
...@@ -176,17 +177,25 @@ class MySqlSchemaManager extends AbstractSchemaManager ...@@ -176,17 +177,25 @@ class MySqlSchemaManager extends AbstractSchemaManager
break; break;
} }
$length = ((int) $length == 0) ? null : (int) $length; $length = $length !== null ? (int) $length : null;
$isNotNull = $tableColumn['null'] !== 'YES';
if ($this->_platform instanceof MariaDb1027Platform) {
$columnDefault = $this->getMariaDb1027ColumnDefault($this->_platform, $tableColumn['default'] ?? null);
} else {
$columnDefault = (isset($tableColumn['default'])) ? $tableColumn['default'] : null;
}
$options = [ $options = [
'length' => $length, 'length' => $length,
'unsigned' => (bool) (strpos($tableColumn['type'], 'unsigned') !== false), 'unsigned' => strpos($tableColumn['type'], 'unsigned') !== false,
'fixed' => (bool) $fixed, 'fixed' => (bool) $fixed,
'default' => isset($tableColumn['default']) ? $tableColumn['default'] : null, 'default' => $columnDefault,
'notnull' => (bool) ($tableColumn['null'] != 'YES'), 'notnull' => $isNotNull,
'scale' => null, 'scale' => null,
'precision' => null, 'precision' => null,
'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false), 'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false,
'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== ''
? $tableColumn['comment'] ? $tableColumn['comment']
: null, : null,
...@@ -206,6 +215,46 @@ class MySqlSchemaManager extends AbstractSchemaManager ...@@ -206,6 +215,46 @@ class MySqlSchemaManager extends AbstractSchemaManager
return $column; return $column;
} }
/**
* Return column default value for MariaDB >= 10.2.7 servers that is
* compatible with existing doctrine mysql implementation (unquoted literals)
*
* Since 10.2.7:
*
* 1. Column defaults stored in information_schema are now quoted
* to distinguish them from expressions (see MDEV-10134 for a what is an expression).
*
* @link https://mariadb.com/kb/en/library/information-schema-columns-table/
* @link https://jira.mariadb.org/browse/MDEV-13132
*
* 2. Quoted string defaults use double single quotes as escaping character in information_schema.
*
* @links https://mariadb.com/kb/en/library/string-literals/
*
* @param null|string $columnDefault default value as stored in information_schema for MariaDB >= 10.2.7
*/
private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?string $columnDefault): ?string {
if ($columnDefault === 'NULL' || $columnDefault === null) {
$defaultValue = null;
} elseif (strpos($columnDefault, "'") === 0) {
$defaultValue = stripslashes(
str_replace("''", "'",
preg_replace('/^\'(.*)\'$/', '$1', $columnDefault)
)
);
} elseif ($columnDefault === 'current_timestamp()') {
$defaultValue = $platform->getCurrentTimestampSQL();
} elseif ($columnDefault === 'curdate()') {
$defaultValue = $platform->getCurrentDateSQL();
} elseif ($columnDefault === 'curtime()') {
$defaultValue = $platform->getCurrentTimeSQL();
} else {
$defaultValue = $columnDefault;
}
return $defaultValue;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -215,10 +264,10 @@ class MySqlSchemaManager extends AbstractSchemaManager ...@@ -215,10 +264,10 @@ class MySqlSchemaManager extends AbstractSchemaManager
foreach ($tableForeignKeys as $value) { foreach ($tableForeignKeys as $value) {
$value = array_change_key_case($value, CASE_LOWER); $value = array_change_key_case($value, CASE_LOWER);
if (!isset($list[$value['constraint_name']])) { if (!isset($list[$value['constraint_name']])) {
if (!isset($value['delete_rule']) || $value['delete_rule'] == "RESTRICT") { if (!isset($value['delete_rule']) || $value['delete_rule'] === "RESTRICT") {
$value['delete_rule'] = null; $value['delete_rule'] = null;
} }
if (!isset($value['update_rule']) || $value['update_rule'] == "RESTRICT") { if (!isset($value['update_rule']) || $value['update_rule'] === "RESTRICT") {
$value['update_rule'] = null; $value['update_rule'] = null;
} }
......
...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\DriverException; ...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Driver\ExceptionConverterDriver; use Doctrine\DBAL\Driver\ExceptionConverterDriver;
use Doctrine\DBAL\VersionAwarePlatformDriver; use Doctrine\DBAL\VersionAwarePlatformDriver;
use Doctrine\Tests\DbalTestCase; use Doctrine\Tests\DbalTestCase;
use Throwable;
abstract class AbstractDriverTest extends DbalTestCase abstract class AbstractDriverTest extends DbalTestCase
{ {
...@@ -122,7 +121,17 @@ abstract class AbstractDriverTest extends DbalTestCase ...@@ -122,7 +121,17 @@ abstract class AbstractDriverTest extends DbalTestCase
} }
foreach ($data as $item) { foreach ($data as $item) {
self::assertSame($item[1], get_class($this->driver->createDatabasePlatformForVersion($item[0]))); self::assertSame($item[1], get_class($this->driver->createDatabasePlatformForVersion($item[0])),
sprintf(
"Expected platform for version %s should be '%s' %s",
$item[0],
$item[1],
($this->driver instanceof VersionAwarePlatformDriver
? 'expected: ' . get_class($this->driver->createDatabasePlatformForVersion($item[0]))
: 'see:' . $item[0]
)
));
} }
} }
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
namespace Doctrine\Tests\DBAL\Driver; namespace Doctrine\Tests\DBAL\Driver;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
use Doctrine\DBAL\Platforms\MySQL57Platform;
use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\MySqlSchemaManager; use Doctrine\DBAL\Schema\MySqlSchemaManager;
...@@ -55,16 +57,21 @@ class AbstractMySQLDriverTest extends AbstractDriverTest ...@@ -55,16 +57,21 @@ class AbstractMySQLDriverTest extends AbstractDriverTest
protected function getDatabasePlatformsForVersions() protected function getDatabasePlatformsForVersions()
{ {
return array( return array(
array('5.6.9', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('5.6.9', MySqlPlatform::class),
array('5.7', 'Doctrine\DBAL\Platforms\MySQL57Platform'), array('5.7', MySQL57Platform::class),
array('5.7.0', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('5.7.0', MySqlPlatform::class),
array('5.7.8', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('5.7.8', MySqlPlatform::class),
array('5.7.9', 'Doctrine\DBAL\Platforms\MySQL57Platform'), array('5.7.9', MySQL57Platform::class),
array('5.7.10', 'Doctrine\DBAL\Platforms\MySQL57Platform'), array('5.7.10', MySQL57Platform::class),
array('6', 'Doctrine\DBAL\Platforms\MySQL57Platform'), array('6', MySQL57Platform::class),
array('10.0.15-MariaDB-1~wheezy', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('10.0.15-MariaDB-1~wheezy', MySqlPlatform::class),
array('10.1.2a-MariaDB-a1~lenny-log', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('5.5.5-10.1.25-MariaDB', MySqlPlatform::class),
array('5.5.40-MariaDB-1~wheezy', 'Doctrine\DBAL\Platforms\MySqlPlatform'), array('10.1.2a-MariaDB-a1~lenny-log', MySqlPlatform::class),
array('5.5.40-MariaDB-1~wheezy', MySqlPlatform::class),
array('5.5.40-MariaDB-1~wheezy', MySqlPlatform::class),
array('5.5.5-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class),
array('10.2.8-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class),
array('10.2.8-MariaDB-1~lenny-log', MariaDb1027Platform::class)
); );
} }
......
...@@ -8,6 +8,7 @@ use Doctrine\DBAL\Schema\ForeignKeyConstraint; ...@@ -8,6 +8,7 @@ use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index; use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
abstract class AbstractMySQLPlatformTestCase extends AbstractPlatformTestCase abstract class AbstractMySQLPlatformTestCase extends AbstractPlatformTestCase
{ {
...@@ -907,4 +908,19 @@ abstract class AbstractMySQLPlatformTestCase extends AbstractPlatformTestCase ...@@ -907,4 +908,19 @@ abstract class AbstractMySQLPlatformTestCase extends AbstractPlatformTestCase
self::assertContains('bar', $sql); self::assertContains('bar', $sql);
self::assertNotContains('DATABASE()', $sql); self::assertNotContains('DATABASE()', $sql);
} }
public function testGetDefaultValueDeclarationSQLIsQuotedWithLiteral()
{
$field = [
'type' => Type::getType('string'),
'default' => "'O'Connor said: \"Hello\" \ \r'"
];
self::assertSame(sprintf(
" DEFAULT %s",
$this->_platform->quoteStringLiteral("'O'Connor said: \"Hello\" \ \r'")
),
$this->_platform->getDefaultValueDeclarationSQL($field)
);
}
} }
...@@ -526,7 +526,7 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase ...@@ -526,7 +526,7 @@ abstract class AbstractPlatformTestCase extends \Doctrine\Tests\DbalTestCase
{ {
// non-timestamp value will get single quotes // non-timestamp value will get single quotes
$field = array( $field = array(
'type' => 'string', 'type' => Type::getType('string'),
'default' => 'non_timestamp' 'default' => 'non_timestamp'
); );
......
<?php
namespace Doctrine\Tests\DBAL\Platforms;
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\Type;
class MariaDb1027PlatformTest extends AbstractMySQLPlatformTestCase
{
/**
* {@inheritdoc}
*/
public function createPlatform()
{
return new MariaDb1027Platform();
}
public function testHasNativeJsonType()
{
self::assertTrue($this->_platform->hasNativeJsonType());
}
public function testReturnsJsonTypeDeclarationSQL()
{
self::assertSame('JSON', $this->_platform->getJsonTypeDeclarationSQL([]));
}
public function testInitializesJsonTypeMapping()
{
self::assertTrue($this->_platform->hasDoctrineTypeMappingFor('json'));
self::assertSame(Type::JSON, $this->_platform->getDoctrineTypeMapping('json'));
}
/**
* Overrides AbstractMySQLPlatformTestCase::testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes()
*/
public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes()
{
$table = new Table("text_blob_default_value");
$table->addColumn('def_text', 'text', array('default' => 'def'));
$table->addColumn('def_blob', 'blob', array('default' => 'def'));
self::assertSame(
array('CREATE TABLE text_blob_default_value (def_text LONGTEXT DEFAULT \'def\' NOT NULL, def_blob LONGBLOB DEFAULT \'def\' NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'),
$this->_platform->getCreateTableSQL($table)
);
$diffTable = clone $table;
$diffTable->changeColumn('def_text', array('default' => 'def'));
$diffTable->changeColumn('def_blob', array('default' => 'def'));
$comparator = new Comparator();
self::assertFalse($comparator->diffTable($table, $diffTable));
}
}
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="../../vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="mysqli"/>
<var name="db_host" value="localhost" />
<var name="db_username" value="travis" />
<var name="db_password" value="" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="3306"/>
<var name="tmpdb_type" value="mysqli"/>
<var name="tmpdb_host" value="localhost" />
<var name="tmpdb_username" value="travis" />
<var name="tmpdb_password" value="" />
<var name="tmpdb_port" value="3306"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment