cipherstash-pg 1.0.0.beta.4-arm64-darwin

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.appveyor.yml +42 -0
  3. data/.gems +6 -0
  4. data/.gemtest +0 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +19 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/BSDL +22 -0
  15. data/Contributors.rdoc +46 -0
  16. data/Gemfile +14 -0
  17. data/Gemfile.lock +45 -0
  18. data/History.md +804 -0
  19. data/LICENSE +56 -0
  20. data/Manifest.txt +72 -0
  21. data/POSTGRES +23 -0
  22. data/README-OS_X.rdoc +68 -0
  23. data/README-Windows.rdoc +56 -0
  24. data/README.ja.md +266 -0
  25. data/README.md +272 -0
  26. data/Rakefile +76 -0
  27. data/Rakefile.cross +298 -0
  28. data/certs/ged.pem +24 -0
  29. data/certs/larskanis-2022.pem +26 -0
  30. data/certs/larskanis-2023.pem +24 -0
  31. data/cipherstash-pg.gemspec +0 -0
  32. data/lib/2.7/pg_ext.bundle +0 -0
  33. data/lib/3.0/pg_ext.bundle +0 -0
  34. data/lib/3.1/pg_ext.bundle +0 -0
  35. data/lib/3.2/pg_ext.bundle +0 -0
  36. data/lib/cipherstash-pg/basic_type_map_based_on_result.rb +11 -0
  37. data/lib/cipherstash-pg/basic_type_map_for_queries.rb +113 -0
  38. data/lib/cipherstash-pg/basic_type_map_for_results.rb +30 -0
  39. data/lib/cipherstash-pg/basic_type_registry.rb +206 -0
  40. data/lib/cipherstash-pg/binary_decoder.rb +21 -0
  41. data/lib/cipherstash-pg/coder.rb +82 -0
  42. data/lib/cipherstash-pg/connection.rb +467 -0
  43. data/lib/cipherstash-pg/constants.rb +3 -0
  44. data/lib/cipherstash-pg/exceptions.rb +19 -0
  45. data/lib/cipherstash-pg/result.rb +22 -0
  46. data/lib/cipherstash-pg/text_decoder.rb +43 -0
  47. data/lib/cipherstash-pg/text_encoder.rb +67 -0
  48. data/lib/cipherstash-pg/tuple.rb +24 -0
  49. data/lib/cipherstash-pg/type_map_by_column.rb +11 -0
  50. data/lib/cipherstash-pg/version.rb +3 -0
  51. data/lib/cipherstash-pg.rb +60 -0
  52. data/lib/libpq.5.dylib +0 -0
  53. data/misc/openssl-pg-segfault.rb +21 -0
  54. data/misc/postgres/History.txt +9 -0
  55. data/misc/postgres/Manifest.txt +5 -0
  56. data/misc/postgres/README.txt +21 -0
  57. data/misc/postgres/Rakefile +14 -0
  58. data/misc/postgres/lib/postgres.rb +12 -0
  59. data/misc/ruby-pg/History.txt +9 -0
  60. data/misc/ruby-pg/Manifest.txt +5 -0
  61. data/misc/ruby-pg/README.txt +21 -0
  62. data/misc/ruby-pg/Rakefile +14 -0
  63. data/misc/ruby-pg/lib/ruby/pg.rb +12 -0
  64. data/rakelib/task_extension.rb +32 -0
  65. data/sample/array_insert.rb +7 -0
  66. data/sample/async_api.rb +60 -0
  67. data/sample/async_copyto.rb +24 -0
  68. data/sample/async_mixed.rb +28 -0
  69. data/sample/check_conn.rb +9 -0
  70. data/sample/copydata.rb +21 -0
  71. data/sample/copyfrom.rb +29 -0
  72. data/sample/copyto.rb +13 -0
  73. data/sample/cursor.rb +11 -0
  74. data/sample/disk_usage_report.rb +92 -0
  75. data/sample/issue-119.rb +46 -0
  76. data/sample/losample.rb +51 -0
  77. data/sample/minimal-testcase.rb +6 -0
  78. data/sample/notify_wait.rb +26 -0
  79. data/sample/pg_statistics.rb +104 -0
  80. data/sample/replication_monitor.rb +123 -0
  81. data/sample/test_binary_values.rb +17 -0
  82. data/sample/wal_shipper.rb +202 -0
  83. data/sample/warehouse_partitions.rb +161 -0
  84. data/translation/.po4a-version +7 -0
  85. data/translation/po/all.pot +875 -0
  86. data/translation/po/ja.po +868 -0
  87. data/translation/po4a.cfg +9 -0
  88. data/vendor/database-extensions/install.sql +317 -0
  89. data/vendor/database-extensions/uninstall.sql +20 -0
  90. metadata +140 -0
@@ -0,0 +1,26 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIETTCCArWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
3
+ L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yMjAyMTQxMzMwNTZaFw0yMzAy
4
+ MTQxMzMwNTZaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
5
+ PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
6
+ mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
7
+ eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
8
+ 8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
9
+ SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
10
+ JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
11
+ eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
12
+ chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
13
+ 9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjgYEwfzAJ
14
+ BgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUOIdbSMr3VFrTCO9/cTM0
15
+ 0exHzBcwIgYDVR0RBBswGYEXbGFyc0BncmVpei1yZWluc2RvcmYuZGUwIgYDVR0S
16
+ BBswGYEXbGFyc0BncmVpei1yZWluc2RvcmYuZGUwDQYJKoZIhvcNAQELBQADggGB
17
+ AFWP7F/y3Oq3NgrqUOnjKOeDaBa7AqNhHS+PZg+C90lnJzMgOs4KKgZYxqSQVSab
18
+ SCEmzIO/StkXY4NpJ4fYLrHemf/fJy1wPyu+fNdp5SEEUwEo+2toRFlzTe4u4LdS
19
+ QC636nPPTMt8H3xz2wf/lUIUeo2Qc95Qt2BQM465ibbG9kmA3c7Sopx6yOabYOAl
20
+ KPRbOSEPiWYcF9Suuz8Gdf8jxEtPlnZiwRvnYJ+IHMq3XQCJWPpMzdDMbtlgHbXE
21
+ vq1zOTLMSYAS0UB3uionR4yo1hLz60odwkCm7qf0o2Ci/5OjtB0a89VuyqRU2vUJ
22
+ QH95WBjDJ6lCCW7J0mrMPnJQSUFTmufsU6jOChvPaCeAzW1YwrsP/YKnvwueG7ip
23
+ VOdW6RitjtFxhS7evRL0201+KUvLz12zZWWjOcujlQs64QprxOtiv/MiisKb1Ng+
24
+ oL1mUdzB8KrZL4/WbG5YNX6UTtJbIOu9qEFbBAy4/jtIkJX+dlNoFwd4GXQW1YNO
25
+ nA==
26
+ -----END CERTIFICATE-----
@@ -0,0 +1,24 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEBDCCAmygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
3
+ L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yMzAyMTUxNzQxMTVaFw0yNDAy
4
+ MTUxNzQxMTVaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
5
+ PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
6
+ mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
7
+ eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
8
+ 8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
9
+ SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
10
+ JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
11
+ eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
12
+ chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
13
+ 9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjOTA3MAkG
14
+ A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQ4h1tIyvdUWtMI739xMzTR
15
+ 7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAQAcuTARfiiVUVx5KURICfdTM2Kd7LhOn
16
+ qt3Vs4ANGvT226LEp3RnQ+kWGQYMRb3cw3LY2TNQRPlnZxE994mgjBscN4fbjXqO
17
+ T0JbVpeszRZa5k1goggbnWT7CO7yU7WcHh13DaSubY7HUpAJn2xz9w2stxQfN/EE
18
+ VMlnDJ1P7mUHAvpK8X9j9h7Xlc1niViT18MYwux8mboVTryrLr+clATUkkM3yBF0
19
+ RV+c34ReW5eXO9Tr6aKTxh/pFC9ggDT6jOxuJgSvG8HWJzVf4NDvMavIas4KYjiI
20
+ BU6CpWaG5NxicqL3BERi52U43HV08br+LNVpb7Rekgve/PJuSFnAR015bhSRXe5U
21
+ vBioD1qW2ZW9tXg8Ww2IfDaO5a1So5Xby51rhNlyo6ATj2NkuLWZUKPKHhAz0TKm
22
+ Dzx/gFSOrRoCt2mXNgrmcAfr386AfaMvCh7cXqdxZwmVo7ILZCYXck0pajvubsDd
23
+ NUIIFkVXvd1odFyK9LF1RFAtxn/iAmpx
24
+ -----END CERTIFICATE-----
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::BasicTypeMapBasedOnResult < CipherStashPG::TypeMapByOid
3
+ include(CipherStashPG::BasicTypeRegistry::Checker)
4
+
5
+ def initialize(connection_or_coder_maps, registry: nil)
6
+ @coder_maps = build_coder_maps(connection_or_coder_maps, :registry => registry)
7
+ @coder_maps.each_format(:encoder).flat_map { |f| f.coders }.each do |coder|
8
+ add_coder(coder)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,113 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::BasicTypeMapForQueries < CipherStashPG::TypeMapByClass
3
+ class BinaryData < String
4
+ end
5
+
6
+ class UndefinedEncoder < RuntimeError
7
+ end
8
+
9
+ include(CipherStashPG::BasicTypeRegistry::Checker)
10
+
11
+ def initialize(connection_or_coder_maps, registry: nil, if_undefined: nil)
12
+ @coder_maps = build_coder_maps(connection_or_coder_maps, :registry => registry)
13
+ @array_encoders_by_klass = array_encoders_by_klass
14
+ @encode_array_as = :array
15
+ @if_undefined = (if_undefined or proc do |oid_name, format|
16
+ raise(UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}")
17
+ end)
18
+ init_encoders
19
+ end
20
+
21
+ def encode_array_as=(pg_type)
22
+ case pg_type
23
+ when :array then
24
+ # do nothing
25
+ when :json then
26
+ # do nothing
27
+ when :record then
28
+ # do nothing
29
+ when /\A_/ then
30
+ # do nothing
31
+ else
32
+ raise(ArgumentError, "invalid pg_type #{pg_type.inspect}")
33
+ end
34
+ @encode_array_as = pg_type
35
+ init_encoders
36
+ end
37
+
38
+ attr_reader(:encode_array_as)
39
+
40
+ private
41
+
42
+ def init_encoders
43
+ coders.each { |kl, c| self[kl] = nil }
44
+ populate_encoder_list
45
+ @textarray_encoder = coder_by_name(0, :encoder, "_text")
46
+ end
47
+
48
+ def coder_by_name(format, direction, name)
49
+ check_format_and_direction(format, direction)
50
+ @coder_maps.map_for(format, direction).coder_by_name(name)
51
+ end
52
+
53
+ def undefined(name, format)
54
+ @if_undefined.call(name, format)
55
+ end
56
+
57
+ def populate_encoder_list
58
+ DEFAULT_TYPE_MAP.each do |klass, selector|
59
+ if Array.===(selector) then
60
+ format, name, oid_name = selector
61
+ coder = coder_by_name(format, :encoder, name).dup
62
+ if coder then
63
+ if oid_name then
64
+ oid_coder = coder_by_name(format, :encoder, oid_name)
65
+ oid_coder ? (coder.oid = oid_coder.oid) : (undefined(oid_name, format))
66
+ else
67
+ coder.oid = 0
68
+ end
69
+ self[klass] = coder
70
+ else
71
+ undefined(name, format)
72
+ end
73
+ else
74
+ case @encode_array_as
75
+ when :array then
76
+ self[klass] = selector
77
+ when :json then
78
+ self[klass] = CipherStashPG::TextEncoder::JSON.new
79
+ when :record then
80
+ self[klass] = CipherStashPG::TextEncoder::Record.new(:type_map => (self))
81
+ when /\A_/ then
82
+ coder = coder_by_name(0, :encoder, @encode_array_as)
83
+ coder ? (self[klass] = coder) : (undefined(@encode_array_as, format))
84
+ else
85
+ raise(ArgumentError, "invalid pg_type #{@encode_array_as.inspect}")
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ def array_encoders_by_klass
92
+ DEFAULT_ARRAY_TYPE_MAP.inject({}) do |h, (klass, (format, name))|
93
+ h[klass] = coder_by_name(format, :encoder, name)
94
+ h
95
+ end
96
+ end
97
+
98
+ def get_array_type(value)
99
+ elem = value
100
+ while elem.kind_of?(Array) do
101
+ elem = elem.first
102
+ end
103
+ (@array_encoders_by_klass[elem.class] or (elem.class.ancestors.lazy.map do |ancestor|
104
+ @array_encoders_by_klass[ancestor]
105
+ end.find do |a|
106
+ a
107
+ end or @textarray_encoder))
108
+ end
109
+
110
+ DEFAULT_TYPE_MAP = { TrueClass => ([1, "bool", "bool"]), FalseClass => ([1, "bool", "bool"]), Integer => ([0, "int8"]), Float => ([0, "float8"]), BigDecimal => ([0, "numeric"]), Time => ([0, "timestamptz"]), IPAddr => ([0, "inet"]), Hash => ([0, "json"]), Array => :get_array_type, BinaryData => ([1, "bytea"]) }
111
+
112
+ DEFAULT_ARRAY_TYPE_MAP = { TrueClass => ([0, "_bool"]), FalseClass => ([0, "_bool"]), Integer => ([0, "_int8"]), String => ([0, "_text"]), Float => ([0, "_float8"]), BigDecimal => ([0, "_numeric"]), Time => ([0, "_timestamptz"]), IPAddr => ([0, "_inet"]) }
113
+ end
@@ -0,0 +1,30 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::BasicTypeMapForResults < CipherStashPG::TypeMapByOid
3
+ include(CipherStashPG::BasicTypeRegistry::Checker)
4
+
5
+ class WarningTypeMap < CipherStashPG::TypeMapInRuby
6
+ def initialize(typenames)
7
+ @already_warned = Hash.new { |h, k| h[k] = {} }
8
+ @typenames_by_oid = typenames
9
+ end
10
+
11
+ def typecast_result_value(result, _tuple, field)
12
+ format = result.fformat(field)
13
+ oid = result.ftype(field)
14
+ unless @already_warned[format][oid] then
15
+ warn("Warning: no type cast defined for type #{@typenames_by_oid[oid].inspect} format #{format} with oid #{oid}. Please cast this type explicitly to TEXT to be safe for future changes.")
16
+ @already_warned[format][oid] = true
17
+ end
18
+ super
19
+ end
20
+ end
21
+
22
+ def initialize(connection_or_coder_maps, registry: nil)
23
+ @coder_maps = build_coder_maps(connection_or_coder_maps, :registry => registry)
24
+ @coder_maps.each_format(:decoder).flat_map { |f| f.coders }.each do |coder|
25
+ add_coder(coder)
26
+ end
27
+ typenames = @coder_maps.typenames_by_oid
28
+ self.default_type_map = WarningTypeMap.new(typenames)
29
+ end
30
+ end
@@ -0,0 +1,206 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::BasicTypeRegistry
3
+ class CoderMap
4
+ DONT_QUOTE_TYPES = ["int2", "int4", "int8", "float4", "float8", "oid", "bool", "date", "timestamp", "timestamptz"].inject({}) do |h, e|
5
+ h[e] = true
6
+ h
7
+ end
8
+
9
+ def initialize(result, coders_by_name, format, arraycoder)
10
+ coder_map = {}
11
+ arrays, nodes = result.partition { |row| (row["typinput"] == "array_in") }
12
+ nodes.find_all { |row| coders_by_name.key?(row["typname"]) }.each do |row|
13
+ coder = coders_by_name[row["typname"]].dup
14
+ coder.oid = row["oid"].to_i
15
+ coder.name = row["typname"]
16
+ coder.format = format
17
+ coder_map[coder.oid] = coder
18
+ end
19
+ if arraycoder then
20
+ arrays.each do |row|
21
+ elements_coder = coder_map[row["typelem"].to_i]
22
+ next unless elements_coder
23
+ coder = arraycoder.new
24
+ coder.oid = row["oid"].to_i
25
+ coder.name = row["typname"]
26
+ coder.format = format
27
+ coder.elements_type = elements_coder
28
+ coder.needs_quotation = (not DONT_QUOTE_TYPES[elements_coder.name])
29
+ coder_map[coder.oid] = coder
30
+ end
31
+ end
32
+ @coders = coder_map.values
33
+ @coders_by_name = @coders.inject({}) do |h, t|
34
+ h[t.name] = t
35
+ h
36
+ end
37
+ @coders_by_oid = @coders.inject({}) do |h, t|
38
+ h[t.oid] = t
39
+ h
40
+ end
41
+ end
42
+
43
+ attr_reader(:coders)
44
+
45
+ attr_reader(:coders_by_oid)
46
+
47
+ attr_reader(:coders_by_name)
48
+
49
+ def coder_by_name(name)
50
+ @coders_by_name[name]
51
+ end
52
+
53
+ def coder_by_oid(oid)
54
+ @coders_by_oid[oid]
55
+ end
56
+ end
57
+
58
+ class CoderMapsBundle
59
+ attr_reader(:typenames_by_oid)
60
+
61
+ def initialize(connection, registry: nil)
62
+ registry ||= DEFAULT_TYPE_REGISTRY
63
+ result = connection.exec("\t\t\t\tSELECT t.oid, t.typname, t.typelem, t.typdelim, ti.proname AS typinput\n\t\t\t\tFROM pg_type as t\n\t\t\t\tJOIN pg_proc as ti ON ti.oid = t.typinput\n").to_a
64
+ @maps = [[0, :encoder, CipherStashPG::TextEncoder::Array], [0, :decoder, CipherStashPG::TextDecoder::Array], [1, :encoder, nil], [1, :decoder, nil]].inject([]) do |h, (format, direction, arraycoder)|
65
+ coders = (registry.coders_for(format, direction) or {})
66
+ h[format] ||= {}
67
+ h[format][direction] = CoderMap.new(result, coders, format, arraycoder)
68
+ h
69
+ end
70
+ @typenames_by_oid = result.inject({}) do |h, t|
71
+ h[t["oid"].to_i] = t["typname"]
72
+ h
73
+ end
74
+ end
75
+
76
+ def each_format(direction)
77
+ @maps.map { |f| f[direction] }
78
+ end
79
+
80
+ def map_for(format, direction)
81
+ @maps[format][direction]
82
+ end
83
+ end
84
+
85
+ module Checker
86
+ ValidFormats = { 0 => true, 1 => true }
87
+
88
+ ValidDirections = { :encoder => true, :decoder => true }
89
+
90
+ protected(def check_format_and_direction(format, direction)
91
+ unless ValidFormats[format] then
92
+ raise(ArgumentError, ("Invalid format value %p" % format))
93
+ end
94
+ unless ValidDirections[direction] then
95
+ raise(ArgumentError, ("Invalid direction %p" % direction))
96
+ end
97
+ end)
98
+
99
+ protected(def build_coder_maps(conn_or_maps, registry: nil)
100
+ if conn_or_maps.is_a?(CipherStashPG::BasicTypeRegistry::CoderMapsBundle) then
101
+ if registry then
102
+ raise(ArgumentError, "registry argument must be given to CoderMapsBundle")
103
+ end
104
+ conn_or_maps
105
+ else
106
+ CipherStashPG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, :registry => registry)
107
+ end
108
+ end)
109
+ end
110
+
111
+ include(Checker)
112
+
113
+ def initialize
114
+ @coders_by_name = []
115
+ end
116
+
117
+ def coders_for(format, direction)
118
+ check_format_and_direction(format, direction)
119
+ @coders_by_name[format][direction]
120
+ end
121
+
122
+ def register_coder(coder)
123
+ h = @coders_by_name[coder.format] ||= { :encoder => ({}), :decoder => ({}) }
124
+ name = (coder.name or raise(ArgumentError, "name of #{coder.inspect} must be defined"))
125
+ h[:encoder][name] = coder if coder.respond_to?(:encode)
126
+ h[:decoder][name] = coder if coder.respond_to?(:decode)
127
+ self
128
+ end
129
+
130
+ def register_type(format, name, encoder_class, decoder_class)
131
+ if encoder_class then
132
+ register_coder(encoder_class.new(:name => name, :format => format))
133
+ end
134
+ if decoder_class then
135
+ register_coder(decoder_class.new(:name => name, :format => format))
136
+ end
137
+ self
138
+ end
139
+
140
+ def alias_type(format, new, old)
141
+ [:encoder, :decoder].each do |ende|
142
+ enc = @coders_by_name[format][ende][old]
143
+ if enc then
144
+ @coders_by_name[format][ende][new] = enc
145
+ else
146
+ @coders_by_name[format][ende].delete(new)
147
+ end
148
+ end
149
+ self
150
+ end
151
+
152
+ def register_default_types
153
+ register_type(0, "int2", CipherStashPG::TextEncoder::Integer, CipherStashPG::TextDecoder::Integer)
154
+ alias_type(0, "int4", "int2")
155
+ alias_type(0, "int8", "int2")
156
+ alias_type(0, "oid", "int2")
157
+ register_type(0, "numeric", CipherStashPG::TextEncoder::Numeric, CipherStashPG::TextDecoder::Numeric)
158
+ register_type(0, "text", CipherStashPG::TextEncoder::String, CipherStashPG::TextDecoder::String)
159
+ alias_type(0, "varchar", "text")
160
+ alias_type(0, "char", "text")
161
+ alias_type(0, "bpchar", "text")
162
+ alias_type(0, "xml", "text")
163
+ alias_type(0, "name", "text")
164
+ register_type(0, "bytea", nil, CipherStashPG::TextDecoder::Bytea)
165
+ register_type(0, "bool", CipherStashPG::TextEncoder::Boolean, CipherStashPG::TextDecoder::Boolean)
166
+ register_type(0, "float4", CipherStashPG::TextEncoder::Float, CipherStashPG::TextDecoder::Float)
167
+ alias_type(0, "float8", "float4")
168
+ register_type(0, "timestamp", CipherStashPG::TextEncoder::TimestampWithoutTimeZone, CipherStashPG::TextDecoder::TimestampWithoutTimeZone)
169
+ register_type(0, "timestamptz", CipherStashPG::TextEncoder::TimestampWithTimeZone, CipherStashPG::TextDecoder::TimestampWithTimeZone)
170
+ register_type(0, "date", CipherStashPG::TextEncoder::Date, CipherStashPG::TextDecoder::Date)
171
+ register_type(0, "json", CipherStashPG::TextEncoder::JSON, CipherStashPG::TextDecoder::JSON)
172
+ alias_type(0, "jsonb", "json")
173
+ register_type(0, "inet", CipherStashPG::TextEncoder::Inet, CipherStashPG::TextDecoder::Inet)
174
+ alias_type(0, "cidr", "inet")
175
+ register_type(1, "int2", CipherStashPG::BinaryEncoder::Int2, CipherStashPG::BinaryDecoder::Integer)
176
+ register_type(1, "int4", CipherStashPG::BinaryEncoder::Int4, CipherStashPG::BinaryDecoder::Integer)
177
+ register_type(1, "int8", CipherStashPG::BinaryEncoder::Int8, CipherStashPG::BinaryDecoder::Integer)
178
+ alias_type(1, "oid", "int2")
179
+ register_type(1, "text", CipherStashPG::BinaryEncoder::String, CipherStashPG::BinaryDecoder::String)
180
+ alias_type(1, "varchar", "text")
181
+ alias_type(1, "char", "text")
182
+ alias_type(1, "bpchar", "text")
183
+ alias_type(1, "xml", "text")
184
+ alias_type(1, "name", "text")
185
+ register_type(1, "bytea", CipherStashPG::BinaryEncoder::Bytea, CipherStashPG::BinaryDecoder::Bytea)
186
+ register_type(1, "bool", CipherStashPG::BinaryEncoder::Boolean, CipherStashPG::BinaryDecoder::Boolean)
187
+ register_type(1, "float4", nil, CipherStashPG::BinaryDecoder::Float)
188
+ register_type(1, "float8", nil, CipherStashPG::BinaryDecoder::Float)
189
+ register_type(1, "timestamp", nil, CipherStashPG::BinaryDecoder::TimestampUtc)
190
+ register_type(1, "timestamptz", nil, CipherStashPG::BinaryDecoder::TimestampUtcToLocal)
191
+ self
192
+ end
193
+
194
+ alias :define_default_types :register_default_types
195
+
196
+ DEFAULT_TYPE_REGISTRY = CipherStashPG::BasicTypeRegistry.new.register_default_types
197
+
198
+ class << self
199
+ [:register_coder, :register_type, :alias_type].each do |meth|
200
+ define_method(meth) do |*args|
201
+ warn("PG::BasicTypeRegistry.#{meth} is deprecated. Please use your own instance by PG::BasicTypeRegistry.new instead!")
202
+ DEFAULT_TYPE_REGISTRY.send(meth, *args)
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,21 @@
1
+ module CipherStashPG
2
+ module BinaryDecoder
3
+ class TimestampUtc < Timestamp
4
+ def initialize(params = {})
5
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_UTC | CipherStashPG::Coder::TIMESTAMP_APP_UTC)))
6
+ end
7
+ end
8
+
9
+ class TimestampUtcToLocal < Timestamp
10
+ def initialize(params = {})
11
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_UTC | CipherStashPG::Coder::TIMESTAMP_APP_LOCAL)))
12
+ end
13
+ end
14
+
15
+ class TimestampLocal < Timestamp
16
+ def initialize(params = {})
17
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_LOCAL | CipherStashPG::Coder::TIMESTAMP_APP_LOCAL)))
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,82 @@
1
+ module CipherStashPG
2
+ class Coder
3
+ module BinaryFormatting
4
+ Params = { :format => 1 }
5
+
6
+ def initialize(params = {})
7
+ super(Params.merge(params))
8
+ end
9
+ end
10
+
11
+ def initialize(params = {})
12
+ params.each { |key, val| send("#{key}=", val) }
13
+ end
14
+
15
+ def dup
16
+ self.class.new(to_h)
17
+ end
18
+
19
+ def to_h
20
+ { :oid => oid, :format => format, :flags => flags, :name => name }
21
+ end
22
+
23
+ def ==(v)
24
+ (self.class == v.class) and (to_h == v.to_h)
25
+ end
26
+
27
+ def marshal_dump
28
+ Marshal.dump(to_h)
29
+ end
30
+
31
+ def marshal_load(str)
32
+ initialize(Marshal.load(str))
33
+ end
34
+
35
+ def inspect
36
+ str = self.to_s
37
+ oid_str = " oid=#{oid}" unless (oid == 0)
38
+ format_str = " format=#{format}" unless (format == 0)
39
+ name_str = " #{name.inspect}" if name
40
+ str[-1, 0] = "#{name_str} #{oid_str}#{format_str}"
41
+ str
42
+ end
43
+
44
+ def inspect_short
45
+ str = case format
46
+ when 0 then
47
+ "T"
48
+ when 1 then
49
+ "B"
50
+ else
51
+ format.to_s
52
+ end
53
+ str = (str + "E") if respond_to?(:encode)
54
+ str = (str + "D") if respond_to?(:decode)
55
+ "#{(name or self.class.name)}:#{str}"
56
+ end
57
+ end
58
+
59
+ class CompositeCoder < Coder
60
+ def to_h
61
+ super.merge!(:elements_type => elements_type, :needs_quotation => needs_quotation?, :delimiter => delimiter)
62
+ end
63
+
64
+ def inspect
65
+ str = super
66
+ str[-1, 0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? ("needs") : ("no")} quotation"
67
+ str
68
+ end
69
+ end
70
+
71
+ class CopyCoder < Coder
72
+ def to_h
73
+ super.merge!(:type_map => type_map, :delimiter => delimiter, :null_string => null_string)
74
+ end
75
+ end
76
+
77
+ class RecordCoder < Coder
78
+ def to_h
79
+ super.merge!(:type_map => type_map)
80
+ end
81
+ end
82
+ end