julien-duponchelle / python-mysql-replication

Pure Python Implementation of MySQL replication protocol build on top of PyMYSQL
2.33k stars 679 forks source link

field type timestamp default '0000-00-00 00:00:00' parse to sql can't import to mysql server #305

Open zxb4221 opened 5 years ago

zxb4221 commented 5 years ago

field type timestamp default '0000-00-00 00:00:00', when field value is '0000-00-00 00:00:00', python-mysql-replication parse the field value to '1970-01-01 08:00:00' which can't import to mysql server with a error: 1292, "Incorrect datetime value: '1970-01-01 08:00:00' for column 'promotion_begintime' at row 1"

source code:

elif column.type == FIELD_TYPE.TIMESTAMP2: values[name] = self.__add_fsp_to_time( datetime.datetime.fromtimestamp( self.packet.read_int_be_by_size(4)), column)

datetime.datetime.fromtimestamp(0) will return '1970-01-01 08:00:00'

rspadim commented 4 years ago

0000-00-00 is an invalid date

change the destination server with proper sql_mode variable, or change it to 0000-01-01 (month 0 and day 0 does not exists)

telemmaite commented 4 years ago

0000-00-00 dates exist for a convenience reason in MySQL and indeed there are modes to forbid them but also there are connectors which handle/translate them to NULL, why not do the same here?

The special “zero” date '0000-00-00' can be stored and retrieved as '0000-00-00'. When a '0000-00-00' date is used through Connector/ODBC, it is automatically converted to NULL because ODBC cannot handle that kind of date.

Month 0 and day 0 do exist and the doc provides example for them.

MySQL permits you to store dates where the day or month and day are zero. This is convenient if you want to store a birthdate in a DATE column and you know only part of the date. To disallow zero month or day parts in dates, enable the NO_ZERO_IN_DATE mode.

Yes, there is an option to force legal dates:

To have MySQL check all dates and accept only legal dates (unless overridden by IGNORE), set the sql_mode system variable to "NO_ZERO_IN_DATE,NO_ZERO_DATE".

Though..how feasible is that on 10 year old production setup just because 0000 dates are not handled here?

rspadim commented 4 years ago

https://dev.mysql.com/doc/refman/8.0/en/datetime.html

Invalid DATE, DATETIME, or TIMESTAMP values are converted to the “zero” value of the appropriate type ('0000-00-00' or '0000-00-00 00:00:00'), if the SQL mode permits this conversion. The precise behavior depends on which if any of strict SQL mode and the NO_ZERO_DATE SQL mode are enabled; see Section 5.1.11, “Server SQL Modes”.

rspadim commented 4 years ago

datetime.datetime.fromtimestamp(0) will return '1970-01-01 08:00:00'

This “from timestamp” isn’t considering the server timezone or maybe the field timezone

rspadim commented 4 years ago

https://github.com/noplay/python-mysql-replication/blob/511b42c8ac2c1682a6e2fd4d6691658245b57987/pymysqlreplication/row_event.py#L279