Skip to content

Commit

Permalink
no issue - fix mysql decimal and float type cast
Browse files Browse the repository at this point in the history
  • Loading branch information
pounard committed Apr 24, 2024
1 parent e5b4ecb commit e0022bb
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.6.1

* [fix] Fix MySQL 5.7 `decimal` and `float` type cast.

## 1.6.0

* [feature] ⭐️ Add `MakinaCorpus\QueryBuilder\BridgeFactory` for creating
Expand Down
20 changes: 20 additions & 0 deletions src/Platform/Writer/MySQL8Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use MakinaCorpus\QueryBuilder\Expression\Raw;
use MakinaCorpus\QueryBuilder\Expression\Row;
use MakinaCorpus\QueryBuilder\Platform\Type\MySQL8TypeConverter;
use MakinaCorpus\QueryBuilder\Type\InternalType;
use MakinaCorpus\QueryBuilder\Type\Type;
use MakinaCorpus\QueryBuilder\Type\TypeConverter;
use MakinaCorpus\QueryBuilder\Writer\WriterContext;

Expand Down Expand Up @@ -38,6 +40,24 @@ protected function doFormatInsertExcludedItem($expression): Expression
return $expression;
}

/**
* Same code as MySQL 5.7 but drops the DECIMAL since MySQL >= 8.0 supports
* the FLOAT type cast.
*/
#[\Override]
protected function doFormatCastType(Type $type, WriterContext $context): ?string
{
if ($type->isText()) {
return 'CHAR';
}
// Do not use "unsigned" on behalf of the user, or it would proceed
// accidentally to transparent data alteration.
if (\in_array($type->internal, [InternalType::INT, InternalType::INT_BIG, InternalType::INT_SMALL, InternalType::INT_TINY])) {
return 'SIGNED';
}
return null;
}

/**
* MySQL VALUES syntax is:
* VALUES ROW(?, ?), ROW(?, ?), ...
Expand Down
33 changes: 26 additions & 7 deletions src/Platform/Writer/MySQLWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,28 @@ protected function doFormatUpdateSetWithTableName(WriterContext $context, string
return $inner;
}

/**
* Compute MySQL cast type.
*
* Because MySQL doesn't like consistency and standard, they need specific
* expressions for CAST instead of usual type names.
*/
protected function doFormatCastType(Type $type, WriterContext $context): ?string
{
if ($type->isText()) {
return 'CHAR';
}
// Do not use "unsigned" on behalf of the user, or it would proceed
// accidentally to transparent data alteration.
if (\in_array($type->internal, [InternalType::INT, InternalType::INT_BIG, InternalType::INT_SMALL, InternalType::INT_TINY])) {
return 'SIGNED';
}
if (\in_array($type->internal, [InternalType::FLOAT, InternalType::FLOAT_BIG, InternalType::FLOAT_SMALL, InternalType::DECIMAL])) {
return 'DECIMAL';
}
return null;
}

/**
* MySQL and types, seriously. Be conservative and fix user basic
* errors, but do not attempt to do too much magic and let unknown
Expand All @@ -393,16 +415,13 @@ protected function doFormatUpdateSetWithTableName(WriterContext $context, string
protected function doFormatCastExpression(string $expressionString, string|Type $type, WriterContext $context): string
{
$type = Type::create($type);
$typeString = $this->typeConverter->getSqlTypeName($type);

// Do not use "unsigned" on behalf of the user, or it would proceed
// accidentally to transparent data alteration.
if (\in_array($type->internal, [InternalType::INT, InternalType::INT_BIG, InternalType::INT_SMALL, InternalType::INT_TINY])) {
$typeString = 'SIGNED';
} else if ($type->isText()) {
$typeString = 'CHAR';
$typeString = $this->doFormatCastType($type, $context);
if (null === $typeString) {
$typeString = $this->typeConverter->getSqlTypeName($type);
}

// This will not work with MySQL 5.7 and previous, beware.
if ($type->array) {
$typeString .= ' ARRAY';
}
Expand Down

0 comments on commit e0022bb

Please sign in to comment.