3939from mycli .constants import (
4040 DEFAULT_HOST ,
4141 DEFAULT_WIDTH ,
42+ ER_MUST_CHANGE_PASSWORD ,
4243 HOME_URL ,
4344 ISSUES_URL ,
4445)
5556from mycli .packages .ptoolkit .history import FileHistoryWithTimestamp
5657from mycli .packages .special .utils import format_uptime , get_ssl_version , get_uptime , get_warning_count
5758from mycli .packages .sql_utils import (
59+ extract_new_password ,
5860 is_dropping_database ,
5961 is_mutating ,
62+ is_password_change ,
63+ is_sandbox_allowed ,
6064 is_select ,
6165 need_completion_refresh ,
6266 need_completion_reset ,
@@ -132,7 +136,8 @@ def _show_startup_banner(
132136 if mycli .less_chatty :
133137 return
134138
135- print (sqlexecute .server_info )
139+ if sqlexecute .server_info is not None :
140+ print (sqlexecute .server_info )
136141 print ('mycli' , mycli_package .__version__ )
137142 print (SUPPORT_INFO )
138143 if random .random () <= 0.25 :
@@ -232,8 +237,6 @@ def get_prompt(
232237) -> str :
233238 sqlexecute = mycli .sqlexecute
234239 assert sqlexecute is not None
235- assert sqlexecute .server_info is not None
236- assert sqlexecute .server_info .species is not None
237240 if mycli .login_path and mycli .login_path_as_host :
238241 prompt_host = mycli .login_path
239242 elif sqlexecute .host is not None :
@@ -250,7 +253,8 @@ def get_prompt(
250253 string = string .replace ('\\ h' , prompt_host or '(none)' )
251254 string = string .replace ('\\ H' , short_prompt_host or '(none)' )
252255 string = string .replace ('\\ d' , sqlexecute .dbname or '(none)' )
253- string = string .replace ('\\ t' , sqlexecute .server_info .species .name )
256+ species_name = sqlexecute .server_info .species .name if sqlexecute .server_info and sqlexecute .server_info .species else 'MySQL'
257+ string = string .replace ('\\ t' , species_name )
254258 string = string .replace ('\\ n' , '\n ' )
255259 string = string .replace ('\\ D' , now .strftime ('%a %b %d %H:%M:%S %Y' ))
256260 string = string .replace ('\\ m' , now .strftime ('%M' ))
@@ -615,6 +619,14 @@ def _one_iteration(
615619 mycli .echo (str (e ), err = True , fg = 'red' )
616620 return
617621
622+ if mycli .sandbox_mode and not is_sandbox_allowed (text ):
623+ mycli .echo (
624+ "ERROR 1820: You must reset your password using ALTER USER or SET PASSWORD before executing this statement." ,
625+ err = True ,
626+ fg = 'red' ,
627+ )
628+ return
629+
618630 if mycli .destructive_warning :
619631 destroy = confirm_destructive_query (mycli .destructive_keywords , text )
620632 if destroy is None :
@@ -674,20 +686,44 @@ def _one_iteration(
674686 mycli .echo ('Not Yet Implemented.' , fg = 'yellow' )
675687 except pymysql .OperationalError as e1 :
676688 mycli .logger .debug ('Exception: %r' , e1 )
677- if e1 .args [0 ] in (2003 , 2006 , 2013 ):
689+ if e1 .args [0 ] == ER_MUST_CHANGE_PASSWORD :
690+ mycli .sandbox_mode = True
691+ mycli .echo (
692+ "ERROR 1820: You must reset your password using ALTER USER or SET PASSWORD before executing this statement." ,
693+ err = True ,
694+ fg = 'red' ,
695+ )
696+ elif e1 .args [0 ] in (2003 , 2006 , 2013 ):
678697 if not mycli .reconnect ():
679698 return
680699 _one_iteration (mycli , state , text )
681700 return
682-
683- mycli .logger .error ('sql: %r, error: %r' , text , e1 )
684- mycli .logger .error ('traceback: %r' , traceback .format_exc ())
685- mycli .echo (str (e1 ), err = True , fg = 'red' )
701+ else :
702+ mycli .logger .error ('sql: %r, error: %r' , text , e1 )
703+ mycli .logger .error ('traceback: %r' , traceback .format_exc ())
704+ mycli .echo (str (e1 ), err = True , fg = 'red' )
686705 except Exception as e :
687706 mycli .logger .error ('sql: %r, error: %r' , text , e )
688707 mycli .logger .error ('traceback: %r' , traceback .format_exc ())
689708 mycli .echo (str (e ), err = True , fg = 'red' )
690709 else :
710+ if mycli .sandbox_mode and is_password_change (text ):
711+ new_password = extract_new_password (text )
712+ if new_password is not None :
713+ sqlexecute .password = new_password
714+ try :
715+ sqlexecute .connect ()
716+ mycli .sandbox_mode = False
717+ mycli .echo ("Password changed successfully. Reconnected." , err = True , fg = 'green' )
718+ mycli .refresh_completions ()
719+ except Exception as e :
720+ mycli .sandbox_mode = False
721+ mycli .echo (
722+ f"Password changed but reconnection failed: { e } \n Please restart mycli with your new password." ,
723+ err = True ,
724+ fg = 'yellow' ,
725+ )
726+
691727 if is_dropping_database (text , sqlexecute .dbname ):
692728 sqlexecute .dbname = None
693729 sqlexecute .connect ()
@@ -756,7 +792,7 @@ def main_repl(mycli: 'MyCli') -> None:
756792 state = ReplState ()
757793
758794 mycli .configure_pager ()
759- if mycli .smart_completion :
795+ if mycli .smart_completion and not mycli . sandbox_mode :
760796 mycli .refresh_completions ()
761797
762798 history = _create_history (mycli )
0 commit comments