pg 0.18.2 → 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.
Files changed (139) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +22 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/BSDL +2 -2
  15. data/Gemfile +14 -0
  16. data/History.md +876 -0
  17. data/Manifest.txt +8 -21
  18. data/README-Windows.rdoc +17 -28
  19. data/README.ja.md +276 -0
  20. data/README.md +286 -0
  21. data/Rakefile +40 -131
  22. data/Rakefile.cross +88 -70
  23. data/certs/ged.pem +24 -0
  24. data/certs/larskanis-2022.pem +26 -0
  25. data/certs/larskanis-2023.pem +24 -0
  26. data/ext/errorcodes.def +113 -0
  27. data/ext/errorcodes.rb +1 -1
  28. data/ext/errorcodes.txt +36 -2
  29. data/ext/extconf.rb +120 -54
  30. data/ext/gvl_wrappers.c +8 -0
  31. data/ext/gvl_wrappers.h +44 -33
  32. data/ext/pg.c +226 -200
  33. data/ext/pg.h +99 -99
  34. data/ext/pg_binary_decoder.c +164 -16
  35. data/ext/pg_binary_encoder.c +249 -22
  36. data/ext/pg_coder.c +189 -44
  37. data/ext/pg_connection.c +1866 -1173
  38. data/ext/pg_copy_coder.c +398 -42
  39. data/ext/pg_errors.c +1 -1
  40. data/ext/pg_record_coder.c +522 -0
  41. data/ext/pg_result.c +727 -232
  42. data/ext/pg_text_decoder.c +629 -43
  43. data/ext/pg_text_encoder.c +269 -102
  44. data/ext/pg_tuple.c +572 -0
  45. data/ext/pg_type_map.c +64 -23
  46. data/ext/pg_type_map_all_strings.c +21 -7
  47. data/ext/pg_type_map_by_class.c +59 -27
  48. data/ext/pg_type_map_by_column.c +86 -43
  49. data/ext/pg_type_map_by_mri_type.c +49 -20
  50. data/ext/pg_type_map_by_oid.c +62 -29
  51. data/ext/pg_type_map_in_ruby.c +56 -22
  52. data/ext/{util.c → pg_util.c} +12 -12
  53. data/ext/{util.h → pg_util.h} +2 -2
  54. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  55. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  56. data/lib/pg/basic_type_map_for_results.rb +104 -0
  57. data/lib/pg/basic_type_registry.rb +299 -0
  58. data/lib/pg/binary_decoder/date.rb +9 -0
  59. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  60. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  61. data/lib/pg/coder.rb +36 -13
  62. data/lib/pg/connection.rb +797 -77
  63. data/lib/pg/exceptions.rb +16 -2
  64. data/lib/pg/result.rb +24 -7
  65. data/lib/pg/text_decoder/date.rb +18 -0
  66. data/lib/pg/text_decoder/inet.rb +9 -0
  67. data/lib/pg/text_decoder/json.rb +14 -0
  68. data/lib/pg/text_decoder/numeric.rb +9 -0
  69. data/lib/pg/text_decoder/timestamp.rb +30 -0
  70. data/lib/pg/text_encoder/date.rb +12 -0
  71. data/lib/pg/text_encoder/inet.rb +28 -0
  72. data/lib/pg/text_encoder/json.rb +14 -0
  73. data/lib/pg/text_encoder/numeric.rb +9 -0
  74. data/lib/pg/text_encoder/timestamp.rb +24 -0
  75. data/lib/pg/tuple.rb +30 -0
  76. data/lib/pg/type_map_by_column.rb +3 -2
  77. data/lib/pg/version.rb +4 -0
  78. data/lib/pg.rb +106 -41
  79. data/misc/openssl-pg-segfault.rb +31 -0
  80. data/misc/postgres/History.txt +9 -0
  81. data/misc/postgres/Manifest.txt +5 -0
  82. data/misc/postgres/README.txt +21 -0
  83. data/misc/postgres/Rakefile +21 -0
  84. data/misc/postgres/lib/postgres.rb +16 -0
  85. data/misc/ruby-pg/History.txt +9 -0
  86. data/misc/ruby-pg/Manifest.txt +5 -0
  87. data/misc/ruby-pg/README.txt +21 -0
  88. data/misc/ruby-pg/Rakefile +21 -0
  89. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  90. data/pg.gemspec +34 -0
  91. data/rakelib/task_extension.rb +46 -0
  92. data/sample/array_insert.rb +1 -1
  93. data/sample/async_api.rb +4 -8
  94. data/sample/async_copyto.rb +1 -1
  95. data/sample/async_mixed.rb +1 -1
  96. data/sample/check_conn.rb +1 -1
  97. data/sample/copydata.rb +71 -0
  98. data/sample/copyfrom.rb +1 -1
  99. data/sample/copyto.rb +1 -1
  100. data/sample/cursor.rb +1 -1
  101. data/sample/disk_usage_report.rb +6 -15
  102. data/sample/issue-119.rb +2 -2
  103. data/sample/losample.rb +1 -1
  104. data/sample/minimal-testcase.rb +2 -2
  105. data/sample/notify_wait.rb +1 -1
  106. data/sample/pg_statistics.rb +6 -15
  107. data/sample/replication_monitor.rb +9 -18
  108. data/sample/test_binary_values.rb +1 -1
  109. data/sample/wal_shipper.rb +2 -2
  110. data/sample/warehouse_partitions.rb +8 -17
  111. data/translation/.po4a-version +7 -0
  112. data/translation/po/all.pot +910 -0
  113. data/translation/po/ja.po +1047 -0
  114. data/translation/po4a.cfg +12 -0
  115. data.tar.gz.sig +0 -0
  116. metadata +137 -204
  117. metadata.gz.sig +0 -0
  118. data/ChangeLog +0 -5545
  119. data/History.rdoc +0 -313
  120. data/README.ja.rdoc +0 -14
  121. data/README.rdoc +0 -161
  122. data/lib/pg/basic_type_mapping.rb +0 -399
  123. data/lib/pg/constants.rb +0 -11
  124. data/lib/pg/text_decoder.rb +0 -42
  125. data/lib/pg/text_encoder.rb +0 -27
  126. data/spec/data/expected_trace.out +0 -26
  127. data/spec/data/random_binary_data +0 -0
  128. data/spec/helpers.rb +0 -355
  129. data/spec/pg/basic_type_mapping_spec.rb +0 -251
  130. data/spec/pg/connection_spec.rb +0 -1535
  131. data/spec/pg/result_spec.rb +0 -449
  132. data/spec/pg/type_map_by_class_spec.rb +0 -138
  133. data/spec/pg/type_map_by_column_spec.rb +0 -222
  134. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  135. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  136. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  137. data/spec/pg/type_map_spec.rb +0 -22
  138. data/spec/pg/type_spec.rb +0 -688
  139. data/spec/pg_spec.rb +0 -50
data/ext/pg_coder.c CHANGED
@@ -26,53 +26,111 @@ pg_coder_allocate( VALUE klass )
26
26
  void
27
27
  pg_coder_init_encoder( VALUE self )
28
28
  {
29
- t_pg_coder *this = DATA_PTR( self );
29
+ t_pg_coder *this = RTYPEDDATA_DATA( self );
30
30
  VALUE klass = rb_class_of(self);
31
31
  if( rb_const_defined( klass, s_id_CFUNC ) ){
32
32
  VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
33
- this->enc_func = DATA_PTR(cfunc);
33
+ this->enc_func = RTYPEDDATA_DATA(cfunc);
34
34
  } else {
35
35
  this->enc_func = NULL;
36
36
  }
37
37
  this->dec_func = NULL;
38
- this->coder_obj = self;
38
+ RB_OBJ_WRITE(self, &this->coder_obj, self);
39
39
  this->oid = 0;
40
40
  this->format = 0;
41
+ this->flags = 0;
41
42
  rb_iv_set( self, "@name", Qnil );
42
43
  }
43
44
 
44
45
  void
45
46
  pg_coder_init_decoder( VALUE self )
46
47
  {
47
- t_pg_coder *this = DATA_PTR( self );
48
+ t_pg_coder *this = RTYPEDDATA_DATA( self );
48
49
  VALUE klass = rb_class_of(self);
49
50
  this->enc_func = NULL;
50
51
  if( rb_const_defined( klass, s_id_CFUNC ) ){
51
52
  VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
52
- this->dec_func = DATA_PTR(cfunc);
53
+ this->dec_func = RTYPEDDATA_DATA(cfunc);
53
54
  } else {
54
55
  this->dec_func = NULL;
55
56
  }
56
- this->coder_obj = self;
57
+ RB_OBJ_WRITE(self, &this->coder_obj, self);
57
58
  this->oid = 0;
58
59
  this->format = 0;
60
+ this->flags = 0;
59
61
  rb_iv_set( self, "@name", Qnil );
60
62
  }
61
63
 
64
+ static size_t
65
+ pg_coder_memsize(const void *_this)
66
+ {
67
+ const t_pg_coder *this = (const t_pg_coder *)_this;
68
+ return sizeof(*this);
69
+ }
70
+
71
+ static size_t
72
+ pg_composite_coder_memsize(const void *_this)
73
+ {
74
+ const t_pg_composite_coder *this = (const t_pg_composite_coder *)_this;
75
+ return sizeof(*this);
76
+ }
77
+
78
+ void
79
+ pg_coder_compact(void *_this)
80
+ {
81
+ t_pg_coder *this = (t_pg_coder *)_this;
82
+ pg_gc_location(this->coder_obj);
83
+ }
84
+
85
+ static void
86
+ pg_composite_coder_compact(void *_this)
87
+ {
88
+ t_pg_composite_coder *this = (t_pg_composite_coder *)_this;
89
+ pg_coder_compact(&this->comp);
90
+ }
91
+
92
+ const rb_data_type_t pg_coder_type = {
93
+ "PG::Coder",
94
+ {
95
+ (RUBY_DATA_FUNC) NULL,
96
+ RUBY_TYPED_DEFAULT_FREE,
97
+ pg_coder_memsize,
98
+ pg_compact_callback(pg_coder_compact),
99
+ },
100
+ 0,
101
+ 0,
102
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
103
+ // macro to update VALUE references, as to trigger write barriers.
104
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
105
+ };
106
+
62
107
  static VALUE
63
108
  pg_simple_encoder_allocate( VALUE klass )
64
109
  {
65
110
  t_pg_coder *this;
66
- VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
111
+ VALUE self = TypedData_Make_Struct( klass, t_pg_coder, &pg_coder_type, this );
67
112
  pg_coder_init_encoder( self );
68
113
  return self;
69
114
  }
70
115
 
116
+ static const rb_data_type_t pg_composite_coder_type = {
117
+ "PG::CompositeCoder",
118
+ {
119
+ (RUBY_DATA_FUNC) NULL,
120
+ RUBY_TYPED_DEFAULT_FREE,
121
+ pg_composite_coder_memsize,
122
+ pg_compact_callback(pg_composite_coder_compact),
123
+ },
124
+ &pg_coder_type,
125
+ 0,
126
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
127
+ };
128
+
71
129
  static VALUE
72
130
  pg_composite_encoder_allocate( VALUE klass )
73
131
  {
74
132
  t_pg_composite_coder *this;
75
- VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
133
+ VALUE self = TypedData_Make_Struct( klass, t_pg_composite_coder, &pg_composite_coder_type, this );
76
134
  pg_coder_init_encoder( self );
77
135
  this->elem = NULL;
78
136
  this->needs_quotation = 1;
@@ -85,7 +143,7 @@ static VALUE
85
143
  pg_simple_decoder_allocate( VALUE klass )
86
144
  {
87
145
  t_pg_coder *this;
88
- VALUE self = Data_Make_Struct( klass, t_pg_coder, NULL, -1, this );
146
+ VALUE self = TypedData_Make_Struct( klass, t_pg_coder, &pg_coder_type, this );
89
147
  pg_coder_init_decoder( self );
90
148
  return self;
91
149
  }
@@ -94,7 +152,7 @@ static VALUE
94
152
  pg_composite_decoder_allocate( VALUE klass )
95
153
  {
96
154
  t_pg_composite_coder *this;
97
- VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, NULL, -1, this );
155
+ VALUE self = TypedData_Make_Struct( klass, t_pg_composite_coder, &pg_composite_coder_type, this );
98
156
  pg_coder_init_decoder( self );
99
157
  this->elem = NULL;
100
158
  this->needs_quotation = 1;
@@ -105,7 +163,7 @@ pg_composite_decoder_allocate( VALUE klass )
105
163
 
106
164
  /*
107
165
  * call-seq:
108
- * coder.encode( value )
166
+ * coder.encode( value [, encoding] )
109
167
  *
110
168
  * Encodes the given Ruby object into string representation, without
111
169
  * sending data to/from the database server.
@@ -114,12 +172,23 @@ pg_composite_decoder_allocate( VALUE klass )
114
172
  *
115
173
  */
116
174
  static VALUE
117
- pg_coder_encode(VALUE self, VALUE value)
175
+ pg_coder_encode(int argc, VALUE *argv, VALUE self)
118
176
  {
119
177
  VALUE res;
120
178
  VALUE intermediate;
179
+ VALUE value;
121
180
  int len, len2;
122
- t_pg_coder *this = DATA_PTR(self);
181
+ int enc_idx;
182
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
183
+
184
+ if(argc < 1 || argc > 2){
185
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc);
186
+ }else if(argc == 1){
187
+ enc_idx = rb_ascii8bit_encindex();
188
+ }else{
189
+ enc_idx = rb_to_encoding_index(argv[1]);
190
+ }
191
+ value = argv[0];
123
192
 
124
193
  if( NIL_P(value) )
125
194
  return Qnil;
@@ -128,22 +197,21 @@ pg_coder_encode(VALUE self, VALUE value)
128
197
  rb_raise(rb_eRuntimeError, "no encoder function defined");
129
198
  }
130
199
 
131
- len = this->enc_func( this, value, NULL, &intermediate );
200
+ len = this->enc_func( this, value, NULL, &intermediate, enc_idx );
132
201
 
133
202
  if( len == -1 ){
134
203
  /* The intermediate value is a String that can be used directly. */
135
- OBJ_INFECT(intermediate, value);
136
204
  return intermediate;
137
205
  }
138
206
 
139
207
  res = rb_str_new(NULL, len);
140
- len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate);
208
+ PG_ENCODING_SET_NOCHECK(res, enc_idx);
209
+ len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate, enc_idx );
141
210
  if( len < len2 ){
142
211
  rb_bug("%s: result length of first encoder run (%i) is less than second run (%i)",
143
212
  rb_obj_classname( self ), len, len2 );
144
213
  }
145
214
  rb_str_set_len( res, len2 );
146
- OBJ_INFECT(res, value);
147
215
 
148
216
  RB_GC_GUARD(intermediate);
149
217
 
@@ -165,10 +233,10 @@ static VALUE
165
233
  pg_coder_decode(int argc, VALUE *argv, VALUE self)
166
234
  {
167
235
  char *val;
168
- VALUE tuple = -1;
169
- VALUE field = -1;
236
+ int tuple = -1;
237
+ int field = -1;
170
238
  VALUE res;
171
- t_pg_coder *this = DATA_PTR(self);
239
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
172
240
 
173
241
  if(argc < 1 || argc > 3){
174
242
  rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..3)", argc);
@@ -180,13 +248,16 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
180
248
  if( NIL_P(argv[0]) )
181
249
  return Qnil;
182
250
 
183
- val = StringValuePtr(argv[0]);
251
+ if( this->format == 0 ){
252
+ val = StringValueCStr(argv[0]);
253
+ }else{
254
+ val = StringValuePtr(argv[0]);
255
+ }
184
256
  if( !this->dec_func ){
185
257
  rb_raise(rb_eRuntimeError, "no decoder function defined");
186
258
  }
187
259
 
188
- res = this->dec_func(this, val, RSTRING_LEN(argv[0]), tuple, field, ENCODING_GET(argv[0]));
189
- OBJ_INFECT(res, argv[0]);
260
+ res = this->dec_func(this, val, RSTRING_LENINT(argv[0]), tuple, field, ENCODING_GET(argv[0]));
190
261
 
191
262
  return res;
192
263
  }
@@ -203,7 +274,8 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
203
274
  static VALUE
204
275
  pg_coder_oid_set(VALUE self, VALUE oid)
205
276
  {
206
- t_pg_coder *this = DATA_PTR(self);
277
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
278
+ rb_check_frozen(self);
207
279
  this->oid = NUM2UINT(oid);
208
280
  return oid;
209
281
  }
@@ -218,7 +290,7 @@ pg_coder_oid_set(VALUE self, VALUE oid)
218
290
  static VALUE
219
291
  pg_coder_oid_get(VALUE self)
220
292
  {
221
- t_pg_coder *this = DATA_PTR(self);
293
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
222
294
  return UINT2NUM(this->oid);
223
295
  }
224
296
 
@@ -234,7 +306,8 @@ pg_coder_oid_get(VALUE self)
234
306
  static VALUE
235
307
  pg_coder_format_set(VALUE self, VALUE format)
236
308
  {
237
- t_pg_coder *this = DATA_PTR(self);
309
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
310
+ rb_check_frozen(self);
238
311
  this->format = NUM2INT(format);
239
312
  return format;
240
313
  }
@@ -249,10 +322,41 @@ pg_coder_format_set(VALUE self, VALUE format)
249
322
  static VALUE
250
323
  pg_coder_format_get(VALUE self)
251
324
  {
252
- t_pg_coder *this = DATA_PTR(self);
325
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
253
326
  return INT2NUM(this->format);
254
327
  }
255
328
 
329
+ /*
330
+ * call-seq:
331
+ * coder.flags = Integer
332
+ *
333
+ * Set coder specific bitwise OR-ed flags.
334
+ * See the particular en- or decoder description for available flags.
335
+ *
336
+ * The default is +0+.
337
+ */
338
+ static VALUE
339
+ pg_coder_flags_set(VALUE self, VALUE flags)
340
+ {
341
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
342
+ rb_check_frozen(self);
343
+ this->flags = NUM2INT(flags);
344
+ return flags;
345
+ }
346
+
347
+ /*
348
+ * call-seq:
349
+ * coder.flags -> Integer
350
+ *
351
+ * Get current bitwise OR-ed coder flags.
352
+ */
353
+ static VALUE
354
+ pg_coder_flags_get(VALUE self)
355
+ {
356
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
357
+ return INT2NUM(this->flags);
358
+ }
359
+
256
360
  /*
257
361
  * call-seq:
258
362
  * coder.needs_quotation = Boolean
@@ -266,7 +370,8 @@ pg_coder_format_get(VALUE self)
266
370
  static VALUE
267
371
  pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
268
372
  {
269
- t_pg_composite_coder *this = DATA_PTR(self);
373
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
374
+ rb_check_frozen(self);
270
375
  this->needs_quotation = RTEST(needs_quotation);
271
376
  return needs_quotation;
272
377
  }
@@ -281,7 +386,7 @@ pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
281
386
  static VALUE
282
387
  pg_coder_needs_quotation_get(VALUE self)
283
388
  {
284
- t_pg_composite_coder *this = DATA_PTR(self);
389
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
285
390
  return this->needs_quotation ? Qtrue : Qfalse;
286
391
  }
287
392
 
@@ -296,7 +401,8 @@ pg_coder_needs_quotation_get(VALUE self)
296
401
  static VALUE
297
402
  pg_coder_delimiter_set(VALUE self, VALUE delimiter)
298
403
  {
299
- t_pg_composite_coder *this = DATA_PTR(self);
404
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
405
+ rb_check_frozen(self);
300
406
  StringValue(delimiter);
301
407
  if(RSTRING_LEN(delimiter) != 1)
302
408
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -313,7 +419,7 @@ pg_coder_delimiter_set(VALUE self, VALUE delimiter)
313
419
  static VALUE
314
420
  pg_coder_delimiter_get(VALUE self)
315
421
  {
316
- t_pg_composite_coder *this = DATA_PTR(self);
422
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
317
423
  return rb_str_new(&this->delimiter, 1);
318
424
  }
319
425
 
@@ -329,12 +435,13 @@ pg_coder_delimiter_get(VALUE self)
329
435
  static VALUE
330
436
  pg_coder_elements_type_set(VALUE self, VALUE elem_type)
331
437
  {
332
- t_pg_composite_coder *this = DATA_PTR( self );
438
+ t_pg_composite_coder *this = RTYPEDDATA_DATA( self );
333
439
 
440
+ rb_check_frozen(self);
334
441
  if ( NIL_P(elem_type) ){
335
442
  this->elem = NULL;
336
443
  } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
337
- this->elem = DATA_PTR( elem_type );
444
+ this->elem = RTYPEDDATA_DATA( elem_type );
338
445
  } else {
339
446
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::Coder)",
340
447
  rb_obj_classname( elem_type ) );
@@ -344,25 +451,52 @@ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
344
451
  return elem_type;
345
452
  }
346
453
 
347
- void
454
+ static const rb_data_type_t pg_coder_cfunc_type = {
455
+ "PG::Coder::CFUNC",
456
+ {
457
+ (RUBY_DATA_FUNC)NULL,
458
+ (RUBY_DATA_FUNC)NULL,
459
+ (size_t (*)(const void *))NULL,
460
+ },
461
+ 0,
462
+ 0,
463
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
464
+ };
465
+
466
+ VALUE
348
467
  pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
349
468
  {
350
- VALUE cfunc_obj = Data_Wrap_Struct( rb_cObject, NULL, NULL, func );
469
+ VALUE cfunc_obj = TypedData_Wrap_Struct( rb_cObject, &pg_coder_cfunc_type, func );
351
470
  VALUE coder_klass = rb_define_class_under( nsp, name, base_klass );
352
471
  if( nsp==rb_mPG_BinaryEncoder || nsp==rb_mPG_BinaryDecoder )
353
472
  rb_include_module( coder_klass, rb_mPG_BinaryFormatting );
354
473
 
355
- rb_define_const( coder_klass, "CFUNC", cfunc_obj );
474
+ if( nsp==rb_mPG_BinaryEncoder || nsp==rb_mPG_TextEncoder )
475
+ rb_define_method( coder_klass, "encode", pg_coder_encode, -1 );
476
+ if( nsp==rb_mPG_BinaryDecoder || nsp==rb_mPG_TextDecoder )
477
+ rb_define_method( coder_klass, "decode", pg_coder_decode, -1 );
478
+
479
+ rb_define_const( coder_klass, "CFUNC", rb_obj_freeze(cfunc_obj) );
356
480
 
357
481
  RB_GC_GUARD(cfunc_obj);
482
+ return coder_klass;
358
483
  }
359
484
 
360
485
 
361
486
  static int
362
- pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
487
+ pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
363
488
  {
364
- *intermediate = rb_funcall( conv->coder_obj, s_id_encode, 1, value );
365
- StringValue( *intermediate );
489
+ int arity = rb_obj_method_arity(conv->coder_obj, s_id_encode);
490
+ if( arity == 1 ){
491
+ VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 1, value );
492
+ StringValue( out_str );
493
+ *intermediate = rb_str_export_to_enc(out_str, rb_enc_from_index(enc_idx));
494
+ }else{
495
+ VALUE enc = rb_enc_from_encoding(rb_enc_from_index(enc_idx));
496
+ VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 2, value, enc );
497
+ StringValue( out_str );
498
+ *intermediate = out_str;
499
+ }
366
500
  return -1;
367
501
  }
368
502
 
@@ -382,14 +516,14 @@ pg_coder_enc_func(t_pg_coder *this)
382
516
  }
383
517
 
384
518
  static VALUE
385
- pg_text_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
519
+ pg_text_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
386
520
  {
387
521
  VALUE string = pg_text_dec_string(this, val, len, tuple, field, enc_idx);
388
522
  return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
389
523
  }
390
524
 
391
525
  static VALUE
392
- pg_bin_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
526
+ pg_bin_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
393
527
  {
394
528
  VALUE string = pg_bin_dec_bytea(this, val, len, tuple, field, enc_idx);
395
529
  return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
@@ -412,7 +546,7 @@ pg_coder_dec_func(t_pg_coder *this, int binary)
412
546
 
413
547
 
414
548
  void
415
- init_pg_coder()
549
+ init_pg_coder(void)
416
550
  {
417
551
  s_id_encode = rb_intern("encode");
418
552
  s_id_decode = rb_intern("decode");
@@ -436,14 +570,25 @@ init_pg_coder()
436
570
  rb_define_method( rb_cPG_Coder, "oid", pg_coder_oid_get, 0 );
437
571
  rb_define_method( rb_cPG_Coder, "format=", pg_coder_format_set, 1 );
438
572
  rb_define_method( rb_cPG_Coder, "format", pg_coder_format_get, 0 );
573
+ rb_define_method( rb_cPG_Coder, "flags=", pg_coder_flags_set, 1 );
574
+ rb_define_method( rb_cPG_Coder, "flags", pg_coder_flags_get, 0 );
575
+
576
+ /* define flags to be used with PG::Coder#flags= */
577
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_UTC", INT2NUM(PG_CODER_TIMESTAMP_DB_UTC));
578
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_DB_LOCAL));
579
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_UTC", INT2NUM(PG_CODER_TIMESTAMP_APP_UTC));
580
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_APP_LOCAL));
581
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_MASK", INT2NUM(PG_CODER_FORMAT_ERROR_MASK));
582
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_RAISE", INT2NUM(PG_CODER_FORMAT_ERROR_TO_RAISE));
583
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_STRING", INT2NUM(PG_CODER_FORMAT_ERROR_TO_STRING));
584
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_PARTIAL", INT2NUM(PG_CODER_FORMAT_ERROR_TO_PARTIAL));
585
+
439
586
  /*
440
587
  * Name of the coder or the corresponding data type.
441
588
  *
442
589
  * This accessor is only used in PG::Coder#inspect .
443
590
  */
444
591
  rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
445
- rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, 1 );
446
- rb_define_method( rb_cPG_Coder, "decode", pg_coder_decode, -1 );
447
592
 
448
593
  /* Document-class: PG::SimpleCoder < PG::Coder */
449
594
  rb_cPG_SimpleCoder = rb_define_class_under( rb_mPG, "SimpleCoder", rb_cPG_Coder );