pg 1.2.3 → 1.6.1

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 (135) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +986 -0
  4. data/Gemfile +23 -0
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +300 -0
  7. data/README.md +327 -0
  8. data/Rakefile +123 -144
  9. data/certs/ged.pem +24 -0
  10. data/certs/kanis@comcard.de.pem +20 -0
  11. data/certs/larskanis-2022.pem +26 -0
  12. data/certs/larskanis-2023.pem +24 -0
  13. data/certs/larskanis-2024.pem +24 -0
  14. data/ext/errorcodes.def +16 -5
  15. data/ext/errorcodes.rb +0 -0
  16. data/ext/errorcodes.txt +5 -5
  17. data/ext/extconf.rb +259 -33
  18. data/ext/gvl_wrappers.c +17 -2
  19. data/ext/gvl_wrappers.h +56 -0
  20. data/ext/pg.c +89 -63
  21. data/ext/pg.h +31 -8
  22. data/ext/pg_binary_decoder.c +232 -1
  23. data/ext/pg_binary_encoder.c +428 -1
  24. data/ext/pg_cancel_connection.c +360 -0
  25. data/ext/pg_coder.c +148 -36
  26. data/ext/pg_connection.c +1365 -817
  27. data/ext/pg_copy_coder.c +360 -38
  28. data/ext/pg_errors.c +1 -1
  29. data/ext/pg_record_coder.c +56 -25
  30. data/ext/pg_result.c +187 -76
  31. data/ext/pg_text_decoder.c +32 -11
  32. data/ext/pg_text_encoder.c +65 -33
  33. data/ext/pg_tuple.c +84 -61
  34. data/ext/pg_type_map.c +44 -10
  35. data/ext/pg_type_map_all_strings.c +17 -3
  36. data/ext/pg_type_map_by_class.c +54 -27
  37. data/ext/pg_type_map_by_column.c +74 -31
  38. data/ext/pg_type_map_by_mri_type.c +48 -19
  39. data/ext/pg_type_map_by_oid.c +61 -27
  40. data/ext/pg_type_map_in_ruby.c +55 -21
  41. data/ext/pg_util.c +2 -2
  42. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  43. data/lib/pg/basic_type_map_for_queries.rb +206 -0
  44. data/lib/pg/basic_type_map_for_results.rb +104 -0
  45. data/lib/pg/basic_type_registry.rb +311 -0
  46. data/lib/pg/binary_decoder/date.rb +9 -0
  47. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  48. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  49. data/lib/pg/cancel_connection.rb +53 -0
  50. data/lib/pg/coder.rb +18 -14
  51. data/lib/pg/connection.rb +894 -91
  52. data/lib/pg/exceptions.rb +20 -1
  53. data/lib/pg/text_decoder/date.rb +21 -0
  54. data/lib/pg/text_decoder/inet.rb +9 -0
  55. data/lib/pg/text_decoder/json.rb +17 -0
  56. data/lib/pg/text_decoder/numeric.rb +9 -0
  57. data/lib/pg/text_decoder/timestamp.rb +30 -0
  58. data/lib/pg/text_encoder/date.rb +13 -0
  59. data/lib/pg/text_encoder/inet.rb +31 -0
  60. data/lib/pg/text_encoder/json.rb +17 -0
  61. data/lib/pg/text_encoder/numeric.rb +9 -0
  62. data/lib/pg/text_encoder/timestamp.rb +24 -0
  63. data/lib/pg/version.rb +4 -0
  64. data/lib/pg.rb +109 -39
  65. data/misc/openssl-pg-segfault.rb +31 -0
  66. data/misc/postgres/History.txt +9 -0
  67. data/misc/postgres/Manifest.txt +5 -0
  68. data/misc/postgres/README.txt +21 -0
  69. data/misc/postgres/Rakefile +21 -0
  70. data/misc/postgres/lib/postgres.rb +16 -0
  71. data/misc/ruby-pg/History.txt +9 -0
  72. data/misc/ruby-pg/Manifest.txt +5 -0
  73. data/misc/ruby-pg/README.txt +21 -0
  74. data/misc/ruby-pg/Rakefile +21 -0
  75. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  76. data/misc/yugabyte/Dockerfile +9 -0
  77. data/misc/yugabyte/docker-compose.yml +28 -0
  78. data/misc/yugabyte/pg-test.rb +45 -0
  79. data/pg.gemspec +38 -0
  80. data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
  81. data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
  82. data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  83. data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  84. data/rakelib/pg_gem_helper.rb +64 -0
  85. data/rakelib/task_extension.rb +46 -0
  86. data/sample/array_insert.rb +20 -0
  87. data/sample/async_api.rb +102 -0
  88. data/sample/async_copyto.rb +39 -0
  89. data/sample/async_mixed.rb +56 -0
  90. data/sample/check_conn.rb +21 -0
  91. data/sample/copydata.rb +71 -0
  92. data/sample/copyfrom.rb +81 -0
  93. data/sample/copyto.rb +19 -0
  94. data/sample/cursor.rb +21 -0
  95. data/sample/disk_usage_report.rb +177 -0
  96. data/sample/issue-119.rb +94 -0
  97. data/sample/losample.rb +69 -0
  98. data/sample/minimal-testcase.rb +17 -0
  99. data/sample/notify_wait.rb +72 -0
  100. data/sample/pg_statistics.rb +285 -0
  101. data/sample/replication_monitor.rb +222 -0
  102. data/sample/test_binary_values.rb +33 -0
  103. data/sample/wal_shipper.rb +434 -0
  104. data/sample/warehouse_partitions.rb +311 -0
  105. data.tar.gz.sig +0 -0
  106. metadata +139 -213
  107. metadata.gz.sig +0 -0
  108. data/.gemtest +0 -0
  109. data/ChangeLog +0 -0
  110. data/History.rdoc +0 -578
  111. data/Manifest.txt +0 -73
  112. data/README.ja.rdoc +0 -13
  113. data/README.rdoc +0 -213
  114. data/Rakefile.cross +0 -299
  115. data/lib/pg/basic_type_mapping.rb +0 -522
  116. data/lib/pg/binary_decoder.rb +0 -23
  117. data/lib/pg/constants.rb +0 -12
  118. data/lib/pg/text_decoder.rb +0 -46
  119. data/lib/pg/text_encoder.rb +0 -59
  120. data/spec/data/expected_trace.out +0 -26
  121. data/spec/data/random_binary_data +0 -0
  122. data/spec/helpers.rb +0 -380
  123. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  124. data/spec/pg/connection_spec.rb +0 -1949
  125. data/spec/pg/connection_sync_spec.rb +0 -41
  126. data/spec/pg/result_spec.rb +0 -681
  127. data/spec/pg/tuple_spec.rb +0 -333
  128. data/spec/pg/type_map_by_class_spec.rb +0 -138
  129. data/spec/pg/type_map_by_column_spec.rb +0 -226
  130. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  131. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  132. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  133. data/spec/pg/type_map_spec.rb +0 -22
  134. data/spec/pg/type_spec.rb +0 -1123
  135. data/spec/pg_spec.rb +0 -50
@@ -0,0 +1,311 @@
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 }.freeze
43
+ private_constant :DONT_QUOTE_TYPES
44
+
45
+ def initialize(result, coders_by_name, format, arraycoder)
46
+ coder_map = {}
47
+
48
+ arrays, nodes = result.partition { |row| row['typinput'] == 'array_in' }
49
+
50
+ # populate the base types
51
+ nodes.find_all { |row| coders_by_name.key?(row['typname']) }.each do |row|
52
+ coder = coders_by_name[row['typname']].dup
53
+ coder.oid = row['oid'].to_i
54
+ coder.name = row['typname']
55
+ coder.format = format
56
+ coder_map[coder.oid] = coder.freeze
57
+ end
58
+
59
+ if arraycoder
60
+ # populate array types
61
+ arrays.each do |row|
62
+ elements_coder = coder_map[row['typelem'].to_i]
63
+ next unless elements_coder
64
+
65
+ coder = arraycoder.new
66
+ coder.oid = row['oid'].to_i
67
+ coder.name = row['typname']
68
+ coder.format = format
69
+ coder.elements_type = elements_coder
70
+ coder.needs_quotation = !DONT_QUOTE_TYPES[elements_coder.name]
71
+ coder_map[coder.oid] = coder.freeze
72
+ end
73
+ end
74
+
75
+ @coders = coder_map.values.freeze
76
+ @coders_by_name = @coders.inject({}){|h, t| h[t.name] = t; h }.freeze
77
+ @coders_by_oid = @coders.inject({}){|h, t| h[t.oid] = t; h }.freeze
78
+ freeze
79
+ end
80
+
81
+ attr_reader :coders
82
+ attr_reader :coders_by_oid
83
+ attr_reader :coders_by_name
84
+
85
+ def coder_by_name(name)
86
+ @coders_by_name[name]
87
+ end
88
+
89
+ def coder_by_oid(oid)
90
+ @coders_by_oid[oid]
91
+ end
92
+ end
93
+
94
+ # An instance of this class stores CoderMap instances to be used for text and binary wire formats
95
+ # as well as encoder and decoder directions.
96
+ #
97
+ # 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 .
98
+ # It provides 4 separate CoderMap instances for the combinations of the two formats and directions.
99
+ #
100
+ # A PG::BasicTypeRegistry::CoderMapsBundle instance can be used to initialize an instance of
101
+ # * PG::BasicTypeMapForResults
102
+ # * PG::BasicTypeMapForQueries
103
+ # * PG::BasicTypeMapBasedOnResult
104
+ # by passing it instead of the connection object like so:
105
+ #
106
+ # conn = PG::Connection.new
107
+ # maps = PG::BasicTypeRegistry::CoderMapsBundle.new(conn)
108
+ # conn.type_map_for_results = PG::BasicTypeMapForResults.new(maps)
109
+ #
110
+ class CoderMapsBundle
111
+ attr_reader :typenames_by_oid
112
+
113
+ def initialize(connection, registry: nil)
114
+ registry ||= DEFAULT_TYPE_REGISTRY
115
+
116
+ result = connection.exec(<<-SQL).to_a
117
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, ti.proname AS typinput
118
+ FROM pg_type as t
119
+ JOIN pg_proc as ti ON ti.oid = t.typinput
120
+ SQL
121
+
122
+ init_maps(registry, result.freeze)
123
+ freeze
124
+ end
125
+
126
+ private def init_maps(registry, result)
127
+ @maps = [
128
+ [0, :encoder, PG::TextEncoder::Array],
129
+ [0, :decoder, PG::TextDecoder::Array],
130
+ [1, :encoder, PG::BinaryEncoder::Array],
131
+ [1, :decoder, PG::BinaryDecoder::Array],
132
+ ].inject([]) do |h, (format, direction, arraycoder)|
133
+ coders = registry.coders_for(format, direction) || {}
134
+ h[format] ||= {}
135
+ h[format][direction] = CoderMap.new(result, coders, format, arraycoder)
136
+ h
137
+ end.each{|h| h.freeze }.freeze
138
+
139
+ @typenames_by_oid = result.inject({}){|h, t| h[t['oid'].to_i] = t['typname']; h }.freeze
140
+ end
141
+
142
+ def each_format(direction)
143
+ @maps.map { |f| f[direction] }
144
+ end
145
+
146
+ def map_for(format, direction)
147
+ @maps[format][direction]
148
+ end
149
+ end
150
+
151
+ module Checker
152
+ ValidFormats = { 0 => true, 1 => true }.freeze
153
+ ValidDirections = { :encoder => true, :decoder => true }.freeze
154
+ private_constant :ValidFormats, :ValidDirections
155
+
156
+ protected def check_format_and_direction(format, direction)
157
+ raise(ArgumentError, "Invalid format value %p" % format) unless ValidFormats[format]
158
+ raise(ArgumentError, "Invalid direction %p" % direction) unless ValidDirections[direction]
159
+ end
160
+
161
+ protected def build_coder_maps(conn_or_maps, registry: nil)
162
+ if conn_or_maps.is_a?(PG::BasicTypeRegistry::CoderMapsBundle)
163
+ raise ArgumentError, "registry argument must be given to CoderMapsBundle" if registry
164
+ conn_or_maps
165
+ else
166
+ PG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, registry: registry).freeze
167
+ end
168
+ end
169
+ end
170
+
171
+ include Checker
172
+
173
+ def initialize
174
+ # @coders_by_name has a content of
175
+ # Array< Hash< Symbol: Hash< String: Coder > > >
176
+ #
177
+ # The layers are:
178
+ # * index of Array is 0 (text) and 1 (binary)
179
+ # * Symbol key in the middle Hash is :encoder and :decoder
180
+ # * String key in the inner Hash corresponds to the `typname` column in the table pg_type
181
+ # * Coder value in the inner Hash is the associated coder object
182
+ @coders_by_name = []
183
+ end
184
+
185
+ # Retrieve a Hash of all en- or decoders for a given wire format.
186
+ # The hash key is the name as defined in table +pg_type+.
187
+ # The hash value is the registered coder object.
188
+ def coders_for(format, direction)
189
+ check_format_and_direction(format, direction)
190
+ @coders_by_name[format]&.[](direction)
191
+ end
192
+
193
+ # Register an encoder or decoder instance for casting a PostgreSQL type.
194
+ #
195
+ # Coder#name must correspond to the +typname+ column in the +pg_type+ table.
196
+ # Coder#format can be 0 for text format and 1 for binary.
197
+ def register_coder(coder)
198
+ h = @coders_by_name[coder.format] ||= { encoder: {}, decoder: {} }
199
+ name = coder.name || raise(ArgumentError, "name of #{coder.inspect} must be defined")
200
+ h[:encoder][name] = coder if coder.respond_to?(:encode)
201
+ h[:decoder][name] = coder if coder.respond_to?(:decode)
202
+ self
203
+ end
204
+
205
+ # Register the given +encoder_class+ and/or +decoder_class+ for casting a PostgreSQL type.
206
+ #
207
+ # +name+ must correspond to the +typname+ column in the +pg_type+ table.
208
+ # +format+ can be 0 for text format and 1 for binary.
209
+ def register_type(format, name, encoder_class, decoder_class)
210
+ register_coder(encoder_class.new(name: name, format: format).freeze) if encoder_class
211
+ register_coder(decoder_class.new(name: name, format: format).freeze) if decoder_class
212
+ self
213
+ end
214
+
215
+ # Alias the +old+ type to the +new+ type.
216
+ def alias_type(format, new, old)
217
+ [:encoder, :decoder].each do |ende|
218
+ enc = @coders_by_name[format][ende][old]
219
+ if enc
220
+ @coders_by_name[format][ende][new] = enc
221
+ else
222
+ @coders_by_name[format][ende].delete(new)
223
+ end
224
+ end
225
+ self
226
+ end
227
+
228
+ # Populate the registry with all builtin types of ruby-pg
229
+ def register_default_types
230
+ register_type 0, 'int2', PG::TextEncoder::Integer, PG::TextDecoder::Integer
231
+ alias_type 0, 'int4', 'int2'
232
+ alias_type 0, 'int8', 'int2'
233
+ alias_type 0, 'oid', 'int2'
234
+
235
+ begin
236
+ PG.require_bigdecimal_without_warning
237
+ register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
238
+ rescue LoadError
239
+ end
240
+ register_type 0, 'text', PG::TextEncoder::String, PG::TextDecoder::String
241
+ alias_type 0, 'varchar', 'text'
242
+ alias_type 0, 'char', 'text'
243
+ alias_type 0, 'bpchar', 'text'
244
+ alias_type 0, 'xml', 'text'
245
+ alias_type 0, 'name', 'text'
246
+
247
+ # FIXME: why are we keeping these types as strings?
248
+ # alias_type 'tsvector', 'text'
249
+ # alias_type 'interval', 'text'
250
+ # alias_type 'macaddr', 'text'
251
+ # alias_type 'uuid', 'text'
252
+ #
253
+ # register_type 'money', OID::Money.new
254
+ register_type 0, 'bytea', PG::TextEncoder::Bytea, PG::TextDecoder::Bytea
255
+ register_type 0, 'bool', PG::TextEncoder::Boolean, PG::TextDecoder::Boolean
256
+ # register_type 'bit', OID::Bit.new
257
+ # register_type 'varbit', OID::Bit.new
258
+
259
+ register_type 0, 'float4', PG::TextEncoder::Float, PG::TextDecoder::Float
260
+ alias_type 0, 'float8', 'float4'
261
+
262
+ # For compatibility reason the timestamp in text format is encoded as local time (TimestampWithoutTimeZone) instead of UTC
263
+ register_type 0, 'timestamp', PG::TextEncoder::TimestampWithoutTimeZone, PG::TextDecoder::TimestampWithoutTimeZone
264
+ register_type 0, 'timestamptz', PG::TextEncoder::TimestampWithTimeZone, PG::TextDecoder::TimestampWithTimeZone
265
+ register_type 0, 'date', PG::TextEncoder::Date, PG::TextDecoder::Date
266
+ # register_type 'time', OID::Time.new
267
+ #
268
+ # register_type 'path', OID::Text.new
269
+ # register_type 'point', OID::Point.new
270
+ # register_type 'polygon', OID::Text.new
271
+ # register_type 'circle', OID::Text.new
272
+ # register_type 'hstore', OID::Hstore.new
273
+ register_type 0, 'json', PG::TextEncoder::JSON, PG::TextDecoder::JSON
274
+ alias_type 0, 'jsonb', 'json'
275
+ # register_type 'citext', OID::Text.new
276
+ # register_type 'ltree', OID::Text.new
277
+ #
278
+ register_type 0, 'inet', PG::TextEncoder::Inet, PG::TextDecoder::Inet
279
+ alias_type 0, 'cidr', 'inet'
280
+
281
+ register_type 0, 'record', PG::TextEncoder::Record, PG::TextDecoder::Record
282
+
283
+
284
+ register_type 1, 'int2', PG::BinaryEncoder::Int2, PG::BinaryDecoder::Integer
285
+ register_type 1, 'int4', PG::BinaryEncoder::Int4, PG::BinaryDecoder::Integer
286
+ register_type 1, 'int8', PG::BinaryEncoder::Int8, PG::BinaryDecoder::Integer
287
+ alias_type 1, 'oid', 'int2'
288
+
289
+ register_type 1, 'text', PG::BinaryEncoder::String, PG::BinaryDecoder::String
290
+ alias_type 1, 'varchar', 'text'
291
+ alias_type 1, 'char', 'text'
292
+ alias_type 1, 'bpchar', 'text'
293
+ alias_type 1, 'xml', 'text'
294
+ alias_type 1, 'name', 'text'
295
+
296
+ register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea
297
+ register_type 1, 'bool', PG::BinaryEncoder::Boolean, PG::BinaryDecoder::Boolean
298
+ register_type 1, 'float4', PG::BinaryEncoder::Float4, PG::BinaryDecoder::Float
299
+ register_type 1, 'float8', PG::BinaryEncoder::Float8, PG::BinaryDecoder::Float
300
+ register_type 1, 'timestamp', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtc
301
+ register_type 1, 'timestamptz', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtcToLocal
302
+ register_type 1, 'date', PG::BinaryEncoder::Date, PG::BinaryDecoder::Date
303
+
304
+ self
305
+ end
306
+
307
+ alias define_default_types register_default_types
308
+
309
+ DEFAULT_TYPE_REGISTRY = PG.make_shareable(PG::BasicTypeRegistry.new.register_default_types)
310
+ private_constant :DEFAULT_TYPE_REGISTRY
311
+ end
@@ -0,0 +1,9 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ module PG
5
+ module BinaryDecoder
6
+ # Init C part of the decoder
7
+ init_date
8
+ end
9
+ end # module PG
@@ -0,0 +1,26 @@
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(hash={}, **kwargs)
9
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
10
+ super(**hash, **kwargs, flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_UTC)
11
+ end
12
+ end
13
+ class TimestampUtcToLocal < Timestamp
14
+ def initialize(hash={}, **kwargs)
15
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
16
+ super(**hash, **kwargs, flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL)
17
+ end
18
+ end
19
+ class TimestampLocal < Timestamp
20
+ def initialize(hash={}, **kwargs)
21
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
22
+ super(**hash, **kwargs, flags: PG::Coder::TIMESTAMP_DB_LOCAL | PG::Coder::TIMESTAMP_APP_LOCAL)
23
+ end
24
+ end
25
+ end
26
+ end # module PG
@@ -0,0 +1,20 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ module PG
5
+ module BinaryEncoder
6
+ # Convenience classes for timezone options
7
+ class TimestampUtc < Timestamp
8
+ def initialize(hash={}, **kwargs)
9
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
10
+ super(**hash, **kwargs, flags: PG::Coder::TIMESTAMP_DB_UTC)
11
+ end
12
+ end
13
+ class TimestampLocal < Timestamp
14
+ def initialize(hash={}, **kwargs)
15
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
16
+ super(**hash, **kwargs, flags: PG::Coder::TIMESTAMP_DB_LOCAL)
17
+ end
18
+ end
19
+ end
20
+ end # module PG
@@ -0,0 +1,53 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ if defined?(PG::CancelConnection)
7
+ class PG::CancelConnection
8
+ include PG::Connection::Pollable
9
+
10
+ alias c_initialize initialize
11
+
12
+ def initialize(conn)
13
+ c_initialize(conn)
14
+
15
+ # A cancel connection is always to one destination server only.
16
+ # Prepare conninfo_hash with just enough information to allow a shared polling_loop.
17
+ @host = conn.host
18
+ @hostaddr = conn.hostaddr
19
+ @port = conn.port
20
+
21
+ @conninfo_hash = {
22
+ host: @host,
23
+ hostaddr: @hostaddr,
24
+ port: @port.to_s,
25
+ connect_timeout: conn.conninfo_hash[:connect_timeout],
26
+ }
27
+ end
28
+
29
+ # call-seq:
30
+ # conn.cancel
31
+ #
32
+ # Requests that the server abandons processing of the current command in a blocking manner.
33
+ #
34
+ # If the cancel request wasn't successfully dispatched an error message is raised.
35
+ #
36
+ # Successful dispatch of the cancellation is no guarantee that the request will have any effect, however.
37
+ # If the cancellation is effective, the command being canceled will terminate early and raises an error.
38
+ # If the cancellation fails (say, because the server was already done processing the command), then there will be no visible result at all.
39
+ #
40
+ def cancel
41
+ start
42
+ polling_loop(:poll)
43
+ end
44
+ alias async_cancel cancel
45
+
46
+ # These private methods are there to allow a shared polling_loop.
47
+ private
48
+ attr_reader :host
49
+ attr_reader :hostaddr
50
+ attr_reader :port
51
+ attr_reader :conninfo_hash
52
+ end
53
+ end
data/lib/pg/coder.rb CHANGED
@@ -6,22 +6,24 @@ module PG
6
6
  class Coder
7
7
 
8
8
  module BinaryFormatting
9
- Params = { format: 1 }
10
- def initialize( params={} )
11
- super(params.merge(Params))
9
+ def initialize(hash={}, **kwargs)
10
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) unless hash.empty?
11
+ super(format: 1, **hash, **kwargs)
12
12
  end
13
13
  end
14
14
 
15
15
 
16
16
  # Create a new coder object based on the attribute Hash.
17
- def initialize(params={})
18
- params.each do |key, val|
17
+ def initialize(hash=nil, **kwargs)
18
+ warn("PG::Coder.new(hash) is deprecated. Please use keyword arguments instead! Called from #{caller.first}", category: :deprecated) if hash
19
+
20
+ (hash || kwargs).each do |key, val|
19
21
  send("#{key}=", val)
20
22
  end
21
23
  end
22
24
 
23
25
  def dup
24
- self.class.new(to_h)
26
+ self.class.new(**to_h)
25
27
  end
26
28
 
27
29
  # Returns coder attributes as Hash.
@@ -43,7 +45,7 @@ module PG
43
45
  end
44
46
 
45
47
  def marshal_load(str)
46
- initialize Marshal.load(str)
48
+ initialize(**Marshal.load(str))
47
49
  end
48
50
 
49
51
  def inspect
@@ -70,35 +72,37 @@ module PG
70
72
 
71
73
  class CompositeCoder < Coder
72
74
  def to_h
73
- super.merge!({
75
+ h = { **super,
74
76
  elements_type: elements_type,
75
77
  needs_quotation: needs_quotation?,
76
78
  delimiter: delimiter,
77
- })
79
+ }
80
+ h[:dimensions] = dimensions if dimensions # Write only when set, for Marshal compat with pg<1.6
81
+ h
78
82
  end
79
83
 
80
84
  def inspect
81
85
  str = super
82
- str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation"
86
+ str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation#{dimensions && " #{dimensions} dimensions"}"
83
87
  str
84
88
  end
85
89
  end
86
90
 
87
91
  class CopyCoder < Coder
88
92
  def to_h
89
- super.merge!({
93
+ { **super,
90
94
  type_map: type_map,
91
95
  delimiter: delimiter,
92
96
  null_string: null_string,
93
- })
97
+ }
94
98
  end
95
99
  end
96
100
 
97
101
  class RecordCoder < Coder
98
102
  def to_h
99
- super.merge!({
103
+ { **super,
100
104
  type_map: type_map,
101
- })
105
+ }
102
106
  end
103
107
  end
104
108
  end # module PG