/src/dbdrivers/postgresql/epgsql/pgsql_binary.erl

https://github.com/SPY/zotonic · Erlang · 88 lines · 77 code · 9 blank · 2 comment · 12 complexity · c097561fbe3bf5985c5b0304bfdfeaa9 MD5 · raw file

  1. %%% Copyright (C) 2008 - Will Glozer. All rights reserved.
  2. %%% 20090311 Marc Worrell - Added support for encoding terms and lists of terms in bytea values
  3. -module(pgsql_binary).
  4. -export([encode/3, decode/3, supports/1]).
  5. -include_lib("zotonic.hrl").
  6. -define(int32, 1/big-signed-unit:32).
  7. -define(TERM_MAGIC_NUMBER, 16#01326A3A:1/big-unsigned-unit:32).
  8. encode(_Any, null, _UseIntDT) -> <<-1:?int32>>;
  9. encode(_Any, undefined, _UseIntDT) -> <<-1:?int32>>;
  10. encode(bool, <<1>>, _UseIntDT) -> <<1:?int32, 1:1/big-signed-unit:8>>;
  11. encode(bool, <<>>, _UseIntDT) -> <<1:?int32, 0:1/big-signed-unit:8>>;
  12. encode(bool, true, _UseIntDT) -> <<1:?int32, 1:1/big-signed-unit:8>>;
  13. encode(bool, false, _UseIntDT) -> <<1:?int32, 0:1/big-signed-unit:8>>;
  14. encode(int2, N, UseIntDT) when is_binary(N); is_list(N) -> encode(int2, z_convert:to_integer(N), UseIntDT);
  15. encode(int4, N, UseIntDT) when is_binary(N); is_list(N) -> encode(int4, z_convert:to_integer(N), UseIntDT);
  16. encode(int8, N, UseIntDT) when is_binary(N); is_list(N) -> encode(int8, z_convert:to_integer(N), UseIntDT);
  17. encode(int2, N, _UseIntDT) -> <<2:?int32, N:1/big-signed-unit:16>>;
  18. encode(int4, N, _UseIntDT) -> <<4:?int32, N:1/big-signed-unit:32>>;
  19. encode(int8, N, _UseIntDT) -> <<8:?int32, N:1/big-signed-unit:64>>;
  20. encode(float4, N, _UseIntDT) -> <<4:?int32, N:1/big-float-unit:32>>;
  21. encode(float8, N, _UseIntDT) -> <<8:?int32, N:1/big-float-unit:64>>;
  22. encode(bpchar, C, _UseIntDT) when is_integer(C) -> <<1:?int32, C:1/big-unsigned-unit:8>>;
  23. encode(bpchar, B, _UseIntDT) when is_binary(B) -> <<(byte_size(B)):?int32, B/binary>>;
  24. encode(Type, B, UseIntDT) when Type == time; Type == timetz -> pgsql_datetime:encode(Type, B, UseIntDT);
  25. encode(Type, B, UseIntDT) when Type == date; Type == timestamp -> pgsql_datetime:encode(Type, B, UseIntDT);
  26. encode(Type, B, UseIntDT) when Type == timestamptz; Type == interval -> pgsql_datetime:encode(Type, B, UseIntDT);
  27. encode(bytea, B, _UseIntDT) when is_binary(B) -> <<(byte_size(B)):?int32, B/binary>>;
  28. encode(text, B, _UseIntDT) when is_binary(B) -> <<(byte_size(B)):?int32, B/binary>>;
  29. encode(varchar, B, _UseIntDT) when is_binary(B) -> <<(byte_size(B)):?int32, B/binary>>;
  30. encode(bytea, T, UseIntDT) when is_tuple(T) ->
  31. B = term_to_binary(T),
  32. encode(bytea, <<?TERM_MAGIC_NUMBER, B/binary>>, UseIntDT);
  33. encode(bytea, [T|_Rest]=L, UseIntDT) when is_tuple(T) ->
  34. B = term_to_binary(L),
  35. encode(bytea, <<?TERM_MAGIC_NUMBER, B/binary>>, UseIntDT);
  36. encode(Type, A, UseIntDT) when is_atom(A) -> encode(Type, atom_to_list(A), UseIntDT);
  37. encode(Type, L, UseIntDT) when is_list(L) -> encode(Type, iolist_to_binary(L), UseIntDT);
  38. encode(_Type, _Value, _UseIntDT) -> {error, unsupported}.
  39. decode(bool, <<1:1/big-signed-unit:8>>, _UseIntDT) -> true;
  40. decode(bool, <<0:1/big-signed-unit:8>>, _UseIntDT) -> false;
  41. decode(bool, <<"t">>, _UseIntDT) -> true;
  42. decode(bool, <<"f">>, _UseIntDT) -> false;
  43. decode(bpchar, <<C:1/big-unsigned-unit:8>>, _UseIntDT) -> C;
  44. decode(int2, <<N:1/big-signed-unit:16>>, _UseIntDT) -> N;
  45. decode(int4, <<N:1/big-signed-unit:32>>, _UseIntDT) -> N;
  46. decode(int8, <<N:1/big-signed-unit:64>>, _UseIntDT) -> N;
  47. decode(float4, <<N:1/big-float-unit:32>>, _UseIntDT) -> N;
  48. decode(float8, <<N:1/big-float-unit:64>>, _UseIntDT) -> N;
  49. decode(record, <<_:?int32, Rest/binary>>, UseIntDT) -> list_to_tuple(decode_record(Rest, UseIntDT, []));
  50. decode(Type, B, UseIntDT) when Type == time; Type == timetz -> pgsql_datetime:decode(Type, B, UseIntDT);
  51. decode(Type, B, UseIntDT) when Type == date; Type == timestamp -> pgsql_datetime:decode(Type, B, UseIntDT);
  52. decode(Type, B, UseIntDT) when Type == timestamptz; Type == interval -> pgsql_datetime:decode(Type, B, UseIntDT);
  53. decode(bytea, <<?TERM_MAGIC_NUMBER, B/binary>>, _UseIntDT) -> binary_to_term(B);
  54. decode(_Other, Bin, _UseIntDT) -> Bin.
  55. decode_record(<<>>, _UseIntDT, Acc) ->
  56. lists:reverse(Acc);
  57. decode_record(<<_Type:?int32, -1:?int32, Rest/binary>>, UseIntDT, Acc) ->
  58. decode_record(Rest, UseIntDT, [undefined | Acc]);
  59. decode_record(<<Type:?int32, Len:?int32, Value:Len/binary, Rest/binary>>, UseIntDT, Acc) ->
  60. Value2 = decode(pgsql_types:oid2type(Type), Value, UseIntDT),
  61. decode_record(Rest, UseIntDT, [Value2 | Acc]).
  62. supports(bool) -> true;
  63. supports(bpchar) -> true;
  64. supports(int2) -> true;
  65. supports(int4) -> true;
  66. supports(int8) -> true;
  67. supports(float4) -> true;
  68. supports(float8) -> true;
  69. supports(bytea) -> true;
  70. supports(text) -> true;
  71. supports(varchar) -> true;
  72. supports(record) -> true;
  73. supports(date) -> true;
  74. supports(time) -> true;
  75. supports(timetz) -> true;
  76. supports(timestamp) -> true;
  77. supports(timestamptz) -> true;
  78. supports(interval) -> true;
  79. supports(_Type) -> false.