diff --git a/lib/ecto/adapters/myxql/connection.ex b/lib/ecto/adapters/myxql/connection.ex index fb363b87..31b334e5 100644 --- a/lib/ecto/adapters/myxql/connection.ex +++ b/lib/ecto/adapters/myxql/connection.ex @@ -16,23 +16,28 @@ if Code.ensure_loaded?(MyXQL) do @impl true def prepare_execute(conn, name, sql, params, opts) do + ensure_list_params!(params) MyXQL.prepare_execute(conn, name, sql, params, opts) end @impl true def query(conn, sql, params, opts) do + ensure_list_params!(params) opts = Keyword.put_new(opts, :query_type, :binary_then_text) MyXQL.query(conn, sql, params, opts) end @impl true def query_many(conn, sql, params, opts) do + ensure_list_params!(params) opts = Keyword.put_new(opts, :query_type, :text) MyXQL.query_many(conn, sql, params, opts) end @impl true def execute(conn, query, params, opts) do + ensure_list_params!(params) + case MyXQL.execute(conn, query, params, opts) do {:ok, _, result} -> {:ok, result} {:error, _} = error -> error @@ -41,9 +46,16 @@ if Code.ensure_loaded?(MyXQL) do @impl true def stream(conn, sql, params, opts) do + ensure_list_params!(params) MyXQL.stream(conn, sql, params, opts) end + defp ensure_list_params!(params) do + unless is_list(params) do + raise ArgumentError, "expected params to be a list, got: #{inspect(params)}" + end + end + @quotes ~w(" ' `) @impl true diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex index 9b59e7f5..53a8af3e 100644 --- a/lib/ecto/adapters/postgres/connection.ex +++ b/lib/ecto/adapters/postgres/connection.ex @@ -99,6 +99,8 @@ if Code.ensure_loaded?(Postgrex) do @impl true def prepare_execute(conn, name, sql, params, opts) do + ensure_list_params!(params) + case Postgrex.prepare_execute(conn, name, sql, params, opts) do {:error, %Postgrex.Error{postgres: %{pg_code: "22P02", message: message}} = error} -> context = """ @@ -121,6 +123,7 @@ if Code.ensure_loaded?(Postgrex) do @impl true def query(conn, sql, params, opts) do + ensure_list_params!(params) Postgrex.query(conn, sql, params, opts) end @@ -131,6 +134,8 @@ if Code.ensure_loaded?(Postgrex) do @impl true def execute(conn, %{ref: ref} = query, params, opts) do + ensure_list_params!(params) + case Postgrex.execute(conn, query, params, opts) do {:ok, %{ref: ^ref}, result} -> {:ok, result} @@ -151,9 +156,16 @@ if Code.ensure_loaded?(Postgrex) do @impl true def stream(conn, sql, params, opts) do + ensure_list_params!(params) Postgrex.stream(conn, sql, params, opts) end + defp ensure_list_params!(params) do + unless is_list(params) do + raise ArgumentError, "expected params to be a list, got: #{inspect(params)}" + end + end + @parent_as __MODULE__ alias Ecto.Query.{BooleanExpr, ByExpr, JoinExpr, QueryExpr, WithExpr} diff --git a/lib/ecto/adapters/sql.ex b/lib/ecto/adapters/sql.ex index ba98643e..96ff0e59 100644 --- a/lib/ecto/adapters/sql.ex +++ b/lib/ecto/adapters/sql.ex @@ -102,6 +102,8 @@ defmodule Ecto.Adapters.SQL do optional(atom) => any } + @type query_params :: [term] | %{(atom | String.t()) => term} + @doc false defmacro __using__(opts) do quote do @@ -335,7 +337,7 @@ defmodule Ecto.Adapters.SQL do """ @spec to_sql(:all | :update_all | :delete_all, Ecto.Repo.t(), Ecto.Queryable.t()) :: - {String.t(), [term]} + {String.t(), query_params} def to_sql(kind, repo, queryable) do case Ecto.Adapter.Queryable.prepare_query(kind, repo, queryable) do {{:cached, _update, _reset, {_id, cached}}, params} -> @@ -510,7 +512,7 @@ defmodule Ecto.Adapters.SQL do [%{rows: [[42]], num_rows: 1}] """ - @spec stream(Ecto.Repo.t(), String.t(), [term], Keyword.t()) :: Enum.t() + @spec stream(Ecto.Repo.t(), String.t(), query_params, Keyword.t()) :: Enum.t() def stream(repo, sql, params \\ [], opts \\ []) do repo |> Ecto.Adapter.lookup_meta() @@ -520,7 +522,12 @@ defmodule Ecto.Adapters.SQL do @doc """ Same as `query/4` but raises on invalid queries. """ - @spec query!(pid() | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), iodata, [term], Keyword.t()) :: + @spec query!( + pid() | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), + iodata, + query_params, + Keyword.t() + ) :: query_result def query!(repo, sql, params \\ [], opts \\ []) do case query(repo, sql, params, opts) do @@ -558,7 +565,12 @@ defmodule Ecto.Adapters.SQL do {:ok, %{rows: [[42]], num_rows: 1}} """ - @spec query(pid() | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), iodata, [term], Keyword.t()) :: + @spec query( + pid() | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), + iodata, + query_params, + Keyword.t() + ) :: {:ok, query_result} | {:error, Exception.t()} def query(repo, sql, params \\ [], opts \\ []) @@ -573,7 +585,12 @@ defmodule Ecto.Adapters.SQL do @doc """ Same as `query_many/4` but raises on invalid queries. """ - @spec query_many!(Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), iodata, [term], Keyword.t()) :: + @spec query_many!( + Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), + iodata, + query_params, + Keyword.t() + ) :: [query_result] def query_many!(repo, sql, params \\ [], opts \\ []) do case query_many(repo, sql, params, opts) do @@ -614,7 +631,7 @@ defmodule Ecto.Adapters.SQL do @spec query_many( pid() | Ecto.Repo.t() | Ecto.Adapter.adapter_meta(), iodata, - [term], + query_params, Keyword.t() ) :: {:ok, [query_result]} | {:error, Exception.t()} def query_many(repo, sql, params \\ [], opts \\ []) diff --git a/lib/ecto/adapters/tds/connection.ex b/lib/ecto/adapters/tds/connection.ex index c0669e92..75c0d37f 100644 --- a/lib/ecto/adapters/tds/connection.ex +++ b/lib/ecto/adapters/tds/connection.ex @@ -79,6 +79,10 @@ if Code.ensure_loaded?(Tds) do def to_constraints(_, _opts), do: [] def prepare_params(params) do + unless is_list(params) do + raise ArgumentError, "expected params to be a list, got: #{inspect(params)}" + end + {params, _} = Enum.map_reduce(params, 1, fn param, acc -> case prepare_param(param) do