@@ -142,14 +142,14 @@ def analyze_columns(schema: Schema) -> dict:
142142 for (table_name ,) in tables :
143143 # Get all columns for this table
144144 columns_query = """
145- SELECT COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, COLUMN_COMMENT
145+ SELECT COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE
146146 FROM information_schema.COLUMNS
147147 WHERE TABLE_SCHEMA = %s
148148 AND TABLE_NAME = %s
149149 """
150150 columns = connection .query (columns_query , args = (schema .database , table_name )).fetchall ()
151151
152- for column_name , column_type , data_type , comment in columns :
152+ for column_name , column_type , data_type , comment , is_nullable in columns :
153153 comment = comment or ""
154154
155155 # Check if column already has a type label (starts with :type:)
@@ -167,6 +167,7 @@ def analyze_columns(schema: Schema) -> dict:
167167 "column" : column_name ,
168168 "native_type" : column_type ,
169169 "comment" : comment ,
170+ "is_nullable" : is_nullable == "YES" ,
170171 }
171172
172173 if is_external :
@@ -270,9 +271,10 @@ def migrate_columns(
270271 new_comment_escaped = new_comment .replace ("\\ " , "\\ \\ " ).replace ("'" , "\\ '" )
271272
272273 # Generate ALTER TABLE statement
274+ not_null = "" if col ["is_nullable" ] else " NOT NULL"
273275 sql = (
274276 f"ALTER TABLE `{ db_name } `.`{ table_name } ` "
275- f"MODIFY COLUMN `{ col ['column' ]} ` { col ['native_type' ]} "
277+ f"MODIFY COLUMN `{ col ['column' ]} ` { col ['native_type' ]} { not_null } "
276278 f"COMMENT '{ new_comment_escaped } '"
277279 )
278280 result ["sql_statements" ].append (sql )
@@ -365,7 +367,7 @@ def analyze_blob_columns(schema: Schema) -> list[dict]:
365367 for (table_name ,) in tables :
366368 # Get column information for each table
367369 columns_query = """
368- SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT
370+ SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT, IS_NULLABLE
369371 FROM information_schema.COLUMNS
370372 WHERE TABLE_SCHEMA = %s
371373 AND TABLE_NAME = %s
@@ -374,7 +376,7 @@ def analyze_blob_columns(schema: Schema) -> list[dict]:
374376
375377 columns = connection .query (columns_query , args = (schema .database , table_name )).fetchall ()
376378
377- for column_name , column_type , comment in columns :
379+ for column_name , column_type , comment , is_nullable in columns :
378380 # Check if comment already has a codec type (starts with :type:)
379381 has_codec = comment and comment .startswith (":" )
380382
@@ -385,6 +387,7 @@ def analyze_blob_columns(schema: Schema) -> list[dict]:
385387 "column_type" : column_type ,
386388 "current_comment" : comment or "" ,
387389 "needs_migration" : not has_codec ,
390+ "is_nullable" : is_nullable == "YES" ,
388391 }
389392 )
390393
@@ -447,9 +450,10 @@ def generate_migration_sql(
447450 db_name , table_name = col ["table_name" ].split ("." )
448451
449452 # Generate ALTER TABLE statement
453+ not_null = "" if col .get ("is_nullable" , True ) else " NOT NULL"
450454 sql = (
451455 f"ALTER TABLE `{ db_name } `.`{ table_name } ` "
452- f"MODIFY COLUMN `{ col ['column_name' ]} ` { col ['column_type' ]} "
456+ f"MODIFY COLUMN `{ col ['column_name' ]} ` { col ['column_type' ]} { not_null } "
453457 f"COMMENT '{ new_comment_escaped } '"
454458 )
455459 sql_statements .append (sql )
0 commit comments