pg 1.4.4 → 1.5.9
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/Gemfile +6 -0
- data/{History.rdoc → History.md} +303 -151
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +16 -4
- data/Rakefile.cross +15 -14
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +8 -5
- data/ext/errorcodes.txt +3 -5
- data/ext/extconf.rb +7 -0
- data/ext/pg.c +15 -30
- data/ext/pg.h +10 -6
- data/ext/pg_binary_decoder.c +81 -0
- data/ext/pg_binary_encoder.c +224 -0
- data/ext/pg_coder.c +16 -7
- data/ext/pg_connection.c +220 -82
- data/ext/pg_copy_coder.c +315 -22
- data/ext/pg_record_coder.c +11 -10
- data/ext/pg_result.c +93 -19
- data/ext/pg_text_decoder.c +31 -10
- data/ext/pg_text_encoder.c +38 -19
- data/ext/pg_tuple.c +34 -31
- data/ext/pg_type_map.c +3 -2
- data/ext/pg_type_map_all_strings.c +2 -2
- data/ext/pg_type_map_by_class.c +5 -3
- data/ext/pg_type_map_by_column.c +7 -3
- data/ext/pg_type_map_by_oid.c +7 -4
- data/ext/pg_type_map_in_ruby.c +5 -2
- data/lib/pg/basic_type_map_based_on_result.rb +21 -1
- data/lib/pg/basic_type_map_for_queries.rb +19 -10
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +44 -34
- 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/coder.rb +15 -13
- data/lib/pg/connection.rb +158 -64
- data/lib/pg/exceptions.rb +13 -0
- 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 +1 -1
- data/lib/pg.rb +65 -15
- data/pg.gemspec +7 -3
- data/rakelib/task_extension.rb +1 -1
- data.tar.gz.sig +2 -4
- metadata +104 -46
- metadata.gz.sig +0 -0
- data/.appveyor.yml +0 -36
- data/.gems +0 -6
- data/.gemtest +0 -0
- data/.github/workflows/binary-gems.yml +0 -86
- data/.github/workflows/source-gem.yml +0 -131
- data/.gitignore +0 -13
- data/.hgsigs +0 -34
- data/.hgtags +0 -41
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -49
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -233
- 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
@@ -39,7 +39,8 @@ class PG::BasicTypeRegistry
|
|
39
39
|
oid
|
40
40
|
bool
|
41
41
|
date timestamp timestamptz
|
42
|
-
].inject({}){|h,e| h[e] = true; h }
|
42
|
+
].inject({}){|h,e| h[e] = true; h }.freeze
|
43
|
+
private_constant :DONT_QUOTE_TYPES
|
43
44
|
|
44
45
|
def initialize(result, coders_by_name, format, arraycoder)
|
45
46
|
coder_map = {}
|
@@ -52,7 +53,7 @@ class PG::BasicTypeRegistry
|
|
52
53
|
coder.oid = row['oid'].to_i
|
53
54
|
coder.name = row['typname']
|
54
55
|
coder.format = format
|
55
|
-
coder_map[coder.oid] = coder
|
56
|
+
coder_map[coder.oid] = coder.freeze
|
56
57
|
end
|
57
58
|
|
58
59
|
if arraycoder
|
@@ -67,13 +68,14 @@ class PG::BasicTypeRegistry
|
|
67
68
|
coder.format = format
|
68
69
|
coder.elements_type = elements_coder
|
69
70
|
coder.needs_quotation = !DONT_QUOTE_TYPES[elements_coder.name]
|
70
|
-
coder_map[coder.oid] = coder
|
71
|
+
coder_map[coder.oid] = coder.freeze
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
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 }
|
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
|
77
79
|
end
|
78
80
|
|
79
81
|
attr_reader :coders
|
@@ -117,6 +119,11 @@ class PG::BasicTypeRegistry
|
|
117
119
|
JOIN pg_proc as ti ON ti.oid = t.typinput
|
118
120
|
SQL
|
119
121
|
|
122
|
+
init_maps(registry, result.freeze)
|
123
|
+
freeze
|
124
|
+
end
|
125
|
+
|
126
|
+
private def init_maps(registry, result)
|
120
127
|
@maps = [
|
121
128
|
[0, :encoder, PG::TextEncoder::Array],
|
122
129
|
[0, :decoder, PG::TextDecoder::Array],
|
@@ -127,9 +134,9 @@ class PG::BasicTypeRegistry
|
|
127
134
|
h[format] ||= {}
|
128
135
|
h[format][direction] = CoderMap.new(result, coders, format, arraycoder)
|
129
136
|
h
|
130
|
-
end
|
137
|
+
end.each{|h| h.freeze }.freeze
|
131
138
|
|
132
|
-
@typenames_by_oid = result.inject({}){|h, t| h[t['oid'].to_i] = t['typname']; h }
|
139
|
+
@typenames_by_oid = result.inject({}){|h, t| h[t['oid'].to_i] = t['typname']; h }.freeze
|
133
140
|
end
|
134
141
|
|
135
142
|
def each_format(direction)
|
@@ -142,8 +149,9 @@ class PG::BasicTypeRegistry
|
|
142
149
|
end
|
143
150
|
|
144
151
|
module Checker
|
145
|
-
ValidFormats = { 0 => true, 1 => true }
|
146
|
-
ValidDirections = { :encoder => true, :decoder => true }
|
152
|
+
ValidFormats = { 0 => true, 1 => true }.freeze
|
153
|
+
ValidDirections = { :encoder => true, :decoder => true }.freeze
|
154
|
+
private_constant :ValidFormats, :ValidDirections
|
147
155
|
|
148
156
|
protected def check_format_and_direction(format, direction)
|
149
157
|
raise(ArgumentError, "Invalid format value %p" % format) unless ValidFormats[format]
|
@@ -155,7 +163,7 @@ class PG::BasicTypeRegistry
|
|
155
163
|
raise ArgumentError, "registry argument must be given to CoderMapsBundle" if registry
|
156
164
|
conn_or_maps
|
157
165
|
else
|
158
|
-
PG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, registry: registry)
|
166
|
+
PG::BasicTypeRegistry::CoderMapsBundle.new(conn_or_maps, registry: registry).freeze
|
159
167
|
end
|
160
168
|
end
|
161
169
|
end
|
@@ -163,7 +171,14 @@ class PG::BasicTypeRegistry
|
|
163
171
|
include Checker
|
164
172
|
|
165
173
|
def initialize
|
166
|
-
#
|
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
|
167
182
|
@coders_by_name = []
|
168
183
|
end
|
169
184
|
|
@@ -192,8 +207,8 @@ class PG::BasicTypeRegistry
|
|
192
207
|
# +name+ must correspond to the +typname+ column in the +pg_type+ table.
|
193
208
|
# +format+ can be 0 for text format and 1 for binary.
|
194
209
|
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
|
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
|
197
212
|
self
|
198
213
|
end
|
199
214
|
|
@@ -217,7 +232,11 @@ class PG::BasicTypeRegistry
|
|
217
232
|
alias_type 0, 'int8', 'int2'
|
218
233
|
alias_type 0, 'oid', 'int2'
|
219
234
|
|
220
|
-
|
235
|
+
begin
|
236
|
+
PG.require_bigdecimal_without_warning
|
237
|
+
register_type 0, 'numeric', PG::TextEncoder::Numeric, PG::TextDecoder::Numeric
|
238
|
+
rescue LoadError
|
239
|
+
end
|
221
240
|
register_type 0, 'text', PG::TextEncoder::String, PG::TextDecoder::String
|
222
241
|
alias_type 0, 'varchar', 'text'
|
223
242
|
alias_type 0, 'char', 'text'
|
@@ -232,9 +251,7 @@ class PG::BasicTypeRegistry
|
|
232
251
|
# alias_type 'uuid', 'text'
|
233
252
|
#
|
234
253
|
# register_type 'money', OID::Money.new
|
235
|
-
|
236
|
-
# in binary format, either with PG::BinaryEncoder::Bytea or in Hash param format.
|
237
|
-
register_type 0, 'bytea', nil, PG::TextDecoder::Bytea
|
254
|
+
register_type 0, 'bytea', PG::TextEncoder::Bytea, PG::TextDecoder::Bytea
|
238
255
|
register_type 0, 'bool', PG::TextEncoder::Boolean, PG::TextDecoder::Boolean
|
239
256
|
# register_type 'bit', OID::Bit.new
|
240
257
|
# register_type 'varbit', OID::Bit.new
|
@@ -242,6 +259,7 @@ class PG::BasicTypeRegistry
|
|
242
259
|
register_type 0, 'float4', PG::TextEncoder::Float, PG::TextDecoder::Float
|
243
260
|
alias_type 0, 'float8', 'float4'
|
244
261
|
|
262
|
+
# For compatibility reason the timestamp in text format is encoded as local time (TimestampWithoutTimeZone) instead of UTC
|
245
263
|
register_type 0, 'timestamp', PG::TextEncoder::TimestampWithoutTimeZone, PG::TextDecoder::TimestampWithoutTimeZone
|
246
264
|
register_type 0, 'timestamptz', PG::TextEncoder::TimestampWithTimeZone, PG::TextDecoder::TimestampWithTimeZone
|
247
265
|
register_type 0, 'date', PG::TextEncoder::Date, PG::TextDecoder::Date
|
@@ -260,6 +278,7 @@ class PG::BasicTypeRegistry
|
|
260
278
|
register_type 0, 'inet', PG::TextEncoder::Inet, PG::TextDecoder::Inet
|
261
279
|
alias_type 0, 'cidr', 'inet'
|
262
280
|
|
281
|
+
register_type 0, 'record', PG::TextEncoder::Record, PG::TextDecoder::Record
|
263
282
|
|
264
283
|
|
265
284
|
register_type 1, 'int2', PG::BinaryEncoder::Int2, PG::BinaryDecoder::Integer
|
@@ -276,26 +295,17 @@ class PG::BasicTypeRegistry
|
|
276
295
|
|
277
296
|
register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea
|
278
297
|
register_type 1, 'bool', PG::BinaryEncoder::Boolean, PG::BinaryDecoder::Boolean
|
279
|
-
register_type 1, 'float4',
|
280
|
-
register_type 1, 'float8',
|
281
|
-
register_type 1, 'timestamp',
|
282
|
-
register_type 1, 'timestamptz',
|
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
|
283
303
|
|
284
304
|
self
|
285
305
|
end
|
286
306
|
|
287
307
|
alias define_default_types register_default_types
|
288
308
|
|
289
|
-
|
290
|
-
DEFAULT_TYPE_REGISTRY
|
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
|
309
|
+
DEFAULT_TYPE_REGISTRY = PG.make_shareable(PG::BasicTypeRegistry.new.register_default_types)
|
310
|
+
private_constant :DEFAULT_TYPE_REGISTRY
|
301
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
|
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,11 +72,11 @@ module PG
|
|
70
72
|
|
71
73
|
class CompositeCoder < Coder
|
72
74
|
def to_h
|
73
|
-
super
|
75
|
+
{ **super,
|
74
76
|
elements_type: elements_type,
|
75
77
|
needs_quotation: needs_quotation?,
|
76
78
|
delimiter: delimiter,
|
77
|
-
}
|
79
|
+
}
|
78
80
|
end
|
79
81
|
|
80
82
|
def inspect
|
@@ -86,19 +88,19 @@ module PG
|
|
86
88
|
|
87
89
|
class CopyCoder < Coder
|
88
90
|
def to_h
|
89
|
-
super
|
91
|
+
{ **super,
|
90
92
|
type_map: type_map,
|
91
93
|
delimiter: delimiter,
|
92
94
|
null_string: null_string,
|
93
|
-
}
|
95
|
+
}
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
99
|
class RecordCoder < Coder
|
98
100
|
def to_h
|
99
|
-
super
|
101
|
+
{ **super,
|
100
102
|
type_map: type_map,
|
101
|
-
}
|
103
|
+
}
|
102
104
|
end
|
103
105
|
end
|
104
106
|
end # module PG
|