Skip to content
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

Review MySQL default null and nullable column definition #14974

Merged
merged 9 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Fixed
- Fixed `Phalcon\Mvc\Model\Query\Builder::getPhql` to add single quote between string value on a simple condition. [#14874](https://github.com/phalcon/cphalcon/issues/14874) [@jenovateurs](https://github.com/jenovateurs)
- Fixed schema manipulation in `Phalcon\Db\Dialect\Mysql`, remove unnecessary `NULL` in column definition, unquote numerical defaults. [#14888](https://github.com/phalcon/cphalcon/pull/14888) [@pfz](https://github.com/pfz)
- Fixed schema manipulation in `Phalcon\Db\Dialect\Mysql`, unquote numerical defaults. [#14888](https://github.com/phalcon/cphalcon/pull/14888) [@pfz](https://github.com/pfz)
sergeyklay marked this conversation as resolved.
Show resolved Hide resolved
- Fixed recognizing language operators inside Volt's echo mode (`{{ ... }}`) [#14476](https://github.com/phalcon/cphalcon/issues/14476)
- Fixed `Tag::friendlyTitle` to correctly convert titles under MacOS and Windows [#14866](https://github.com/phalcon/cphalcon/issues/14866)
- Fixed the Volt compiler to no longer parse `cache` fragments and thus searching for the `viewCache` service (deprecated for v4) [#14907](https://github.com/phalcon/cphalcon/issues/14907)
Expand Down
80 changes: 53 additions & 27 deletions phalcon/Db/Dialect/Mysql.zep
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,31 @@ class Mysql extends Dialect
*/
public function addColumn(string! tableName, string! schemaName, <ColumnInterface> column) -> string
{
var afterPosition, defaultValue;
var afterPosition, defaultValue, upperDefaultValue;
string sql;

let sql = "ALTER TABLE " . this->prepareTable(tableName, schemaName) . " ADD `" . column->getName() . "` " . this->getColumnDefinition(column);

if column->isNotNull() {
let sql .= " NOT NULL";
} else {
// This is required for some types like TIMESTAMP
// Query won't be executed if NULL wasn't specified
// Even if DEFAULT NULL was specified
let sql .= " NULL";
}

if column->hasDefault() {
let defaultValue = column->getDefault();
let upperDefaultValue = strtoupper(defaultValue);

if memstr(strtoupper(defaultValue), "CURRENT_TIMESTAMP") || is_int(defaultValue) || is_float(defaultValue) {
if memstr(upperDefaultValue, "CURRENT_TIMESTAMP") || memstr(upperDefaultValue, "NULL") || is_int(defaultValue) || is_float(defaultValue) {
let sql .= " DEFAULT " . defaultValue;
} else {
let sql .= " DEFAULT \"" . addcslashes(defaultValue, "\"") . "\"";
}
}

if column->isNotNull() {
let sql .= " NOT NULL";
}

if column->isAutoIncrement() {
let sql .= " AUTO_INCREMENT";
}
Expand Down Expand Up @@ -135,7 +141,7 @@ class Mysql extends Dialect
{
var temporary, options, table, columns, column, indexes, index,
reference, references, indexName, columnLine, indexType, onDelete,
onUpdate, defaultValue;
onUpdate, defaultValue, upperDefaultValue;
array createLines;
string indexSql, referenceSql, sql;

Expand Down Expand Up @@ -166,30 +172,32 @@ class Mysql extends Dialect
for column in columns {
let columnLine = "`" . column->getName() . "` " . this->getColumnDefinition(column);

/**
* Add a NOT NULL clause
*/
if column->isNotNull() {
let columnLine .= " NOT NULL";
} else {
// This is required for some types like TIMESTAMP
// Query won't be executed if NULL wasn't specified
// Even if DEFAULT NULL was specified
let columnLine .= " NULL";
}

/**
* Add a Default clause
*/
if column->hasDefault() {
let defaultValue = column->getDefault();
let upperDefaultValue = strtoupper(defaultValue);

if (defaultValue === null) {
let columnLine .= " DEFAULT NULL";
if memstr(upperDefaultValue, "CURRENT_TIMESTAMP") || memstr(upperDefaultValue, "NULL") || is_int(defaultValue) || is_float(defaultValue) {
let columnLine .= " DEFAULT " . defaultValue;
} else {
if memstr(strtoupper(defaultValue), "CURRENT_TIMESTAMP") || is_int(defaultValue) || is_float(defaultValue) {
let columnLine .= " DEFAULT " . defaultValue;
} else {
let columnLine .= " DEFAULT \"" . addcslashes(defaultValue, "\"") . "\"";
}
let columnLine .= " DEFAULT \"" . addcslashes(defaultValue, "\"") . "\"";
}
}

/**
* Add a NOT NULL clause
*/
if column->isNotNull() {
let columnLine .= " NOT NULL";
}

/**
* Add an AUTO_INCREMENT clause
*/
Expand Down Expand Up @@ -448,6 +456,10 @@ class Mysql extends Dialect
let columnSql .= "DATETIME";
}

if column->getSize() > 0 {
let columnSql .= this->getColumnSize(column);
}

break;

case Column::TYPE_DECIMAL:
Expand Down Expand Up @@ -560,13 +572,21 @@ class Mysql extends Dialect
let columnSql .= "TIME";
}

if column->getSize() > 0 {
let columnSql .= this->getColumnSize(column);
}

break;

case Column::TYPE_TIMESTAMP:
if empty columnSql {
let columnSql .= "TIMESTAMP";
}

if column->getSize() > 0 {
let columnSql .= this->getColumnSize(column);
}

break;

case Column::TYPE_TINYBLOB:
Expand Down Expand Up @@ -672,7 +692,7 @@ class Mysql extends Dialect
*/
public function modifyColumn(string! tableName, string! schemaName, <ColumnInterface> column, <ColumnInterface> currentColumn = null) -> string
{
var afterPosition, defaultValue, columnDefinition;
var afterPosition, defaultValue, upperDefaultValue, columnDefinition;
string sql;

let columnDefinition = this->getColumnDefinition(column),
Expand All @@ -688,20 +708,26 @@ class Mysql extends Dialect
let sql .= " MODIFY `" . column->getName() . "` " . columnDefinition;
}

if column->isNotNull() {
let sql .= " NOT NULL";
} else {
// This is required for some types like TIMESTAMP
// Query won't be executed if NULL wasn't specified
// Even if DEFAULT NULL was specified
let sql .= " NULL";
}

if column->hasDefault() {
let defaultValue = column->getDefault();
let upperDefaultValue = strtoupper(defaultValue);

if memstr(strtoupper(defaultValue), "CURRENT_TIMESTAMP") || is_int(defaultValue) || is_float(defaultValue) {
if memstr(upperDefaultValue, "CURRENT_TIMESTAMP") || memstr(upperDefaultValue, "NULL") || is_int(defaultValue) || is_float(defaultValue) {
let sql .= " DEFAULT " . defaultValue;
} else {
let sql .= " DEFAULT \"" . addcslashes(defaultValue, "\"") . "\"";
}
}

if column->isNotNull() {
let sql .= " NOT NULL";
}

if column->isAutoIncrement() {
let sql .= " AUTO_INCREMENT";
}
Expand Down
51 changes: 43 additions & 8 deletions tests/integration/Db/Dialect/Mysql/AddColumnCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,72 @@ class AddColumnCest
* Tests Phalcon\Db\Adapter\Pdo\Mysql :: addColumn()
*
* @author Phalcon Team <[email protected]>
* @since 2020-02-27
* @since 2020-05-02
Jeckerson marked this conversation as resolved.
Show resolved Hide resolved
*/
public function dbAdapterPdoMysqlAddColumn(IntegrationTester $I)
{
$I->wantToTest('Db\Adapter\Pdo\Mysql - addColumn()');

$additions = [
[
new Column(
'numeric_val',
[
'type' => Column::TYPE_FLOAT,
'default' => 21.42,
'notNull' => true,
]
),
'ALTER TABLE `test` ADD `numeric_val` FLOAT NOT NULL DEFAULT 21.42',
],
[
new Column(
'null_int',
[
'type' => Column::TYPE_INTEGER,
'size' => 11,
'notNull' => false,
'after' => 'numeric_val',
]
),
'ALTER TABLE `test` ADD `null_int` INT(11) NULL AFTER `numeric_val`',
],
[
new Column(
'created_at',
[
'type' => Column::TYPE_TIMESTAMP,
'default' => "CURRENT_TIMESTAMP",
'notNull' => true,
'after' => 'null_int',
]
),
'ALTER TABLE `test` ADD `created_at` TIMESTAMP NOT NULL ' .
'DEFAULT CURRENT_TIMESTAMP AFTER `null_int`',
],
[
new Column(
'updated_at',
[
'type' => Column::TYPE_TIMESTAMP,
'default' => "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP",
'notNull' => false,
'notNull' => true,
'after' => 'created_at',
]
),
'ALTER TABLE `test` ADD `updated_at` TIMESTAMP ' .
'ALTER TABLE `test` ADD `updated_at` TIMESTAMP NOT NULL ' .
'DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER `created_at`',
],
[
new Column(
'numeric_val',
'deleted_at',
[
'type' => Column::TYPE_FLOAT,
'default' => 21.42,
'notNull' => true,
'type' => Column::TYPE_TIMESTAMP,
'notNull' => false,
'after' => 'updated_at',
]
),
'ALTER TABLE `test` ADD `numeric_val` FLOAT DEFAULT 21.42 NOT NULL AFTER `updated_at`',
'ALTER TABLE `test` ADD `deleted_at` TIMESTAMP NULL AFTER `updated_at`',
],
];

Expand Down
43 changes: 36 additions & 7 deletions tests/integration/Db/Dialect/Mysql/CreateTableCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CreateTableCest
* Tests Phalcon\Db\Adapter\Pdo\Mysql :: createTable()
*
* @author Phalcon Team <[email protected]>
* @since 2020-02-27
* @since 2020-05-02
*/
public function dbAdapterPdoMysqlCreateTable(IntegrationTester $I)
{
Expand All @@ -42,21 +42,47 @@ public function dbAdapterPdoMysqlCreateTable(IntegrationTester $I)
'first' => true,
]
),
new Column(
'numeric_val',
[
'type' => Column::TYPE_FLOAT,
'default' => 21.42,
'notNull' => true,
]
),
new Column(
'null_int',
[
'type' => Column::TYPE_INTEGER,
'size' => 11,
'notNull' => false,
'after' => 'numeric_val',
]
),
new Column(
'created_at',
[
'type' => Column::TYPE_TIMESTAMP,
'default' => "CURRENT_TIMESTAMP",
'notNull' => true,
'after' => 'created_at',
]
),
new Column(
'updated_at',
[
'type' => Column::TYPE_TIMESTAMP,
'default' => "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP",
'notNull' => false,
'notNull' => true,
'after' => 'created_at',
]
),
new Column(
'numeric_val',
'deleted_at',
[
'type' => Column::TYPE_FLOAT,
'type' => Column::TYPE_TIMESTAMP,
'notNull' => false,
'after' => 'updated_at',
'after' => 'created_at',
]
),
],
Expand All @@ -70,8 +96,11 @@ public function dbAdapterPdoMysqlCreateTable(IntegrationTester $I)
$expected = <<<SQL
CREATE TABLE `test` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`numeric_val` FLOAT,
`numeric_val` FLOAT NOT NULL DEFAULT 21.42,
`null_int` INT(11) NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` TIMESTAMP NULL,
PRIMARY KEY (`id`)
)
SQL;
Expand Down
Loading