pg 1.4.6 → 1.5.3
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/.appveyor.yml +1 -1
- data/.gitignore +3 -0
- data/History.md +72 -0
- data/README.ja.md +29 -19
- data/README.md +29 -15
- data/Rakefile.cross +1 -1
- data/ext/pg.c +10 -28
- data/ext/pg.h +10 -5
- data/ext/pg_binary_decoder.c +79 -0
- data/ext/pg_binary_encoder.c +224 -0
- data/ext/pg_coder.c +16 -7
- data/ext/pg_connection.c +50 -34
- data/ext/pg_copy_coder.c +306 -17
- data/ext/pg_record_coder.c +5 -4
- data/ext/pg_result.c +91 -17
- data/ext/pg_text_decoder.c +28 -10
- data/ext/pg_text_encoder.c +22 -9
- 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 +13 -8
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +30 -32
- 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 +84 -12
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -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 +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -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 +55 -9
- data/pg.gemspec +1 -1
- data/translation/po/all.pot +170 -135
- data/translation/po/ja.po +365 -186
- data/translation/po4a.cfg +4 -1
- data.tar.gz.sig +0 -0
- metadata +28 -10
- metadata.gz.sig +0 -0
- 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/ext/pg_type_map_by_column.c
CHANGED
@@ -232,7 +232,7 @@ static const rb_data_type_t pg_tmbc_type = {
|
|
232
232
|
},
|
233
233
|
&pg_typemap_type,
|
234
234
|
0,
|
235
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
235
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
236
236
|
};
|
237
237
|
|
238
238
|
static VALUE
|
@@ -266,13 +266,14 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
266
266
|
t_tmbc *this;
|
267
267
|
int conv_ary_len;
|
268
268
|
|
269
|
+
rb_check_frozen(self);
|
269
270
|
Check_Type(conv_ary, T_ARRAY);
|
270
271
|
conv_ary_len = RARRAY_LENINT(conv_ary);
|
271
272
|
this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
|
272
273
|
/* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
|
273
274
|
this->nfields = 0;
|
274
275
|
this->typemap.funcs = pg_tmbc_funcs;
|
275
|
-
this->typemap.default_typemap
|
276
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
276
277
|
RTYPEDDATA_DATA(self) = this;
|
277
278
|
|
278
279
|
for(i=0; i<conv_ary_len; i++)
|
@@ -283,8 +284,11 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
|
|
283
284
|
/* no type cast */
|
284
285
|
this->convs[i].cconv = NULL;
|
285
286
|
} else {
|
287
|
+
t_pg_coder *p_coder;
|
286
288
|
/* Check argument type and store the coder pointer */
|
287
|
-
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type,
|
289
|
+
TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
|
290
|
+
RB_OBJ_WRITTEN(self, Qnil, p_coder->coder_obj);
|
291
|
+
this->convs[i].cconv = p_coder;
|
288
292
|
}
|
289
293
|
}
|
290
294
|
|
data/ext/pg_type_map_by_oid.c
CHANGED
@@ -194,7 +194,7 @@ static const rb_data_type_t pg_tmbo_type = {
|
|
194
194
|
},
|
195
195
|
&pg_typemap_type,
|
196
196
|
0,
|
197
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
197
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
198
198
|
};
|
199
199
|
|
200
200
|
static VALUE
|
@@ -212,11 +212,11 @@ pg_tmbo_s_allocate( VALUE klass )
|
|
212
212
|
this->typemap.funcs.typecast_result_value = pg_tmbo_result_value;
|
213
213
|
this->typemap.funcs.typecast_query_param = pg_typemap_typecast_query_param;
|
214
214
|
this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
|
215
|
-
this->typemap.default_typemap
|
215
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
216
216
|
this->max_rows_for_online_lookup = 10;
|
217
217
|
|
218
218
|
for( i=0; i<2; i++){
|
219
|
-
this->format[i].oid_to_coder
|
219
|
+
RB_OBJ_WRITE(self, &this->format[i].oid_to_coder, rb_hash_new());
|
220
220
|
}
|
221
221
|
|
222
222
|
return self;
|
@@ -242,6 +242,7 @@ pg_tmbo_add_coder( VALUE self, VALUE coder )
|
|
242
242
|
t_pg_coder *p_coder;
|
243
243
|
struct pg_tmbo_oid_cache_entry *p_ce;
|
244
244
|
|
245
|
+
rb_check_frozen(self);
|
245
246
|
TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, p_coder);
|
246
247
|
|
247
248
|
if( p_coder->format < 0 || p_coder->format > 1 )
|
@@ -276,6 +277,7 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
|
|
276
277
|
int i_format = NUM2INT(format);
|
277
278
|
struct pg_tmbo_oid_cache_entry *p_ce;
|
278
279
|
|
280
|
+
rb_check_frozen(self);
|
279
281
|
if( i_format < 0 || i_format > 1 )
|
280
282
|
rb_raise(rb_eArgError, "invalid format code %d", i_format);
|
281
283
|
|
@@ -318,6 +320,7 @@ static VALUE
|
|
318
320
|
pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
|
319
321
|
{
|
320
322
|
t_tmbo *this = RTYPEDDATA_DATA( self );
|
323
|
+
rb_check_frozen(self);
|
321
324
|
this->max_rows_for_online_lookup = NUM2INT(value);
|
322
325
|
return value;
|
323
326
|
}
|
@@ -338,7 +341,7 @@ pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
|
|
338
341
|
* typemap.build_column_map( result )
|
339
342
|
*
|
340
343
|
* This builds a PG::TypeMapByColumn that fits to the given PG::Result object
|
341
|
-
* based on it's type OIDs.
|
344
|
+
* based on it's type OIDs and binary/text format.
|
342
345
|
*
|
343
346
|
*/
|
344
347
|
static VALUE
|
data/ext/pg_type_map_in_ruby.c
CHANGED
@@ -44,7 +44,7 @@ static const rb_data_type_t pg_tmir_type = {
|
|
44
44
|
},
|
45
45
|
&pg_typemap_type,
|
46
46
|
0,
|
47
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
47
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
48
48
|
};
|
49
49
|
|
50
50
|
/*
|
@@ -210,6 +210,9 @@ pg_tmir_typecast_query_param( VALUE self, VALUE param_value, VALUE field )
|
|
210
210
|
* This method is called, when a type map is used for decoding copy data,
|
211
211
|
* before the value is casted.
|
212
212
|
*
|
213
|
+
* Should return the expected number of columns or 0 if the number of columns is unknown.
|
214
|
+
* This number is only used for memory pre-allocation.
|
215
|
+
*
|
213
216
|
*/
|
214
217
|
static VALUE pg_tmir_fit_to_copy_get_dummy( VALUE self ){}
|
215
218
|
#endif
|
@@ -291,7 +294,7 @@ pg_tmir_s_allocate( VALUE klass )
|
|
291
294
|
this->typemap.funcs.typecast_result_value = pg_tmir_result_value;
|
292
295
|
this->typemap.funcs.typecast_query_param = pg_tmir_query_param;
|
293
296
|
this->typemap.funcs.typecast_copy_get = pg_tmir_copy_get;
|
294
|
-
this->typemap.default_typemap
|
297
|
+
RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
|
295
298
|
this->self = self;
|
296
299
|
|
297
300
|
return self;
|
@@ -32,7 +32,27 @@ require 'pg' unless defined?( PG )
|
|
32
32
|
# conn.put_copy_data ['a', 123, [5,4,3]]
|
33
33
|
# end
|
34
34
|
# This inserts a single row into copytable with type casts from ruby to
|
35
|
-
# database types.
|
35
|
+
# database types using text format.
|
36
|
+
#
|
37
|
+
# Very similar with binary format:
|
38
|
+
#
|
39
|
+
# conn.exec( "CREATE TEMP TABLE copytable (t TEXT, i INT, blob bytea, created_at timestamp)" )
|
40
|
+
# # Retrieve table OIDs per empty result set in binary format.
|
41
|
+
# res = conn.exec_params( "SELECT * FROM copytable LIMIT 0", [], 1 )
|
42
|
+
# # Build a type map for common ruby to database type encoders.
|
43
|
+
# btm = PG::BasicTypeMapBasedOnResult.new(conn)
|
44
|
+
# # Build a PG::TypeMapByColumn with encoders suitable for copytable.
|
45
|
+
# tm = btm.build_column_map( res )
|
46
|
+
# row_encoder = PG::BinaryEncoder::CopyRow.new type_map: tm
|
47
|
+
#
|
48
|
+
# conn.copy_data( "COPY copytable FROM STDIN WITH (FORMAT binary)", row_encoder ) do |res|
|
49
|
+
# conn.put_copy_data ['a', 123, "\xff\x00".b, Time.now]
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# This inserts a single row into copytable with type casts from ruby to
|
53
|
+
# database types using binary copy and value format.
|
54
|
+
# Binary COPY is faster than text format but less portable and less readable and pg offers fewer en-/decoders of database types.
|
55
|
+
#
|
36
56
|
class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
|
37
57
|
include PG::BasicTypeRegistry::Checker
|
38
58
|
|
@@ -47,16 +47,20 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
47
47
|
# Options:
|
48
48
|
# * +registry+: Custom type registry, nil for default global registry
|
49
49
|
# * +if_undefined+: Optional +Proc+ object which is called, if no type for an parameter class is not defined in the registry.
|
50
|
+
# The +Proc+ object is called with the name and format of the missing type.
|
51
|
+
# Its return value is not used.
|
50
52
|
def initialize(connection_or_coder_maps, registry: nil, if_undefined: nil)
|
51
53
|
@coder_maps = build_coder_maps(connection_or_coder_maps, registry: registry)
|
52
54
|
@array_encoders_by_klass = array_encoders_by_klass
|
53
55
|
@encode_array_as = :array
|
54
|
-
@if_undefined = if_undefined ||
|
55
|
-
raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
|
56
|
-
}
|
56
|
+
@if_undefined = if_undefined || method(:raise_undefined_type).to_proc
|
57
57
|
init_encoders
|
58
58
|
end
|
59
59
|
|
60
|
+
private def raise_undefined_type(oid_name, format)
|
61
|
+
raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
|
62
|
+
end
|
63
|
+
|
60
64
|
# Change the mechanism that is used to encode ruby array values
|
61
65
|
#
|
62
66
|
# Possible values:
|
@@ -162,7 +166,7 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
162
166
|
@textarray_encoder
|
163
167
|
end
|
164
168
|
|
165
|
-
DEFAULT_TYPE_MAP = {
|
169
|
+
DEFAULT_TYPE_MAP = PG.make_shareable({
|
166
170
|
TrueClass => [1, 'bool', 'bool'],
|
167
171
|
FalseClass => [1, 'bool', 'bool'],
|
168
172
|
# We use text format and no type OID for numbers, because setting the OID can lead
|
@@ -177,9 +181,10 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
177
181
|
Hash => [0, 'json'],
|
178
182
|
Array => :get_array_type,
|
179
183
|
BinaryData => [1, 'bytea'],
|
180
|
-
}
|
184
|
+
})
|
185
|
+
private_constant :DEFAULT_TYPE_MAP
|
181
186
|
|
182
|
-
DEFAULT_ARRAY_TYPE_MAP = {
|
187
|
+
DEFAULT_ARRAY_TYPE_MAP = PG.make_shareable({
|
183
188
|
TrueClass => [0, '_bool'],
|
184
189
|
FalseClass => [0, '_bool'],
|
185
190
|
Integer => [0, '_int8'],
|
@@ -188,6 +193,6 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
|
|
188
193
|
BigDecimal => [0, '_numeric'],
|
189
194
|
Time => [0, '_timestamptz'],
|
190
195
|
IPAddr => [0, '_inet'],
|
191
|
-
}
|
192
|
-
|
196
|
+
})
|
197
|
+
private_constant :DEFAULT_ARRAY_TYPE_MAP
|
193
198
|
end
|
@@ -46,22 +46,45 @@ require 'pg' unless defined?( PG )
|
|
46
46
|
# This prints the rows with type casted columns:
|
47
47
|
# ["a", 123, [5, 4, 3]]
|
48
48
|
#
|
49
|
+
# Very similar with binary format:
|
50
|
+
#
|
51
|
+
# conn.exec( "CREATE TABLE copytable AS VALUES('a', 123, '2023-03-19 18:39:44'::TIMESTAMP)" )
|
52
|
+
#
|
53
|
+
# # Retrieve table OIDs per empty result set in binary format.
|
54
|
+
# res = conn.exec_params( "SELECT * FROM copytable LIMIT 0", [], 1 )
|
55
|
+
# # Build a type map for common database to ruby type decoders.
|
56
|
+
# btm = PG::BasicTypeMapForResults.new(conn)
|
57
|
+
# # Build a PG::TypeMapByColumn with decoders suitable for copytable.
|
58
|
+
# tm = btm.build_column_map( res )
|
59
|
+
# row_decoder = PG::BinaryDecoder::CopyRow.new type_map: tm
|
60
|
+
#
|
61
|
+
# conn.copy_data( "COPY copytable TO STDOUT WITH (FORMAT binary)", row_decoder ) do |res|
|
62
|
+
# while row=conn.get_copy_data
|
63
|
+
# p row
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
# This prints the rows with type casted columns:
|
67
|
+
# ["a", 123, 2023-03-19 18:39:44 UTC]
|
68
|
+
#
|
49
69
|
# See also PG::BasicTypeMapBasedOnResult for the encoder direction and PG::BasicTypeRegistry for the definition of additional types.
|
50
70
|
class PG::BasicTypeMapForResults < PG::TypeMapByOid
|
51
71
|
include PG::BasicTypeRegistry::Checker
|
52
72
|
|
53
73
|
class WarningTypeMap < PG::TypeMapInRuby
|
54
74
|
def initialize(typenames)
|
55
|
-
@already_warned =
|
75
|
+
@already_warned = {}
|
56
76
|
@typenames_by_oid = typenames
|
57
77
|
end
|
58
78
|
|
59
79
|
def typecast_result_value(result, _tuple, field)
|
60
80
|
format = result.fformat(field)
|
61
81
|
oid = result.ftype(field)
|
62
|
-
unless @already_warned
|
82
|
+
unless @already_warned.dig(format, oid)
|
63
83
|
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."
|
64
|
-
|
84
|
+
unless frozen?
|
85
|
+
@already_warned[format] ||= {}
|
86
|
+
@already_warned[format][oid] = true
|
87
|
+
end
|
65
88
|
end
|
66
89
|
super
|
67
90
|
end
|
@@ -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
|
@@ -192,8 +200,8 @@ class PG::BasicTypeRegistry
|
|
192
200
|
# +name+ must correspond to the +typname+ column in the +pg_type+ table.
|
193
201
|
# +format+ can be 0 for text format and 1 for binary.
|
194
202
|
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
|
203
|
+
register_coder(encoder_class.new(name: name, format: format).freeze) if encoder_class
|
204
|
+
register_coder(decoder_class.new(name: name, format: format).freeze) if decoder_class
|
197
205
|
self
|
198
206
|
end
|
199
207
|
|
@@ -232,9 +240,7 @@ class PG::BasicTypeRegistry
|
|
232
240
|
# alias_type 'uuid', 'text'
|
233
241
|
#
|
234
242
|
# 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
|
243
|
+
register_type 0, 'bytea', PG::TextEncoder::Bytea, PG::TextDecoder::Bytea
|
238
244
|
register_type 0, 'bool', PG::TextEncoder::Boolean, PG::TextDecoder::Boolean
|
239
245
|
# register_type 'bit', OID::Bit.new
|
240
246
|
# register_type 'varbit', OID::Bit.new
|
@@ -242,6 +248,7 @@ class PG::BasicTypeRegistry
|
|
242
248
|
register_type 0, 'float4', PG::TextEncoder::Float, PG::TextDecoder::Float
|
243
249
|
alias_type 0, 'float8', 'float4'
|
244
250
|
|
251
|
+
# For compatibility reason the timestamp in text format is encoded as local time (TimestampWithoutTimeZone) instead of UTC
|
245
252
|
register_type 0, 'timestamp', PG::TextEncoder::TimestampWithoutTimeZone, PG::TextDecoder::TimestampWithoutTimeZone
|
246
253
|
register_type 0, 'timestamptz', PG::TextEncoder::TimestampWithTimeZone, PG::TextDecoder::TimestampWithTimeZone
|
247
254
|
register_type 0, 'date', PG::TextEncoder::Date, PG::TextDecoder::Date
|
@@ -276,26 +283,17 @@ class PG::BasicTypeRegistry
|
|
276
283
|
|
277
284
|
register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea
|
278
285
|
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',
|
286
|
+
register_type 1, 'float4', PG::BinaryEncoder::Float4, PG::BinaryDecoder::Float
|
287
|
+
register_type 1, 'float8', PG::BinaryEncoder::Float8, PG::BinaryDecoder::Float
|
288
|
+
register_type 1, 'timestamp', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtc
|
289
|
+
register_type 1, 'timestamptz', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtcToLocal
|
290
|
+
register_type 1, 'date', PG::BinaryEncoder::Date, PG::BinaryDecoder::Date
|
283
291
|
|
284
292
|
self
|
285
293
|
end
|
286
294
|
|
287
295
|
alias define_default_types register_default_types
|
288
296
|
|
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
|
297
|
+
DEFAULT_TYPE_REGISTRY = PG.make_shareable(PG::BasicTypeRegistry.new.register_default_types)
|
298
|
+
private_constant :DEFAULT_TYPE_REGISTRY
|
301
299
|
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
|