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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +986 -0
- data/Gemfile +23 -0
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +300 -0
- data/README.md +327 -0
- data/Rakefile +123 -144
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +16 -5
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +5 -5
- data/ext/extconf.rb +259 -33
- data/ext/gvl_wrappers.c +17 -2
- data/ext/gvl_wrappers.h +56 -0
- data/ext/pg.c +89 -63
- data/ext/pg.h +31 -8
- data/ext/pg_binary_decoder.c +232 -1
- data/ext/pg_binary_encoder.c +428 -1
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +148 -36
- data/ext/pg_connection.c +1365 -817
- data/ext/pg_copy_coder.c +360 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +56 -25
- data/ext/pg_result.c +187 -76
- data/ext/pg_text_decoder.c +32 -11
- data/ext/pg_text_encoder.c +65 -33
- data/ext/pg_tuple.c +84 -61
- data/ext/pg_type_map.c +44 -10
- data/ext/pg_type_map_all_strings.c +17 -3
- data/ext/pg_type_map_by_class.c +54 -27
- data/ext/pg_type_map_by_column.c +74 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +61 -27
- data/ext/pg_type_map_in_ruby.c +55 -21
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +206 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +311 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +18 -14
- data/lib/pg/connection.rb +894 -91
- data/lib/pg/exceptions.rb +20 -1
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +109 -39
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +38 -0
- data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +139 -213
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/Manifest.txt +0 -73
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/Rakefile.cross +0 -299
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -630
- data/spec/pg/connection_spec.rb +0 -1949
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -1123
- 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,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
|
-
|
10
|
-
|
11
|
-
super(
|
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(
|
18
|
-
|
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
|
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
|
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
|
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
|
103
|
+
{ **super,
|
100
104
|
type_map: type_map,
|
101
|
-
}
|
105
|
+
}
|
102
106
|
end
|
103
107
|
end
|
104
108
|
end # module PG
|