phinx icon indicating copy to clipboard operation
phinx copied to clipboard

Lower-case default value of TIMESTAMP causes error

Open t2hog opened this issue 3 years ago • 3 comments

We have discovered a bug that occurs when using Phinx with MariaDB, and trying to update a TIMESTAMP column with current_timestamp() as default value.

The error: PDOException: SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'createdAt'

We have found the reason the error occurs. MariaDB is defaulting the TIMESTAMP-value to current_timestamp() in lower-case. There is Phinx code to NOT quote CURRENT_TIMESTAMP in src/Phinx/Db/Adapter/PdoAdapter.php:getDefaultValueDefinition(), but because it only handles upper-case, this lower-case default value is quoted anyway.

elseif (is_string($default) && strpos($default, 'CURRENT_TIMESTAMP') !== 0) {
            // Ensure a defaults of CURRENT_TIMESTAMP(3) is not quoted.
            $default = $this->getConnection()->quote($default);
}

The suggested fix: Adding strtolower around $default and 'CURRENT_TIMESTAMP' in src/Phinx/Db/Adapter/PdoAdapter.php:getDefaultValueDefinition().

} elseif (is_string($default) && strpos(strtolower($default), strtolower('CURRENT_TIMESTAMP')) !== 0) {
            // Ensure a defaults of CURRENT_TIMESTAMP(3) is not quoted.
            $default = $this->getConnection()->quote($default);
}

Is it possible to get this small fix done? :-) Or is there another workaround?

Apparently, MariaDB has changed the default from CURRENT_TIMESTAMP to current_timestamp() from version 10.2.3. (https://mariadb.com/kb/en/now/#description )

Our migration causing the error:

private const TABLE_NAME = 'DocumentRef';
private const NEW_COLUMN_NAME = 'incomingAt';
private const OLD_COLUMN_NAME = 'createdAt';

public function change()
{
    $this->table(self::TABLE_NAME)
          ->renameColumn(self::OLD_COLUMN_NAME, self::NEW_COLUMN_NAME)
          ->update();
 }

The generated SQL causing the error:

"ALTER TABLE `DocumentRef` CHANGE COLUMN `incomingAt` `createdAt` timestamp NOT NULL  DEFAULT           
 'current_timestamp()' COMMENT '';"

t2hog avatar Oct 06 '22 11:10 t2hog

You can open pull request with suggested fix.

You can use stripos instead of strpos, the strtolower is unnecessary.

garas avatar Oct 06 '22 15:10 garas

Thanks for your reply. I'll look into doing a pull request. In the meantime, we managed to solve it by creating a custom adapter and doing the necessary change of the default value, before calling the original getDefaultValueDefinition() function.

Aha, yeah, stripos is a better idea. :-)

t2hog avatar Oct 07 '22 12:10 t2hog

Maybe the solution in here would be for phinx to not quote functions.
In this case someone might want to use the functionality of precision described in here https://mariadb.com/kb/en/current_timestamp/

In a similar case we want to include a default value for a json in mysql which would be better using the functions included https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html

pe1uca avatar Feb 28 '23 14:02 pe1uca