@@ -419,13 +419,15 @@ defmodule Ecto.Adapters.MyXQL do
419419 case File . read ( path ) do
420420 { :ok , contents } ->
421421 args = [
422- "--execute" ,
423- "SET FOREIGN_KEY_CHECKS = 0; " <> contents <> "; SET FOREIGN_KEY_CHECKS = 1" ,
422+ "--silent" ,
423+ "--batch" ,
424+ "--unbuffered" ,
425+ "--init-command=SET FOREIGN_KEY_CHECKS = 0;" ,
424426 "--database" ,
425427 config [ :database ]
426428 ]
427429
428- case run_with_cmd ( "mysql" , config , args ) do
430+ case run_with_port ( "mysql" , config , args , contents ) do
429431 { _output , 0 } -> { :ok , path }
430432 { output , _ } -> { :error , output }
431433 end
@@ -497,6 +499,46 @@ defmodule Ecto.Adapters.MyXQL do
497499 "please guarantee it is available before running ecto commands"
498500 end
499501
502+ { args , env } = args_env ( opts , opt_args )
503+
504+ cmd_opts =
505+ cmd_opts
506+ |> Keyword . put_new ( :stderr_to_stdout , true )
507+ |> Keyword . update ( :env , env , & Enum . concat ( env , & 1 ) )
508+
509+ System . cmd ( cmd , args , cmd_opts )
510+ end
511+
512+ defp run_with_port ( cmd , opts , opt_args , contents ) do
513+ abs_cmd = System . find_executable ( cmd )
514+
515+ unless abs_cmd do
516+ raise "could not find executable `#{ cmd } ` in path, " <>
517+ "please guarantee it is available before running ecto commands"
518+ end
519+
520+ abs_cmd = String . to_charlist ( abs_cmd )
521+ { args , env } = args_env ( opts , opt_args )
522+
523+ port_opts = [
524+ :use_stdio ,
525+ :exit_status ,
526+ :binary ,
527+ :hide ,
528+ :stderr_to_stdout ,
529+ env: validate_env ( env ) ,
530+ args: args
531+ ]
532+
533+ port = Port . open ( { :spawn_executable , abs_cmd } , port_opts )
534+ Port . command ( port , contents )
535+ # Use this as a signal to close the port since we cannot
536+ # send an exit command to mysql in batch mode
537+ Port . command ( port , ";SELECT '__ECTO_EOF__';\n " )
538+ collect_output ( port , "" )
539+ end
540+
541+ defp args_env ( opts , opt_args ) do
500542 env =
501543 if password = opts [ :password ] do
502544 [ { "MYSQL_PWD" , password } ]
@@ -525,11 +567,36 @@ defmodule Ecto.Adapters.MyXQL do
525567 protocol
526568 ] ++ user_args ++ opt_args
527569
528- cmd_opts =
529- cmd_opts
530- |> Keyword . put_new ( :stderr_to_stdout , true )
531- |> Keyword . update ( :env , env , & Enum . concat ( env , & 1 ) )
570+ { args , env }
571+ end
532572
533- System . cmd ( cmd , args , cmd_opts )
573+ defp validate_env ( enum ) do
574+ Enum . map ( enum , fn
575+ { k , nil } ->
576+ { String . to_charlist ( k ) , false }
577+
578+ { k , v } ->
579+ { String . to_charlist ( k ) , String . to_charlist ( v ) }
580+
581+ other ->
582+ raise ArgumentError , "invalid environment key-value #{ inspect ( other ) } "
583+ end )
584+ end
585+
586+ defp collect_output ( port , acc ) do
587+ receive do
588+ { ^ port , { :data , data } } ->
589+ acc = acc <> data
590+
591+ if acc =~ "__ECTO_EOF__" do
592+ Port . close ( port )
593+ { acc , 0 }
594+ else
595+ collect_output ( port , acc )
596+ end
597+
598+ { ^ port , { :exit_status , status } } ->
599+ { acc , status }
600+ end
534601 end
535602end
0 commit comments