From ab4265e68aac5073a595adbac7d0c5765d5ee3fc Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 2 Nov 2023 12:55:48 -0500 Subject: [PATCH] Add configuration to skip querying of comp_oids (#663) --- lib/postgrex.ex | 3 +++ lib/postgrex/protocol.ex | 15 +++++++++------ lib/postgrex/types.ex | 31 ++++++++++++++++++++----------- mix.lock | 2 +- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/postgrex.ex b/lib/postgrex.ex index b82f4e97..f9f9b373 100644 --- a/lib/postgrex.ex +++ b/lib/postgrex.ex @@ -167,6 +167,9 @@ defmodule Postgrex do See the [PostgreSQL docs](https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH) for more details. + * `:disable_composite_types` - Set to `true` to disable composite types support. + This is useful when using Postgrex against systems that do not support composite types + (default: `false`). `Postgrex` uses the `DBConnection` library and supports all `DBConnection` options like `:idle`, `:after_connect` etc. See `DBConnection.start_link/2` diff --git a/lib/postgrex/protocol.ex b/lib/postgrex/protocol.ex index fd08ff2b..1f85ec88 100644 --- a/lib/postgrex/protocol.ex +++ b/lib/postgrex/protocol.ex @@ -27,7 +27,8 @@ defmodule Postgrex.Protocol do transactions: :strict, buffer: nil, disconnect_on_error_codes: [], - scram: nil + scram: nil, + disable_composite_types: false @type state :: %__MODULE__{ sock: {module, any}, @@ -80,6 +81,7 @@ defmodule Postgrex.Protocol do types_mod = Keyword.fetch!(opts, :types) disconnect_on_error_codes = opts[:disconnect_on_error_codes] || [] target_server_type = opts[:target_server_type] || :any + disable_composite_types = opts[:disable_composite_types] || false transactions = case opts[:transactions] || :naive do @@ -98,7 +100,8 @@ defmodule Postgrex.Protocol do ping_timeout: ping_timeout, postgres: :idle, transactions: transactions, - disconnect_on_error_codes: disconnect_on_error_codes + disconnect_on_error_codes: disconnect_on_error_codes, + disable_composite_types: disable_composite_types } connect_timeout = Keyword.get(opts, :connect_timeout, timeout) @@ -1029,10 +1032,10 @@ defmodule Postgrex.Protocol do end end - defp bootstrap_send(%{types: types} = s, status, buffer) do + defp bootstrap_send(s, status, buffer) do %{parameters: parameters} = s version = Postgrex.Utils.parse_version(parameters["server_version"]) - statement = Types.bootstrap_query(version, types) + statement = Types.bootstrap_query(version, s) if statement do bootstrap_send(s, status, statement, buffer) @@ -1867,12 +1870,12 @@ defmodule Postgrex.Protocol do end end - defp reload(%{types: types} = s, status, oids, acc, buffer) do + defp reload(s, status, oids, acc, buffer) do %{parameters: parameters} = s with {:ok, parameters} <- Postgrex.Parameters.fetch(parameters) do version = Postgrex.Utils.parse_version(parameters["server_version"]) - statement = Types.reload_query(version, Enum.to_list(oids), types) + statement = Types.reload_query(version, Enum.to_list(oids), s) if statement do reload_send(s, status, statement, acc, buffer) diff --git a/lib/postgrex/types.ex b/lib/postgrex/types.ex index 5daa9c13..71ac0176 100644 --- a/lib/postgrex/types.ex +++ b/lib/postgrex/types.ex @@ -44,7 +44,7 @@ defmodule Postgrex.Types do @doc false @spec bootstrap_query({pos_integer, non_neg_integer, non_neg_integer}, state) :: binary | nil - def bootstrap_query(version, {_, table}) do + def bootstrap_query(version, %{types: {_, table}} = s) do case :ets.info(table, :size) do 0 -> # avoid loading information about table-types @@ -56,14 +56,14 @@ defmodule Postgrex.Types do AND (t.typelem = 0 OR NOT EXISTS (SELECT 1 FROM pg_catalog.pg_type s WHERE s.typrelid != 0 AND s.oid = t.typelem)) """ - build_bootstrap_query(version, filter_oids) + build_bootstrap_query(version, filter_oids, s) _ -> nil end end - defp build_bootstrap_query(version, filter_oids) do + defp build_bootstrap_query(version, filter_oids, s) do {typelem, join_domain} = if version >= {9, 0, 0} do {"coalesce(d.typelem, t.typelem)", "LEFT JOIN pg_type AS d ON t.typbasetype = d.oid"} @@ -85,14 +85,23 @@ defmodule Postgrex.Types do {"0", ""} end + comp_oids = + if s.disable_composite_types do + "null" + else + """ + ARRAY ( + SELECT a.atttypid + FROM pg_attribute AS a + WHERE a.attrelid = t.typrelid AND a.attnum > 0 AND NOT a.attisdropped + ORDER BY a.attnum + ) + """ + end + """ SELECT t.oid, t.typname, t.typsend, t.typreceive, t.typoutput, t.typinput, - #{typelem}, #{rngsubtype}, ARRAY ( - SELECT a.atttypid - FROM pg_attribute AS a - WHERE a.attrelid = t.typrelid AND a.attnum > 0 AND NOT a.attisdropped - ORDER BY a.attnum - ) + #{typelem}, #{rngsubtype}, #{comp_oids} FROM pg_type AS t #{join_domain} #{join_range} @@ -103,13 +112,13 @@ defmodule Postgrex.Types do @doc false @spec reload_query({pos_integer, non_neg_integer, non_neg_integer}, [oid, ...], state) :: binary | nil - def reload_query(version, oids, {_, table}) do + def reload_query(version, oids, %{types: {_, table}} = s) do case Enum.reject(oids, &:ets.member(table, &1)) do [] -> nil oids -> - build_bootstrap_query(version, "WHERE t.oid IN (#{Enum.join(oids, ", ")})") + build_bootstrap_query(version, "WHERE t.oid IN (#{Enum.join(oids, ", ")})", s) end end diff --git a/mix.lock b/mix.lock index fc4894cc..a97bd191 100644 --- a/mix.lock +++ b/mix.lock @@ -8,7 +8,7 @@ "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, "table": {:hex, :table, "0.1.0", "f16104d717f960a623afb134a91339d40d8e11e0c96cfce54fee086b333e43f0", [:mix], [], "hexpm", "bf533d3606823ad8a7ee16f41941e5e6e0e42a20c4504cdf4cfabaaed1c8acb9"}, "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, }