Skip to content

Commit

Permalink
Merge pull request #1778 from MasterOdin/mysql_enum
Browse files Browse the repository at this point in the history
fix using quoted and escaped values for mysql enums
  • Loading branch information
dereuromark committed May 10, 2020
2 parents cb3122c + 9a9965c commit dcc3e51
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 5 deletions.
70 changes: 65 additions & 5 deletions src/Phinx/Db/Adapter/MysqlAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,51 @@ public function getPhinxType($sqlTypeDef)
];

if ($type === static::PHINX_TYPE_ENUM || $type === static::PHINX_TYPE_SET) {
$phinxType['values'] = explode("','", trim($matches[6], "()'"));
$values = trim($matches[6], "()");
$phinxType['values'] = [];
$opened = false;
$escaped = false;
$wasEscaped = false;
$value = '';
$valuesLength = strlen($values);
for ($i = 0; $i < $valuesLength; $i++) {
$char = $values[$i];
if ($char === "'" && !$opened) {
$opened = true;
} elseif (
!$escaped
&& ($i + 1) < $valuesLength
&& (
$char === "'" && $values[$i + 1] === "'"
|| $char === "\\" && $values[$i + 1] === "\\"
)
) {
$escaped = true;
} elseif ($char === "'" && $opened && !$escaped) {
$phinxType['values'][] = $value;
$value = '';
$opened = false;
} elseif (($char === "'" || $char === "\\") && $opened && $escaped) {
$value .= $char;
$escaped = false;
$wasEscaped = true;
} elseif ($opened) {
if ($values[$i - 1] === "\\" && !$wasEscaped) {
if ($char === 'n') {
$char = "\n";
} elseif ($char === 'r') {
$char = "\r";
} elseif ($char === 't') {
$char = "\t";
}
if ($values[$i] !== $char) {
$value = substr($value, 0, strlen($value) - 1);
}
}
$value .= $char;
$wasEscaped = false;
}
}
}

return $phinxType;
Expand All @@ -1133,7 +1177,12 @@ public function createDatabase($name, $options = [])
$charset = $options['charset'] ?? 'utf8';

if (isset($options['collation'])) {
$this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
$this->execute(sprintf(
'CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`',
$name,
$charset,
$options['collation']
));
} else {
$this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
}
Expand Down Expand Up @@ -1189,16 +1238,27 @@ protected function getColumnSqlDefinition(Column $column)
$def .= '(' . $sqlType['limit'] . ')';
}
if (($values = $column->getValues()) && is_array($values)) {
$def .= "('" . implode("', '", $values) . "')";
$def .= "(" . implode(", ", array_map(function ($value) {
// we special case NULL as it's not actually allowed an enum value,
// and we want MySQL to issue an error on the create statement, but
// quote coerces it to an empty string, which will not error
return $value === null ? 'NULL' : $this->getConnection()->quote($value);
}, $values)) . ")";
}

$def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
$def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
$def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '';
$def .= !$column->isSigned() && isset($this->signedColumnTypes[$column->getType()]) ? ' unsigned' : '';
$def .= $column->isNull() ? ' NULL' : ' NOT NULL';

if (
version_compare($this->getAttribute(\PDO::ATTR_SERVER_VERSION), '8') > -1
&& in_array($column->getType(), [static::PHINX_TYPE_GEOMETRY, static::PHINX_TYPE_POINT, static::PHINX_TYPE_LINESTRING, static::PHINX_TYPE_POLYGON])
&& in_array($column->getType(), [
static::PHINX_TYPE_GEOMETRY,
static::PHINX_TYPE_POINT,
static::PHINX_TYPE_LINESTRING,
static::PHINX_TYPE_POLYGON,
])
&& !is_null($column->getSrid())
) {
$def .= " SRID {$column->getSrid()}";
Expand Down
12 changes: 12 additions & 0 deletions tests/Phinx/Db/Adapter/MysqlAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,9 @@ public function columnsProvider()
['column20', 'uuid', []],
['column21', 'set', ['values' => ['one', 'two']]],
['column22', 'enum', ['values' => ['three', 'four']]],
['enum_quotes', 'enum', ['values' => [
"'", '\'\n', '\\', ',', '', "\\\n", "\\n", "\n", "\r", "\r\n", '/', ',,', "\t",
]]],
['column23', 'bit', []],
];
}
Expand Down Expand Up @@ -1542,6 +1545,15 @@ public function testEnumColumnValuesFilledUpFromSchema()
$this->assertEquals(['one', 'two'], $enumColumn->getValues());
}

public function testEnumColumnWithNullValue()
{
$table = new \Phinx\Db\Table('table1', [], $this->adapter);
$table->addColumn('enum_column', 'enum', ['values' => ['one', 'two', null]]);

$this->expectException(PDOException::class);
$table->save();
}

public function testHasColumn()
{
$table = new \Phinx\Db\Table('table1', [], $this->adapter);
Expand Down

0 comments on commit dcc3e51

Please sign in to comment.