@@ -72,7 +72,7 @@ def _upgrade_mysql() -> None:
7272 op .drop_constraint (fk ['name' ], table_name , type_ = 'foreignkey' )
7373
7474 # Step 2: Alter columns to BIGINT
75- _alter_columns_to_bigint ()
75+ _alter_columns_to_bigint_mysql ()
7676
7777 # Step 3: Recreate FKs
7878 for table_name , fks in fk_info .items ():
@@ -90,6 +90,65 @@ def _upgrade_postgresql() -> None:
9090 _alter_columns_to_bigint ()
9191
9292
93+ def _is_bigint_type (sqlalchemy_type ) -> bool :
94+ """Check if a reflected SQLAlchemy type is BIGINT."""
95+ return "BIGINT" in str (sqlalchemy_type ).upper ()
96+
97+
98+ def _alter_columns_to_bigint_mysql ():
99+ """MySQL-optimized BIGINT conversion.
100+
101+ Combine changes per table to reduce table rebuilds and skip columns
102+ that are already BIGINT (resume-friendly after interrupted runs).
103+ """
104+ bind = op .get_bind ()
105+ inspector = inspect (bind )
106+
107+ # Avoid waiting for a very long default metadata-lock timeout.
108+ op .execute (sa .text ("SET SESSION lock_wait_timeout = 120" ))
109+
110+ table_specs = [
111+ ('admins' , [('id' , False , True )]),
112+ ('core_configs' , [('id' , False , True )]),
113+ ('groups' , [('id' , False , True )]),
114+ ('hosts' , [('id' , False , True )]),
115+ ('inbounds' , [('id' , False , True )]),
116+ ('user_templates' , [('id' , False , True )]),
117+ ('settings' , [('id' , False , True )]),
118+ ('system' , [('id' , False , True )]),
119+ ('nodes' , [('id' , False , True ), ('core_config_id' , True , False )]),
120+ ('users' , [('id' , False , True ), ('admin_id' , True , False )]),
121+ ('admin_usage_logs' , [('id' , False , True ), ('admin_id' , False , False )]),
122+ ('node_stats' , [('id' , False , True ), ('node_id' , False , False )]),
123+ ('node_usages' , [('id' , False , True ), ('node_id' , True , False )]),
124+ ('node_user_usages' , [('id' , False , True ), ('user_id' , False , False ), ('node_id' , True , False )]),
125+ ('node_usage_reset_logs' , [('id' , False , True ), ('node_id' , False , False )]),
126+ ('notification_reminders' , [('id' , False , True ), ('user_id' , False , False )]),
127+ ('user_usage_logs' , [('id' , False , True ), ('user_id' , True , False )]),
128+ ('user_subscription_updates' , [('id' , False , True ), ('user_id' , False , False )]),
129+ ('next_plans' , [('id' , False , True ), ('user_id' , False , False ), ('user_template_id' , True , False )]),
130+ ('inbounds_groups_association' , [('inbound_id' , False , False ), ('group_id' , False , False )]),
131+ ('users_groups_association' , [('user_id' , False , False ), ('groups_id' , False , False )]),
132+ ('template_group_association' , [('user_template_id' , True , False ), ('group_id' , True , False )]),
133+ ]
134+
135+ for table_name , columns in table_specs :
136+ reflected_columns = {column ['name' ]: column for column in inspector .get_columns (table_name )}
137+ alter_clauses = []
138+ for column_name , nullable , autoincrement in columns :
139+ reflected = reflected_columns .get (column_name )
140+ if reflected and _is_bigint_type (reflected ['type' ]):
141+ continue
142+
143+ clause = f"MODIFY COLUMN `{ column_name } ` BIGINT { 'NULL' if nullable else 'NOT NULL' } "
144+ if autoincrement :
145+ clause += " AUTO_INCREMENT"
146+ alter_clauses .append (clause )
147+
148+ if alter_clauses :
149+ op .execute (sa .text (f"ALTER TABLE `{ table_name } ` { ', ' .join (alter_clauses )} " ))
150+
151+
93152def _alter_columns_to_bigint ():
94153 """Alter all ID columns from INTEGER to BIGINT"""
95154 # Parent tables - all primary keys are NOT NULL with autoincrement
0 commit comments