@@ -771,69 +771,229 @@ defmodule Ecto.Adapters.SQL do
771771 ## Callbacks
772772
773773 @ doc false
774- def __before_compile__ ( _driver , _env ) do
774+ def __before_compile__ ( driver , _env ) do
775775 quote do
776776 @ doc """
777- A convenience function for SQL-based repositories that executes the given query.
778-
779- See `Ecto.Adapters.SQL.query/4` for more information.
777+ Runs a custom SQL query.
778+
779+ If the query was successful, it will return an `:ok` tuple containing
780+ a map with at least two keys:
781+ * `:num_rows` - the number of rows affected
782+ * `:rows` - the result set as a list. `nil` may be returned
783+ instead of the list if the command does not yield any row
784+ as result (but still yields the number of affected rows,
785+ like a `delete` command without returning would)
786+
787+ ## Options
788+ * `:log` - When false, does not log the query
789+ * `:timeout` - Execute request timeout, accepts: `:infinity` (default: `15000`);
790+
791+ ## Examples
792+ iex> MyRepo.query("SELECT $1::integer + $2", [40, 2])
793+ {:ok, %{rows: [[42]], num_rows: 1}}
780794 """
795+ @ spec query ( iodata ( ) , Ecto.Adapters.SQL . query_params ( ) , Keyword . t ( ) ) ::
796+ { :ok , query_result ( ) } | { :error , Exception . t ( ) }
781797 def query ( sql , params \\ [ ] , opts \\ [ ] ) do
782798 Ecto.Adapters.SQL . query ( get_dynamic_repo ( ) , sql , params , opts )
783799 end
784800
785801 @ doc """
786- A convenience function for SQL-based repositories that executes the given query.
802+ Runs a custom SQL query.
787803
788- See `Ecto.Adapters.SQL. query!/4` for more information .
804+ Same as ` query/3` but raises on invalid queries .
789805 """
806+ @ spec query ( iodata ( ) , Ecto.Adapters.SQL . query_params ( ) , Keyword . t ( ) ) ::
807+ { :ok , query_result ( ) } | { :error , Exception . t ( ) }
790808 def query! ( sql , params \\ [ ] , opts \\ [ ] ) do
791809 Ecto.Adapters.SQL . query! ( get_dynamic_repo ( ) , sql , params , opts )
792810 end
793811
794812 @ doc """
795- A convenience function for SQL-based repositories that executes the given multi-result query.
813+ Runs a custom SQL query that returns multiple results on the given repo.
814+
815+ In case of success, it must return an `:ok` tuple containing
816+ a list of maps with at least two keys:
817+
818+ * `:num_rows` - the number of rows affected
819+
820+ * `:rows` - the result set as a list. `nil` may be returned
821+ instead of the list if the command does not yield any row
822+ as result (but still yields the number of affected rows,
823+ like a `delete` command without returning would)
824+
825+ ## Options
826+
827+ * `:log` - When false, does not log the query
828+ * `:timeout` - Execute request timeout, accepts: `:infinity` (default: `#{ @ timeout } `);
829+
830+ ## Examples
796831
797- See `Ecto.Adapters.SQL.query_many/4` for more information.
832+ iex> MyRepo.query_many("SELECT $1; SELECT $2;", [40, 2])
833+ {:ok, [%{rows: [[40]], num_rows: 1}, %{rows: [[2]], num_rows: 1}]}
798834 """
835+
836+ @ spec query_many ( iodata , query_params , Keyword . t ( ) ) ::
837+ { :ok , [ query_result ] } | { :error , Exception . t ( ) }
799838 def query_many ( sql , params \\ [ ] , opts \\ [ ] ) do
800839 Ecto.Adapters.SQL . query_many ( get_dynamic_repo ( ) , sql , params , opts )
801840 end
802841
803842 @ doc """
804- A convenience function for SQL-based repositories that executes the given multi-result query.
805-
806- See `Ecto.Adapters.SQL.query_many!/4` for more information.
843+ Same as `query_many/4` but raises on invalid queries.
807844 """
845+ @ spec query_many! ( iodata , query_params , Keyword . t ( ) ) ::
846+ [ query_result ]
808847 def query_many! ( sql , params \\ [ ] , opts \\ [ ] ) do
809848 Ecto.Adapters.SQL . query_many! ( get_dynamic_repo ( ) , sql , params , opts )
810849 end
811850
812851 @ doc """
813- A convenience function for SQL-based repositories that translates the given query to SQL.
852+ Converts the given query to SQL according to its kind and the
853+ adapter in the given repository.
854+
855+ ## Examples
856+
857+ The examples below are meant for reference. Each adapter will
858+ return a different result:
859+
860+ iex> MyRepo.to_sql(:all, Post)
861+ {"SELECT p.id, p.title, p.inserted_at, p.created_at FROM posts as p", []}
862+
863+ iex> MyRepo.to_sql(:update_all, from(p in Post, update: [set: [title: ^"hello"]]))
864+ {"UPDATE posts AS p SET title = $1", ["hello"]}
814865
815- See `Ecto.Adapters.SQL.to_sql/3` for more information.
816866 """
867+ @ spec to_sql ( :all | :update_all | :delete_all , Ecto.Queryable . t ( ) ) ::
868+ { String . t ( ) , query_params }
817869 def to_sql ( operation , queryable ) do
818870 Ecto.Adapters.SQL . to_sql ( operation , get_dynamic_repo ( ) , queryable )
819871 end
820872
821- @ doc """
822- A convenience function for SQL-based repositories that executes an EXPLAIN statement or similar
823- depending on the adapter to obtain statistics for the given query.
873+ case unquote ( driver ) do
874+ :postgrex ->
875+ @ doc """
876+ Executes an EXPLAIN statement or similar for the given query according to its kind and the
877+ adapter in the given repository.
824878
825- See `Ecto.Adapters.SQL.explain/4` for more information.
826- """
879+ ## Examples
880+
881+ iex> MyRepo.explain(:all, Post)
882+ "Seq Scan on posts p0 (cost=0.00..12.12 rows=1 width=443)"
883+
884+ # Shared opts
885+ iex> MyRepo.explain(:all, Post, analyze: true, timeout: 20_000)
886+ "Seq Scan on posts p0 (cost=0.00..11.70 rows=170 width=443) (actual time=0.013..0.013 rows=0 loops=1)\\ nPlanning Time: 0.031 ms\\ nExecution Time: 0.021 ms"
887+
888+ It's safe to execute it for updates and deletes, no data change will be committed:
889+
890+ iex> MyRepo.explain(:update_all, from(p in Post, update: [set: [title: "new title"]]))
891+ "Update on posts p0 (cost=0.00..11.70 rows=170 width=449)\\ n -> Seq Scan on posts p0 (cost=0.00..11.70 rows=170 width=449)"
892+
893+ ### Options
894+
895+ The built-in Postgrex adapter supports passing `opts` to the EXPLAIN statement according to the following:
896+ `:analyze`, `:verbose`, `:costs`, `:settings`, `:buffers`, `:timing`, `:summary`, `:format`, `:plan`
897+
898+ All options except `format` are boolean valued and default to `false`.
899+
900+ The allowed `format` values are `:map`, `:yaml`, and `:text`:
901+ * `:map` is the deserialized JSON encoding.
902+ * `:yaml` and `:text` return the result as a string.
903+
904+ The Postgrex adapter supports the following formats: `:map`, `:yaml` and `:text`
905+
906+ The `:plan` option in Postgrex can take the values `:custom` or `:fallback_generic`. When `:custom`
907+ is specified, the explain plan generated will consider the specific values of the query parameters
908+ that are supplied. When using `:fallback_generic`, the specific values of the query parameters will
909+ be ignored. `:fallback_generic` does not use PostgreSQL's built-in support for a generic explain
910+ plan (available as of PostgreSQL 16), but instead uses a special implementation that works for PostgreSQL
911+ versions 12 and above. Defaults to `:custom`.
912+
913+ Any other value passed to `opts` will be forwarded to the underlying adapter query function, including
914+ shared Repo options such as `:timeout`. Non built-in adapters may have specific behaviour and you should
915+ consult their documentation for more details.
916+
917+ For version compatibility, please check your database's documentation:
918+
919+ * _Postgrex_: [PostgreSQL doc](https://www.postgresql.org/docs/current/sql-explain.html).
920+
921+ """
922+
923+ :myxql ->
924+ @ doc """
925+ Executes an EXPLAIN statement or similar for the given query according to its kind and the
926+ adapter in the given repository.
927+
928+ ## Examples
929+
930+ # MySQL
931+ iex> MyRepo.explain(:all, from(p in Post, where: p.title == "title")) |> IO.puts()
932+ +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
933+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
934+ +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
935+ | 1 | SIMPLE | p0 | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.0 | Using where |
936+ +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
937+
938+ # Shared opts
939+ iex> MyRepo.explain(:all, Post, analyze: true, timeout: 20_000)
940+ "Seq Scan on posts p0 (cost=0.00..11.70 rows=170 width=443) (actual time=0.013..0.013 rows=0 loops=1)\\ nPlanning Time: 0.031 ms\\ nExecution Time: 0.021 ms"
941+
942+ It's safe to execute it for updates and deletes, no data change will be committed:
943+
944+ iex> MyRepo(:update_all, from(p in Post, update: [set: [title: "new title"]]))
945+ "Update on posts p0 (cost=0.00..11.70 rows=170 width=449)\\ n -> Seq Scan on posts p0 (cost=0.00..11.70 rows=170 width=449)"
946+
947+ ### Options
948+
949+ The MyXQL adapter supports passing `opts` to the EXPLAIN statement according to the following:
950+
951+ * `:format`
952+
953+ All options except `format` are boolean valued and default to `false`.
954+
955+ The allowed `format` values are `:map`, `:yaml`, and `:text`:
956+ * `:map` is the deserialized JSON encoding.
957+ * `:yaml` and `:text` return the result as a string.
958+
959+ The built-in adapters support the following formats: `:map` and `:text`
960+
961+ Any other value passed to `opts` will be forwarded to the underlying adapter query function, including
962+ shared Repo options such as `:timeout`. Non built-in adapters may have specific behaviour and you should
963+ consult their documentation for more details.
964+
965+ For version compatibility, please check your database's documentation:
966+
967+ * _MyXQL_: [MySQL doc](https://dev.mysql.com/doc/refman/8.0/en/explain.html).
968+
969+ """
970+
971+ _ -> :ok
972+ end
973+
974+ @ spec explain ( :all | :update_all | :delete_all , Ecto.Queryable . t ( ) , opts :: Keyword . t ( ) ) ::
975+ String . t ( ) | Exception . t ( ) | list ( map )
827976 def explain ( operation , queryable , opts \\ [ ] ) do
828977 Ecto.Adapters.SQL . explain ( get_dynamic_repo ( ) , operation , queryable , opts )
829978 end
830979
831980 @ doc """
832- A convenience function for SQL-based repositories that forces all connections in the
833- pool to disconnect within the given interval.
834-
835- See `Ecto.Adapters.SQL.disconnect_all/3` for more information.
981+ Forces all connections in the repo pool to disconnect within the given interval.
982+
983+ Once this function is called, the pool will disconnect all of its connections
984+ as they are checked in or as they are pinged. Checked in connections will be
985+ randomly disconnected within the given time interval. Pinged connections are
986+ immediately disconnected - as they are idle (according to `:idle_interval`).
987+
988+ If the connection has a backoff configured (which is the case by default),
989+ disconnecting means an attempt at a new connection will be done immediately
990+ after, without starting a new process for each connection. However, if backoff
991+ has been disabled, the connection process will terminate. In such cases,
992+ disconnecting all connections may cause the pool supervisor to restart
993+ depending on the max_restarts/max_seconds configuration of the pool,
994+ so you will want to set those carefully.
836995 """
996+ @ spec disconnect_all ( non_neg_integer , opts :: Keyword . t ( ) ) :: :ok
837997 def disconnect_all ( interval , opts \\ [ ] ) do
838998 Ecto.Adapters.SQL . disconnect_all ( get_dynamic_repo ( ) , interval , opts )
839999 end
0 commit comments