-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MariaDB 10.2 initial support #2825
Conversation
@@ -178,12 +178,19 @@ protected function _getPortableTableColumnDefinition($tableColumn) | |||
|
|||
$length = ((int) $length == 0) ? null : (int) $length; | |||
|
|||
$isNotNull = ($tableColumn['null'] !== 'YES'); | |||
$columnDefault = (isset($tableColumn['default'])) ? $tableColumn['default'] : null; | |||
if ($columnDefault === 'NULL' && !$isNotNull) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a bit weird. How does MariaDB 10.2.7 distinct between default NULL
and 'NULL'
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I was wondering too... looks they tried to fix something else and got a regression. Possible they will revert this... in this case we could eventually check the server version, and apply the fix selectively for a while.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are not going to revert it... they are planing to enforce it as a standard in all upcoming versions, see https://jira.mariadb.org/browse/MDEV-13341
Quoted from above link:
It was an intentional change...
We've tried to reduce the damage by doing this change only in 10.2 (not in 10.1 or 10.0 or 5.5) and by keeping old behavior of SHOW COLUMNS (because it's non-standard, so there're no rules for it). Applications can switch to SHOW COLUMNS easily. Or adapt to use the new behavior, because old one cannot describe default values unambiguously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was wondering, but now I've tested and figured out there's no problem at all. To the question of @morozov , how to disambiguate ? actually very simple:
CREATE TABLE `my_table` (
`column_1` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`column_2` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'NULL'
) ENGINE = InnoDB;
If you read the information_schema
, like
SELECT * FROM `COLUMNS` where TABLE_SCHEMA = 'mytest'
You'll see defaults are NULL
and 'NULL'
. So no problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@belgattitude my question was about the information schema, not about the actual tables. What does it contain for the columns above?
'Type' => 'datetime', | ||
'Null' => 'YES', | ||
'Key' => '', | ||
'Default' => 'NULL', // MariaDB 10.2.7 return 'NULL' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to have this as a functional test. It's an implementation detail of a given DB version, not really an expectation of the DBAL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, but too new to the project to figure out quickly how the test suite runs. Just mocked as a first step.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested solved the issue with mariadb 10.2.7... suggesting to change the comment in line 184 from "// for mariadb 10.2.7" to "// for mariadb 10.2+"
Thanks @auviagroup , changed the comment to >= 10.2.7 instead. Don't know the policy of doctrine concerning code... maybe I'll remove. |
@@ -178,12 +179,27 @@ protected function _getPortableTableColumnDefinition($tableColumn) | |||
|
|||
$length = ((int) $length == 0) ? null : (int) $length; | |||
|
|||
|
|||
$isNotNull = (bool) ($tableColumn['null'] !== 'YES'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comparison result is already boolean. I see it's copied from the existing code, but anyways.
|
||
// For MariaDB >= 10.2.7 | ||
if ($this->_platform instanceof MariaDb102Platform) { | ||
$columnDefault = (!$isNotNull && $tableColumn['default'] === 'NULL') ? null : $tableColumn['default']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that the column is NOT NULL
but the default is NULL
? Why do we check !$isNotNull
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You right, looks they fixed it:
SQL_MODE has been changed; in particular, NOT NULL fields with no default will no longer fall back to a dummy value for inserts which do not specify a value for that field.
(try col INT(10) NOT NULL DEFAULT NULL
in previous versions, to be sure. MariaDb 10.2 is ok)
} | ||
} else { | ||
// Regular MySQL | ||
$columnDefault = (isset($tableColumn['default'])) ? $tableColumn['default'] : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that the 'default'
key does not exist in the column definition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, but it was originally like that. I guess it was made on purpose.
For me we can replace by $tableColumn['default'] === null
. But I would not add this to the current P/R. Not sure about all mysql versions.
$table = new Table("text_null_default_value"); | ||
$table->addColumn('txt_def_null', 'string', ['notnull' => false, 'default' => null]); | ||
$table->addColumn('txt_def_null_as_string', 'string', ['notnull' => false, 'default' => 'NULL']); | ||
$table->addColumn('txt_def_null_as_quoted_string', 'string', ['notnull' => false, 'default' => "NULL"]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different from the field above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely reworked now, thanks
$table->addColumn('txt_def_null', 'string', ['notnull' => false, 'default' => null]); | ||
$table->addColumn('txt_def_null_as_string', 'string', ['notnull' => false, 'default' => 'NULL']); | ||
$table->addColumn('txt_def_null_as_quoted_string', 'string', ['notnull' => false, 'default' => "NULL"]); | ||
$table->addColumn('txt_def_null_as_doublequoted_string', 'string', ['notnull' => false, 'default' => '"NULL"']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd replace this with a single-quoted string since string defaults will be single-quoted in information_schema
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know, I was wondering... I'll fix
|
||
$majorVersion = $versionParts['major']; | ||
$minorVersion = isset($versionParts['minor']) ? $versionParts['minor'] : 0; | ||
$patchVersion = isset($versionParts['patch']) ? $versionParts['patch'] : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GIven the regexps above, how can 'minor'
and 'patch'
keys be not set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch, thanks
|
||
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; | ||
// Will catch things like '10.2.8-MariaDB-1~lenny-log' | ||
preg_match('/(?P<major>\d{1,2})\.(?P<minor>\d{1,2})\.(?P<patch>\d+)/', $version, $firstMatch); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why restrict the number of digits to 2 in major
and minor
but not in the patch
? \d
looks reasonable to me in all cases.
// Will catch things like '10.2.8-MariaDB-1~lenny-log' | ||
preg_match('/(?P<major>\d{1,2})\.(?P<minor>\d{1,2})\.(?P<patch>\d+)/', $version, $firstMatch); | ||
// Will catch things like '5.5.5-10.2.8-MariaDB-10.2.8+maria~xenial-log' | ||
preg_match('/\-(?P<major>10)\.(?P<minor>\d{1,2})\.(?P<patch>\d+)/', $version, $secondMatch); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which of the '10.2.8'
is this supposed to match? The one after the '5.5.5'
or after 'MariaDB'
? Why only the major version of 10
is considered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both expressions are almost the same with the exception of the leading dash. Could they be combined together?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but for now I would consider to create a separate class or method (will be needed for mysqli
support in MysqliConnection)... Yes I'm not happy with detection, but wanted something to start. It's in the todo. Once a better detection is ready I'll need your feedback.
throw DBALException::invalidPlatformVersionSpecified( | ||
$version, | ||
'MariaDB-<major_version>.<minor_version>.<patch_version>' . | ||
'or <major_version>.<minor_version>.<patch_version>-MariaDB' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come the 'MariaDB'
marker is part of the version string requirement in the error message but not in the regexp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, anyway I want to move those tests somewhere else (and at the same time support mysqli detection, see todo list)
|
||
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; | ||
if (version_compare($version, '10.2.7', '>=')) { | ||
return new MariaDb102Platform(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to name the class MariaDb1027Platform
? Otherwise, it would be confusing that a connection to MariaDB 10.2.6 doesn't use the MariaDb102Platform
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmmmh, seems too much for me. Fix was released in 10.2.7, the first stable (GA) was 10.2.6. Will be forgotten soon. I guess no distributions include the first stable, and 10.2.6 was too much buggy for people to not update anyway.
Thanks a lot @morozov !!! I've updated the P/R with some of your remarks. Not yet 100% ready, but I'll see what's possible to improve tonight. See also my previous comment with the roadmap |
Hi @morozov , maybe you can point me to some direction. To be able to work with mysqli driver, I will have to change If you look in MysqliConnection: public function getServerVersion()
{
$majorVersion = floor($this->_conn->server_version / 10000);
$minorVersion = floor(($this->_conn->server_version - $majorVersion * 10000) / 100);
$patchVersion = floor($this->_conn->server_version - $majorVersion * 10000 - $minorVersion * 100);
return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
} This won't work with things like So I'm thinking to make something like: public function getServerVersion()
{
$serverInfo = $this->_conn->get_server_info();
if (false !== stripos($serverInfo, 'mariadb')) { // optional, prevent one more method call if makes sense
$version = MariaDbVersionStringParserOrBetterName::getVersion($serverInfo);
if ($version !== null) {
return $version;
}
}
$majorVersion = floor($this->_conn->server_version / 10000);
$minorVersion = floor(($this->_conn->server_version - $majorVersion * 10000) / 100);
$patchVersion = floor($this->_conn->server_version - $majorVersion * 10000 - $minorVersion * 100);
return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
} What would be a good name and namespace for |
FYI, see my last comment in https://jira.mariadb.org/browse/MDEV-13341?focusedCommentId=99353&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-99353 about version reasoning and BC in Mariadb. |
According to the comment, the client just needs to strip the Something like: $serverInfo = $this->_conn->get_server_info();
if (false !== stripos($serverInfo, 'mariadb')) {
$serverInfo = str_replace('5.5.5-', '', $serverInfo);
}
// parse $serverInfo |
LGTM, I'll make a P/R... just trying to setup mariadb 10.2 on Travis and I'll commit |
Will fix this bug too: #2819. |
Will also fix: nextcloud/server#6193 and belgattitude/openstore-schema-core#1 |
looks you're working crazily on doctrine ;) Feel free to contact me about this P/R, if you need change, infos... I'll try my best to respond quickly. Keep up the great work and thanks a lot. |
if ('5' === $majorVersion && '7' === $minorVersion && null === $patchVersion) { | ||
$patchVersion = '9'; | ||
} | ||
if (!preg_match('/^(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/', strtolower($version), $versionParts)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entire block needs to be moved to a private
method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, just added AbstractMySQLDriver::getMariaDbMysqlVersionNumber($version)
.
if (version_compare($version, '10.2.7', '>=')) { | ||
return new MariaDb102Platform(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this block not supposed to return here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not want to change too much from the original code, all that is less than 10.2.7 will fallback to the last statement getDatabasePlatform()
which actually sets the `MysqlPlatform' by default. I was not very happy with this neither, but tried to mimic what was done for Mysql57. Wait a bit I'll commit some changes soon, it will be more clear.
|
||
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; | ||
if (!preg_match('/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/', $version, $versionParts)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again to be moved to a private
method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, just added AbstractMySQLDriver::getOracleMysqlVersionNumber($version)
.
if (version_compare($version, '5.7.9', '>=')) { | ||
return new MySQL57Platform(); | ||
if ('5' === $majorVersion && '7' === $minorVersion && null === $patchVersion) { | ||
$patchVersion = '9'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't overwrite an existing version, please: use a new variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be.
); | ||
} | ||
$majorVersion = $versionParts['major']; | ||
$minorVersion = isset($versionParts['minor']) ? $versionParts['minor'] : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
??
$this->_sm->dropAndCreateTable($table); | ||
|
||
$onlineTable = $this->_sm->listTableDetails("test_column_defaults_with_table"); | ||
$this->assertNull($onlineTable->getColumn('col0')->getDefault()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's self::assertNull
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I never noticed assertNull, assertEquals... were static. I fixed. Thx
/** | ||
* For testing MariaDB 10.2+ / MySQL differences | ||
*/ | ||
public function testColumnDefaultsWithCreate() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
: void
. Opening brace on next line.
} | ||
|
||
/** | ||
* For testing MariaDB 10.2+ / MySQL differences |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this description in the method name instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to testColumnDefaultsWithCreateAreValidForMySqlAndMariaDb102
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afterwards thinking, this test is newly introduced when working on MariaDB. Actually it's valid for both anyway. I'll cleanup the description completely. But good to know about method naming
$this->assertEquals(0, $t->getColumn('col9')->getDefault()); | ||
$this->assertEquals('He"ll"o world', $t->getColumn('col10')->getDefault()); | ||
|
||
// @todo mariadb returns 'current_timestamp()' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this? Blocker for merging?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm, let me one day more to see what I can do... From what I've seen it's not easy... The two syntaxes are accepted by mysql/mariadb. The only change is that with Mariadb, whatever syntax you used to create the table, it will always return current_timestamp()
(don't remember where I read it, but from what I tested it's working like that).
@@ -817,6 +817,7 @@ public function testChangeColumnsTypeWithDefaultValue() | |||
|
|||
$columns = $this->_sm->listTableColumns($tableName); | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert
I tried to reflect your advices (at least as far as I understood them ;). Note that I had to update the Regarding the 'current_timestamp()' issue, I'll try to find a solution in a couple of days. As this behaviour was not yet tested, I fear to introduce BC with mysql. I'll let you know the possible risks (I guess I will need to alias It took me a while to get into the project conventions and CI setup, hope I'll be less messy next time. Thanks for your feedbacks and the time you spend on this project. Fantastic design :) |
As I'm leaving for a short 6 days break on wednesday 6th, I can possibly fix some things tomorrow... or when I come back. Regarding
As this patch fixes a lot of others too (travis, proper mariadb detection, null and default quoted values in information_schema), you may want to merge it sooner. Feel free to do, I can also make a separate p/r for All the best |
Special thanks for @morozov too... without him this P/R would have not happened ! |
yes, big thanks @morozov @belgattitude @lcobucci |
@geeksareforlife What did you do to get your migrations to run, per this bug? |
@mpash I never had an issue with the migrations running, just with the migration creation when the schema was compared to the database. So at the moment I am just removing all the alter table statements that are generated, but that obviously makes an entry point for errors - I have had at least two occasions where I removed too many statements and had to go back! |
so, @belgattitude when do you think this patch can be released and tagged ? :) |
TYPO3 is also looking forward to a new release so we can update the dependencies to have a release with this fix. Issue at TYPO3 referencing this: https://forge.typo3.org/issues/82023 |
No idea. But in the meantime can you check everything is working for you ? FYI, I had a report about some issues with dev-master on doctrine/orm#6565 (look at the end of the thread). But finally it appears to be something unrelated. Anyway, always good to test. Just try a schema creation/update with your project.
And let me know. |
@belgattitude @lcobucci : this release will be really appreciated by MariaDb users! |
I can confirm @belgattitude that it fixes my problem. Once the big migration has been generated and executed (a lot of |
@belgattitude @lcobucci @tristanbes I also confirm diffs are OK with these fixes |
Well, @belgattitude it seems that it's not entirely fixed.
The only issue it seems to be fixed is that without touching the schema, the migrations are not longer generated when without this patch, it constantly generates diffs |
hey @tristan, I cannot test right now cause I'm traveling for about a month without laptop. I'm not totally sure to understand your problem, if there is you'll have to wait till 27dec or try a pr. |
Let me rephrase it @belgattitude:
AFTER this patch
So 2/ is not fixed, and is really a pain in the *** when generating diff for your application |
@tristanbes, weird. I remember having done that without problem. but not sure. /cc @Bukashk0zzz because he might help to test. I've done some debugging with him recently. doctrine/orm#6565. others might help too.it might be something else. testing dev-master includes more than my patch. could be nice to look deeper. at least see if it does not happen with mysql too. |
Made test for the case that @tristanbes discarded and all works ok no problem detected. Code: Bukashk0zzz/dbal-test#3 Test: |
@Bukashk0zzz : Mhhh, You have tested it against MariaDB 10.3. I'm having this issue for MariaDB 10.2. ( |
@tristanbes No problem. Update to use MariaDB 10.2 |
I found what causes the problem. When specifying the doctrine:
dbal:
server_version: 10.2 As soon as I remove |
that makes sense. if you want to use server_version, you should set 10.2.7 instead of 10.2. the schema change appeared after 10.2.6. this will be confusing, but autodetection works. |
Hello :-) |
@tristanbes you guessed it right: no 2.7 yet ;-) It will arrive, we're just not focused on it at the moment. |
I get the feeling that there would be multiple people that would be really happy to see this merged... Is there any way we can encourage this to receive some focus? 😄 |
Not really, no. Edit: to clarify (sorry, I'm just multitasking like crazy, didn't want to come off as rude), we're not working on pushing DBAL 2.7 out the door for now, but rather focused on stabelizing the ORM 3.0 development branch. |
Could we get this into the 2.6-branch maybe? Another project currently using DBAL 2.6.x would be happy to have at least initial MariaDB 10.2-support. |
PSA: Additions are ONLY EVER for minor/major releases. Stop asking. |
Initial support for MariaDB 10.2.7+.
Updated: Title updated from 'MariaDB 10.2 support (will also fix version detection), version detection should be considered as new feature.
Features
2. MariaDb 10.2 supportBLOB/TEXT
defaults values (since 10.2.1).Update: Removed from this P/R... will be made available in a subsequent P/R (due to architecture decision to be made - current doctrine implementation needs to be reworked)
3. MariaDb 10.2 supportJSON
type.Removed from P/R by @lcobucci, probably to reflect the fact that MariaDB alias JSON to MEDIUMTEXT
CURRENT_TIME
,CURRENT_DATE
as default values5. Default literal values must be escaped.Update: Removed from this PR in favor of #2850... Current doctrine implementation does not handle escaping of defaults (backslashes...), adding it in this P/R should be done for all platforms at once and thus introduce more BC-risks (bugs...). Implementing separately looks safer and should help having this P/R sooner. Both P/R can be done independently.
7. Support for MariaDB 10.2 reserved keywords.
8. Added MariaDB 10.2 in travis (both pdo_mysql and mysqli)
Possible BC-breaks:
None found. Since the extraction of defaults escaping in #2850, there should be no impact on other platforms.
Portability concerns
Issues that will be fixed by this P/R:
DBAL related:
ORM related:
Fix (or might fix) the following issues :
Other related open P/R