error_code.ex (2515B)
1 defmodule Postgrex.ErrorCode do 2 @moduledoc false 3 # We put this file in the repo because the last real change happened in 2011. 4 # https://github.com/postgres/postgres/blob/master/src/backend/utils/errcodes.txt 5 @external_resource errcodes_path = Path.join(__DIR__, "errcodes.txt") 6 7 errcodes = 8 for line <- File.stream!(errcodes_path), 9 match?(<<_code::5*8, " ", _::binary>>, line) do 10 case String.split(line, " ", trim: true) do 11 [code, _, _, name] -> {code, name |> String.trim() |> String.to_atom()} 12 # duplicated code without name 13 [code, _, _] -> {code} 14 end 15 end 16 17 {errcodes, duplicates} = Enum.split_with(errcodes, &match?({_, _}, &1)) 18 19 # The errcodes.txt file does contain some codes twice, but the duplicates 20 # don't have a name. Make sure every every code without a name has another 21 # entry with a name. 22 for {duplicate} <- duplicates do 23 unless Enum.find(errcodes, fn {code, _} -> code == duplicate end) do 24 raise RuntimeError, "found errcode #{duplicate} without name" 25 end 26 end 27 28 @doc ~S""" 29 Translates a PostgreSQL error code into a name 30 31 Examples: 32 iex> code_to_name("23505") 33 :unique_violation 34 """ 35 @spec code_to_name(String.t()) :: atom | no_return 36 def code_to_name(code) 37 38 for {code, errcodes} <- Enum.group_by(errcodes, &elem(&1, 0)) do 39 [{^code, name}] = errcodes 40 def code_to_name(unquote(code)), do: unquote(name) 41 end 42 43 def code_to_name(_), do: nil 44 45 @doc ~S""" 46 Translates a PostgreSQL error name into a list of possible codes. 47 Most error names have only a single code, but there are exceptions. 48 49 Examples: 50 iex> name_to_code(:prohibited_sql_statement_attempted) 51 "2F003" 52 """ 53 @spec name_to_code(atom) :: String.t() 54 def name_to_code(name) 55 56 @code_decision_table [ 57 # 01004 not used 58 string_data_right_truncation: "22001", 59 # 38002 or 2F002 not used 60 modifying_sql_data_not_permitted: nil, 61 # 38003 not used 62 prohibited_sql_statement_attempted: "2F003", 63 # 38004 or 2F004 not used 64 reading_sql_data_not_permitted: nil, 65 # 39004 not used 66 null_value_not_allowed: "22004" 67 ] 68 69 for {name, errcodes} <- Enum.group_by(errcodes, &elem(&1, 1)) do 70 case Keyword.fetch(@code_decision_table, name) do 71 {:ok, nil} -> 72 :ok 73 74 {:ok, code} -> 75 def name_to_code(unquote(name)), do: unquote(code) 76 77 :error -> 78 [{code, ^name}] = errcodes 79 def name_to_code(unquote(name)), do: unquote(code) 80 end 81 end 82 end