cipherstash-pg 1.0.0.beta.1-arm64-darwin-22

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/BSDL +22 -0
  3. data/Contributors.rdoc +46 -0
  4. data/Gemfile +14 -0
  5. data/History.rdoc +789 -0
  6. data/LICENSE +56 -0
  7. data/Manifest.txt +72 -0
  8. data/POSTGRES +23 -0
  9. data/README-OS_X.rdoc +68 -0
  10. data/README-Windows.rdoc +56 -0
  11. data/README.ja.rdoc +13 -0
  12. data/README.rdoc +233 -0
  13. data/Rakefile +115 -0
  14. data/certs/ged.pem +24 -0
  15. data/certs/larskanis-2022.pem +26 -0
  16. data/cipherstash-pg.gemspec +31 -0
  17. data/lib/2.7/pg_ext.bundle +0 -0
  18. data/lib/3.0/pg_ext.bundle +0 -0
  19. data/lib/3.1/pg_ext.bundle +0 -0
  20. data/lib/3.2/pg_ext.bundle +0 -0
  21. data/lib/cipherstash-pg.rb +15 -0
  22. data/lib/libpq.5.dylib +0 -0
  23. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  24. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  25. data/lib/pg/basic_type_map_for_results.rb +81 -0
  26. data/lib/pg/basic_type_registry.rb +301 -0
  27. data/lib/pg/binary_decoder.rb +23 -0
  28. data/lib/pg/coder.rb +104 -0
  29. data/lib/pg/connection.rb +878 -0
  30. data/lib/pg/constants.rb +12 -0
  31. data/lib/pg/exceptions.rb +18 -0
  32. data/lib/pg/result.rb +43 -0
  33. data/lib/pg/text_decoder.rb +46 -0
  34. data/lib/pg/text_encoder.rb +59 -0
  35. data/lib/pg/tuple.rb +30 -0
  36. data/lib/pg/type_map_by_column.rb +16 -0
  37. data/lib/pg/version.rb +4 -0
  38. data/lib/pg.rb +55 -0
  39. data/misc/openssl-pg-segfault.rb +31 -0
  40. data/misc/postgres/History.txt +9 -0
  41. data/misc/postgres/Manifest.txt +5 -0
  42. data/misc/postgres/README.txt +21 -0
  43. data/misc/postgres/Rakefile +21 -0
  44. data/misc/postgres/lib/postgres.rb +16 -0
  45. data/misc/ruby-pg/History.txt +9 -0
  46. data/misc/ruby-pg/Manifest.txt +5 -0
  47. data/misc/ruby-pg/README.txt +21 -0
  48. data/misc/ruby-pg/Rakefile +21 -0
  49. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  50. data/rakelib/task_extension.rb +46 -0
  51. data/sample/array_insert.rb +20 -0
  52. data/sample/async_api.rb +102 -0
  53. data/sample/async_copyto.rb +39 -0
  54. data/sample/async_mixed.rb +56 -0
  55. data/sample/check_conn.rb +21 -0
  56. data/sample/copydata.rb +71 -0
  57. data/sample/copyfrom.rb +81 -0
  58. data/sample/copyto.rb +19 -0
  59. data/sample/cursor.rb +21 -0
  60. data/sample/disk_usage_report.rb +177 -0
  61. data/sample/issue-119.rb +94 -0
  62. data/sample/losample.rb +69 -0
  63. data/sample/minimal-testcase.rb +17 -0
  64. data/sample/notify_wait.rb +72 -0
  65. data/sample/pg_statistics.rb +285 -0
  66. data/sample/replication_monitor.rb +222 -0
  67. data/sample/test_binary_values.rb +33 -0
  68. data/sample/wal_shipper.rb +434 -0
  69. data/sample/warehouse_partitions.rb +311 -0
  70. data/vendor/database-extensions/install.sql +317 -0
  71. data/vendor/database-extensions/uninstall.sql +20 -0
  72. metadata +118 -0
@@ -0,0 +1,301 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ # This class defines the mapping between PostgreSQL types and encoder/decoder classes for PG::BasicTypeMapForResults, PG::BasicTypeMapForQueries and PG::BasicTypeMapBasedOnResult.
7
+ #
8
+ # Additional types can be added like so:
9
+ #
10
+ # require 'pg'
11
+ # require 'ipaddr'
12
+ #
13
+ # class InetDecoder < PG::SimpleDecoder
14
+ # def decode(string, tuple=nil, field=nil)
15
+ # IPAddr.new(string)
16
+ # end
17
+ # end
18
+ # class InetEncoder < PG::SimpleEncoder
19
+ # def encode(ip_addr)
20
+ # ip_addr.to_s
21
+ # end
22
+ # end
23
+ #
24
+ # conn = PG.connect
25
+ # regi = PG::BasicTypeRegistry.new.register_default_types
26
+ # regi.register_type(0, 'inet', InetEncoder, InetDecoder)
27
+ # conn.type_map_for_results = PG::BasicTypeMapForResults.new(conn, registry: regi)
28
+ class PG::BasicTypeRegistry
29
+ # An instance of this class stores the coders that should be used for a particular wire format (text or binary)
30
+ # and type cast direction (encoder or decoder).
31
+ #
32
+ # Each coder object is filled with the PostgreSQL type name, OID, wire format and array coders are filled with the base elements_type.
33
+ class CoderMap
34
+ # Hash of text types that don't require quotation, when used within composite types.
35
+ # type.name => true
36
+ DONT_QUOTE_TYPES = %w[
37
+ int2 int4 int8
38
+ float4 float8
39
+ oid
40
+ bool
41
+ date timestamp timestamptz
42
+ ].inject({}){|h,e| h[e] = true; h }
43
+
44
+ def initialize(result, coders_by_name, format, arraycoder)
45
+ coder_map = {}
46
+
47
+ arrays, nodes = result.partition { |row| row['typinput'] == 'array_in' }
48
+
49
+ # populate the base types
50
+ nodes.find_all { |row| coders_by_name.key?(row['typname']) }.each do |row|
51
+ coder = coders_by_name[row['typname']].dup
52
+ coder.oid = row['oid'].to_i
53
+ coder.name = row['typname']
54
+ coder.format = format
55
+ coder_map[coder.oid] = coder
56
+ end
57
+
58
+ if arraycoder
59
+ # populate array types
60
+ arrays.each do |row|
61
+ elements_coder = coder_map[row['typelem'].to_i]
62
+ next unless elements_coder
63
+
64
+ coder = arraycoder.new
65
+ coder.oid = row['oid'].to_i
66
+ coder.name = row['typname']
67
+ coder.format = format
68
+ coder.elements_type = elements_coder
69
+ coder.needs_quotation = !DONT_QUOTE_TYPES[elements_coder.name]
70
+ coder_map[coder.oid] = coder
71
+ end
72
+ end
73
+
74
+ @coders = coder_map.values
75
+ @coders_by_name = @coders.inject({}){|h, t| h[t.name] = t; h }
76
+ @coders_by_oid = @coders.inject({}){|h, t| h[t.oid] = t; h }
77
+ end
78
+
79
+ attr_reader :coders
80
+ attr_reader :coders_by_oid
81
+ attr_reader :coders_by_name
82
+
83
+ def coder_by_name(name)
84
+ @coders_by_name[name]
85
+ end
86
+
87
+ def coder_by_oid(oid)
88
+ @coders_by_oid[oid]
89
+ end
90
+ end
91
+
92
+ # An instance of this class stores CoderMap instances to be used for text and binary wire formats
93
+ # as well as encoder and decoder directions.
94
+ #
95
+ # A PG::BasicTypeRegistry::CoderMapsBundle instance retrieves all type definitions from the PostgreSQL server and matches them with the coder definitions of the global PG::BasicTypeRegistry .
96
+ # It provides 4 separate CoderMap instances for the combinations of the two formats and directions.
97
+ #
98
+ # A PG::BasicTypeRegistry::CoderMapsBundle instance can be used to initialize an instance of
99
+ # * PG::BasicTypeMapForResults
100
+ # * PG::BasicTypeMapForQueries
101
+ # * PG::BasicTypeMapBasedOnResult
102
+ # by passing it instead of the connection object like so:
103
+ #
104
+ # conn = PG::Connection.new
105
+ # maps = PG::BasicTypeRegistry::CoderMapsBundle.new(conn)
106
+ # conn.type_map_for_results = PG::BasicTypeMapForResults.new(maps)
107
+ #
108
+ class CoderMapsBundle
109
+ attr_reader :typenames_by_oid
110
+
111
+ def initialize(connection, registry: nil)
112
+ registry ||= DEFAULT_TYPE_REGISTRY
113
+
114
+ result = connection.exec(<<-SQL).to_a
115
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, ti.proname AS typinput
116
+ FROM pg_type as t
117
+ JOIN pg_proc as ti ON ti.oid = t.typinput
118
+ SQL
119
+
120
+ @maps = [
121
+ [0, :encoder, PG::TextEncoder::Array],
122
+ [0, :decoder, PG::TextDecoder::Array],
123
+ [1, :encoder, nil],
124
+ [1, :decoder, nil],
125
+ ].inject([]) do |h, (format, direction, arraycoder)|
126
+ coders = registry.coders_for(format, direction) || {}
127
+ h[format] ||= {}
128
+ h[format][direction] = CoderMap.new(result, coders, format, arraycoder)
129
+ h
130
+ end
131
+
132
+ @typenames_by_oid = result.inject({}){|h, t| h[t['oid'].to_i] = t['typname']; h }
133
+ end
134
+
135
+ def each_format(direction)
136
+ @maps.map { |f| f[direction] }
137
+ end
138
+
139
+ def map_for(format, direction)
140
+ @maps[format][direction]
141
+ end
142
+ end
143
+
144
+ module Checker
145
+ ValidFormats = { 0 => true, 1 => true }
146
+ ValidDirections = { :encoder => true, :decoder => true }
147
+
148
+ protected def check_format_and_direction(format, direction)
149
+ raise(ArgumentError, "Invalid format value %p" % format) unless ValidFormats[format]
150
+ raise(ArgumentError, "Invalid direction %p" % direction) unless ValidDirections[direction]
151
+ end
152
+
153
+ protected def build_coder_maps(conn_or_maps, registry: nil)
154
+ if conn_or_maps.is_a?(PG::BasicTypeRegistry::CoderMapsBundle)
155
+ raise ArgumentError, "registry argument must be given to CoderMapsBundle" if registry
156
+ conn_or_maps
157
+ else
158
+ PG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, registry: registry)
159
+ end
160
+ end
161
+ end
162
+
163
+ include Checker
164
+
165
+ def initialize
166
+ # The key of these hashs maps to the `typname` column from the table pg_type.
167
+ @coders_by_name = []
168
+ end
169
+
170
+ # Retrieve a Hash of all en- or decoders for a given wire format.
171
+ # The hash key is the name as defined in table +pg_type+.
172
+ # The hash value is the registered coder object.
173
+ def coders_for(format, direction)
174
+ check_format_and_direction(format, direction)
175
+ @coders_by_name[format]&.[](direction)
176
+ end
177
+
178
+ # Register an encoder or decoder instance for casting a PostgreSQL type.
179
+ #
180
+ # Coder#name must correspond to the +typname+ column in the +pg_type+ table.
181
+ # Coder#format can be 0 for text format and 1 for binary.
182
+ def register_coder(coder)
183
+ h = @coders_by_name[coder.format] ||= { encoder: {}, decoder: {} }
184
+ name = coder.name || raise(ArgumentError, "name of #{coder.inspect} must be defined")
185
+ h[:encoder][name] = coder if coder.respond_to?(:encode)
186
+ h[:decoder][name] = coder if coder.respond_to?(:decode)
187
+ self
188
+ end
189
+
190
+ # Register the given +encoder_class+ and/or +decoder_class+ for casting a PostgreSQL type.
191
+ #
192
+ # +name+ must correspond to the +typname+ column in the +pg_type+ table.
193
+ # +format+ can be 0 for text format and 1 for binary.
194
+ def register_type(format, name, encoder_class, decoder_class)
195
+ register_coder(encoder_class.new(name: name, format: format)) if encoder_class
196
+ register_coder(decoder_class.new(name: name, format: format)) if decoder_class
197
+ self
198
+ end
199
+
200
+ # Alias the +old+ type to the +new+ type.
201
+ def alias_type(format, new, old)
202
+ [:encoder, :decoder].each do |ende|
203
+ enc = @coders_by_name[format][ende][old]
204
+ if enc
205
+ @coders_by_name[format][ende][new] = enc
206
+ else
207
+ @coders_by_name[format][ende].delete(new)
208
+ end
209
+ end
210
+ self
211
+ end
212
+
213
+ # Populate the registry with all builtin types of ruby-pg
214
+ def register_default_types
215
+ register_type 0, 'int2', PG::TextEncoder::Integer, PG::TextDecoder::Integer
216
+ alias_type 0, 'int4', 'int2'
217
+ alias_type 0, 'int8', 'int2'
218
+ alias_type 0, 'oid', 'int2'
219
+
220
+ register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
221
+ register_type 0, 'text', PG::TextEncoder::String, PG::TextDecoder::String
222
+ alias_type 0, 'varchar', 'text'
223
+ alias_type 0, 'char', 'text'
224
+ alias_type 0, 'bpchar', 'text'
225
+ alias_type 0, 'xml', 'text'
226
+ alias_type 0, 'name', 'text'
227
+
228
+ # FIXME: why are we keeping these types as strings?
229
+ # alias_type 'tsvector', 'text'
230
+ # alias_type 'interval', 'text'
231
+ # alias_type 'macaddr', 'text'
232
+ # alias_type 'uuid', 'text'
233
+ #
234
+ # register_type 'money', OID::Money.new
235
+ # There is no PG::TextEncoder::Bytea, because it's simple and more efficient to send bytea-data
236
+ # in binary format, either with PG::BinaryEncoder::Bytea or in Hash param format.
237
+ register_type 0, 'bytea', nil, PG::TextDecoder::Bytea
238
+ register_type 0, 'bool', PG::TextEncoder::Boolean, PG::TextDecoder::Boolean
239
+ # register_type 'bit', OID::Bit.new
240
+ # register_type 'varbit', OID::Bit.new
241
+
242
+ register_type 0, 'float4', PG::TextEncoder::Float, PG::TextDecoder::Float
243
+ alias_type 0, 'float8', 'float4'
244
+
245
+ register_type 0, 'timestamp', PG::TextEncoder::TimestampWithoutTimeZone, PG::TextDecoder::TimestampWithoutTimeZone
246
+ register_type 0, 'timestamptz', PG::TextEncoder::TimestampWithTimeZone, PG::TextDecoder::TimestampWithTimeZone
247
+ register_type 0, 'date', PG::TextEncoder::Date, PG::TextDecoder::Date
248
+ # register_type 'time', OID::Time.new
249
+ #
250
+ # register_type 'path', OID::Text.new
251
+ # register_type 'point', OID::Point.new
252
+ # register_type 'polygon', OID::Text.new
253
+ # register_type 'circle', OID::Text.new
254
+ # register_type 'hstore', OID::Hstore.new
255
+ register_type 0, 'json', PG::TextEncoder::JSON, PG::TextDecoder::JSON
256
+ alias_type 0, 'jsonb', 'json'
257
+ # register_type 'citext', OID::Text.new
258
+ # register_type 'ltree', OID::Text.new
259
+ #
260
+ register_type 0, 'inet', PG::TextEncoder::Inet, PG::TextDecoder::Inet
261
+ alias_type 0, 'cidr', 'inet'
262
+
263
+
264
+
265
+ register_type 1, 'int2', PG::BinaryEncoder::Int2, PG::BinaryDecoder::Integer
266
+ register_type 1, 'int4', PG::BinaryEncoder::Int4, PG::BinaryDecoder::Integer
267
+ register_type 1, 'int8', PG::BinaryEncoder::Int8, PG::BinaryDecoder::Integer
268
+ alias_type 1, 'oid', 'int2'
269
+
270
+ register_type 1, 'text', PG::BinaryEncoder::String, PG::BinaryDecoder::String
271
+ alias_type 1, 'varchar', 'text'
272
+ alias_type 1, 'char', 'text'
273
+ alias_type 1, 'bpchar', 'text'
274
+ alias_type 1, 'xml', 'text'
275
+ alias_type 1, 'name', 'text'
276
+
277
+ register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea
278
+ register_type 1, 'bool', PG::BinaryEncoder::Boolean, PG::BinaryDecoder::Boolean
279
+ register_type 1, 'float4', nil, PG::BinaryDecoder::Float
280
+ register_type 1, 'float8', nil, PG::BinaryDecoder::Float
281
+ register_type 1, 'timestamp', nil, PG::BinaryDecoder::TimestampUtc
282
+ register_type 1, 'timestamptz', nil, PG::BinaryDecoder::TimestampUtcToLocal
283
+
284
+ self
285
+ end
286
+
287
+ alias define_default_types register_default_types
288
+
289
+ # @private
290
+ DEFAULT_TYPE_REGISTRY = PG::BasicTypeRegistry.new.register_default_types
291
+
292
+ # Delegate class method calls to DEFAULT_TYPE_REGISTRY
293
+ class << self
294
+ %i[ register_coder register_type alias_type ].each do |meth|
295
+ define_method(meth) do |*args|
296
+ warn "PG::BasicTypeRegistry.#{meth} is deprecated. Please use your own instance by PG::BasicTypeRegistry.new instead!"
297
+ DEFAULT_TYPE_REGISTRY.send(meth, *args)
298
+ end
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ module PG
5
+ module BinaryDecoder
6
+ # Convenience classes for timezone options
7
+ class TimestampUtc < Timestamp
8
+ def initialize(params={})
9
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_UTC))
10
+ end
11
+ end
12
+ class TimestampUtcToLocal < Timestamp
13
+ def initialize(params={})
14
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL))
15
+ end
16
+ end
17
+ class TimestampLocal < Timestamp
18
+ def initialize(params={})
19
+ super(params.merge(flags: PG::Coder::TIMESTAMP_DB_LOCAL | PG::Coder::TIMESTAMP_APP_LOCAL))
20
+ end
21
+ end
22
+ end
23
+ end # module PG
data/lib/pg/coder.rb ADDED
@@ -0,0 +1,104 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ module PG
5
+
6
+ class Coder
7
+
8
+ module BinaryFormatting
9
+ Params = { format: 1 }
10
+ def initialize( params={} )
11
+ super(Params.merge(params))
12
+ end
13
+ end
14
+
15
+
16
+ # Create a new coder object based on the attribute Hash.
17
+ def initialize(params={})
18
+ params.each do |key, val|
19
+ send("#{key}=", val)
20
+ end
21
+ end
22
+
23
+ def dup
24
+ self.class.new(to_h)
25
+ end
26
+
27
+ # Returns coder attributes as Hash.
28
+ def to_h
29
+ {
30
+ oid: oid,
31
+ format: format,
32
+ flags: flags,
33
+ name: name,
34
+ }
35
+ end
36
+
37
+ def ==(v)
38
+ self.class == v.class && to_h == v.to_h
39
+ end
40
+
41
+ def marshal_dump
42
+ Marshal.dump(to_h)
43
+ end
44
+
45
+ def marshal_load(str)
46
+ initialize Marshal.load(str)
47
+ end
48
+
49
+ def inspect
50
+ str = self.to_s
51
+ oid_str = " oid=#{oid}" unless oid==0
52
+ format_str = " format=#{format}" unless format==0
53
+ name_str = " #{name.inspect}" if name
54
+ str[-1,0] = "#{name_str} #{oid_str}#{format_str}"
55
+ str
56
+ end
57
+
58
+ def inspect_short
59
+ str = case format
60
+ when 0 then "T"
61
+ when 1 then "B"
62
+ else format.to_s
63
+ end
64
+ str += "E" if respond_to?(:encode)
65
+ str += "D" if respond_to?(:decode)
66
+
67
+ "#{name || self.class.name}:#{str}"
68
+ end
69
+ end
70
+
71
+ class CompositeCoder < Coder
72
+ def to_h
73
+ super.merge!({
74
+ elements_type: elements_type,
75
+ needs_quotation: needs_quotation?,
76
+ delimiter: delimiter,
77
+ })
78
+ end
79
+
80
+ def inspect
81
+ str = super
82
+ str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation"
83
+ str
84
+ end
85
+ end
86
+
87
+ class CopyCoder < Coder
88
+ def to_h
89
+ super.merge!({
90
+ type_map: type_map,
91
+ delimiter: delimiter,
92
+ null_string: null_string,
93
+ })
94
+ end
95
+ end
96
+
97
+ class RecordCoder < Coder
98
+ def to_h
99
+ super.merge!({
100
+ type_map: type_map,
101
+ })
102
+ end
103
+ end
104
+ end # module PG