@@ -19,6 +19,7 @@ package migrationscripts
1919
2020import (
2121 "github.com/apache/incubator-devlake/core/context"
22+ "github.com/apache/incubator-devlake/core/dal"
2223 "github.com/apache/incubator-devlake/core/errors"
2324)
2425
@@ -31,14 +32,78 @@ func (*modifyFileMetaTable) Name() string {
3132func (* modifyFileMetaTable ) Up (basicRes context.BasicRes ) errors.Error {
3233 db := basicRes .GetDal ()
3334
34- // 修改 processed_time 列允许为 NULL
35- sql := "ALTER TABLE _tool_q_dev_s3_file_meta MODIFY processed_time DATETIME NULL"
36- err := db .Exec (sql )
37- if err != nil {
38- return errors .Default .Wrap (err , "failed to modify processed_time column" )
35+ // Target table and column
36+ tableName := "_tool_q_dev_s3_file_meta"
37+ columnName := "processed_time"
38+
39+ // If column doesn't exist, no migration needed, idempotent
40+ if ! db .HasColumn (tableName , columnName ) {
41+ return nil
3942 }
4043
41- return nil
44+ // Read column metadata to check if already nullable, return idempotently if already nullable
45+ var processedTimeNullable bool
46+ {
47+ cols , err := db .GetColumns (dal.DefaultTabler {Name : tableName }, func (cm dal.ColumnMeta ) bool {
48+ return cm .Name () == columnName
49+ })
50+ if err != nil {
51+ return errors .Default .Wrap (err , "failed to load column metadata for _tool_q_dev_s3_file_meta.processed_time" )
52+ }
53+ if len (cols ) == 0 {
54+ // If column is not visible in metadata, treat as no processing needed
55+ return nil
56+ }
57+ if nullable , ok := cols [0 ].Nullable (); ok {
58+ processedTimeNullable = nullable
59+ }
60+ }
61+ if processedTimeNullable {
62+ return nil
63+ }
64+
65+ // Execute compatible SQL by dialect
66+ switch db .Dialect () {
67+ case "postgres" :
68+ // PostgreSQL makes column nullable via DROP NOT NULL, without changing data type
69+ if err := db .Exec (
70+ "ALTER TABLE ? ALTER COLUMN ? DROP NOT NULL" ,
71+ dal.ClauseTable {Name : tableName },
72+ dal.ClauseColumn {Name : columnName },
73+ ); err != nil {
74+ return errors .Default .Wrap (err , "failed to drop NOT NULL on processed_time for postgres" )
75+ }
76+ return nil
77+ case "mysql" :
78+ // MySQL requires MODIFY COLUMN with original type specification, preserve original type as much as possible
79+ cols , err := db .GetColumns (dal.DefaultTabler {Name : tableName }, func (cm dal.ColumnMeta ) bool {
80+ return cm .Name () == columnName
81+ })
82+ if err != nil {
83+ return errors .Default .Wrap (err , "failed to load column metadata for mysql type preservation" )
84+ }
85+ columnTypeSql := "DATETIME"
86+ if len (cols ) > 0 {
87+ if ct , ok := cols [0 ].ColumnType (); ok && ct != "" {
88+ columnTypeSql = ct
89+ } else if dbt := cols [0 ].DatabaseTypeName (); dbt != "" {
90+ // DatabaseTypeName may return DATETIME, TIMESTAMP etc
91+ columnTypeSql = dbt
92+ }
93+ }
94+ alterSql := "ALTER TABLE ? MODIFY COLUMN ? " + columnTypeSql + " NULL"
95+ if err := db .Exec (
96+ alterSql ,
97+ dal.ClauseTable {Name : tableName },
98+ dal.ClauseColumn {Name : columnName },
99+ ); err != nil {
100+ return errors .Default .Wrap (err , "failed to modify processed_time to NULL for mysql" )
101+ }
102+ return nil
103+ default :
104+ // Other dialects are not forced to migrate for now, return idempotently
105+ return nil
106+ }
42107}
43108
44109func (* modifyFileMetaTable ) Version () uint64 {
0 commit comments