33
33
34
34
from alembic import op
35
35
from sqlalchemy .dialects import mysql
36
+ from sqlalchemy import text
36
37
import sqlalchemy as sa
37
38
38
39
39
40
def upgrade ():
40
41
conn = op .get_bind ()
41
42
if conn .dialect .name == 'mysql' :
42
43
conn .execute ("SET time_zone = '+00:00'" )
43
- cur = conn .execute ("SELECT @@explicit_defaults_for_timestamp" )
44
- res = cur .fetchall ()
45
- if res [0 ][0 ] == 0 :
46
- raise Exception ("Global variable explicit_defaults_for_timestamp needs to be on (1) for mysql" )
44
+ # @awilcox July 2018
45
+ # we only need to worry about explicit_defaults_for_timestamp if we have
46
+ # DATETIME columns that are NOT explicitly declared with NULL
47
+ # ... and we don't, all are explicit
48
+
49
+ # cur = conn.execute("SELECT @@explicit_defaults_for_timestamp")
50
+ # res = cur.fetchall()
51
+ # if res[0][0] == 0:
52
+ # raise Exception("Global variable explicit_defaults_for_timestamp needs to be on (1) for mysql")
47
53
48
54
op .alter_column (table_name = 'chart' , column_name = 'last_modified' , type_ = mysql .TIMESTAMP (fsp = 6 ))
49
55
@@ -53,7 +59,9 @@ def upgrade():
53
59
54
60
op .alter_column (table_name = 'dag_pickle' , column_name = 'created_dttm' , type_ = mysql .TIMESTAMP (fsp = 6 ))
55
61
56
- op .alter_column (table_name = 'dag_run' , column_name = 'execution_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
62
+ # NOTE(kwilson): See below.
63
+ op .alter_column (table_name = 'dag_run' , column_name = 'execution_date' , type_ = mysql .TIMESTAMP (fsp = 6 ),
64
+ nullable = False , server_default = text ('CURRENT_TIMESTAMP(6)' ))
57
65
op .alter_column (table_name = 'dag_run' , column_name = 'start_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
58
66
op .alter_column (table_name = 'dag_run' , column_name = 'end_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
59
67
@@ -76,7 +84,29 @@ def upgrade():
76
84
op .alter_column (table_name = 'task_fail' , column_name = 'start_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
77
85
op .alter_column (table_name = 'task_fail' , column_name = 'end_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
78
86
79
- op .alter_column (table_name = 'task_instance' , column_name = 'execution_date' , type_ = mysql .TIMESTAMP (fsp = 6 ), nullable = False )
87
+ # NOTE(kwilson)
88
+ #
89
+ # N.B. Here (and above) we explicitly set a default to the string literal `CURRENT_TIMESTAMP(6)` to avoid the
90
+ # default MySQL behavior for TIMESTAMP without `explicit_defaults_for_timestamp` turned on as stated here:
91
+ #
92
+ # "The first TIMESTAMP column in a table, if not explicitly declared with the NULL attribute or an explicit
93
+ # DEFAULT or ON UPDATE attribute, is automatically declared with the DEFAULT CURRENT_TIMESTAMP and
94
+ # ON UPDATE CURRENT_TIMESTAMP attributes." [0]
95
+ #
96
+ # Because of the "ON UPDATE CURRENT_TIMESTAMP" default, anytime the `task_instance` table is UPDATE'd without
97
+ # explicitly re-passing the current value for the `execution_date` column, it will end up getting clobbered with
98
+ # the current timestamp value which breaks `dag_run` <-> `task_instance` alignment and causes all sorts of
99
+ # scheduler and DB integrity breakage (because `execution_date` is part of the primary key).
100
+ #
101
+ # We unfortunately cannot turn `explicit_defaults_for_timestamp` on globally ourselves as is now technically
102
+ # required by Airflow [1], because this has to be set in the my.cnf and we don't control that in managed MySQL.
103
+ # A request to enable this fleet-wide has been made in MVP-18609.
104
+ #
105
+ # [0]: https://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp
106
+ # [1]: https://github.com/apache/incubator-airflow/blob/master/UPDATING.md#mysql-setting-required
107
+
108
+ op .alter_column (table_name = 'task_instance' , column_name = 'execution_date' , type_ = mysql .TIMESTAMP (fsp = 6 ),
109
+ nullable = False , server_default = text ('CURRENT_TIMESTAMP(6)' ))
80
110
op .alter_column (table_name = 'task_instance' , column_name = 'start_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
81
111
op .alter_column (table_name = 'task_instance' , column_name = 'end_date' , type_ = mysql .TIMESTAMP (fsp = 6 ))
82
112
op .alter_column (table_name = 'task_instance' , column_name = 'queued_dttm' , type_ = mysql .TIMESTAMP (fsp = 6 ))
0 commit comments