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
data/ext/pg_coder.c CHANGED
@@ -26,16 +26,16 @@ 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
41
  this->flags = 0;
@@ -45,52 +45,97 @@ pg_coder_init_encoder( VALUE self )
45
45
  void
46
46
  pg_coder_init_decoder( VALUE self )
47
47
  {
48
- t_pg_coder *this = DATA_PTR( self );
48
+ t_pg_coder *this = RTYPEDDATA_DATA( self );
49
49
  VALUE klass = rb_class_of(self);
50
50
  this->enc_func = NULL;
51
51
  if( rb_const_defined( klass, s_id_CFUNC ) ){
52
52
  VALUE cfunc = rb_const_get( klass, s_id_CFUNC );
53
- this->dec_func = DATA_PTR(cfunc);
53
+ this->dec_func = RTYPEDDATA_DATA(cfunc);
54
54
  } else {
55
55
  this->dec_func = NULL;
56
56
  }
57
- this->coder_obj = self;
57
+ RB_OBJ_WRITE(self, &this->coder_obj, self);
58
58
  this->oid = 0;
59
59
  this->format = 0;
60
60
  this->flags = 0;
61
61
  rb_iv_set( self, "@name", Qnil );
62
62
  }
63
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
+
64
78
  void
65
- pg_coder_mark(t_pg_coder *this)
79
+ pg_coder_compact(void *_this)
66
80
  {
67
- rb_gc_mark(this->coder_obj);
81
+ t_pg_coder *this = (t_pg_coder *)_this;
82
+ pg_gc_location(this->coder_obj);
68
83
  }
69
84
 
70
85
  static void
71
- pg_composite_coder_mark(t_pg_composite_coder *this)
86
+ pg_composite_coder_compact(void *_this)
72
87
  {
73
- pg_coder_mark(&this->comp);
88
+ t_pg_composite_coder *this = (t_pg_composite_coder *)_this;
89
+ pg_coder_compact(&this->comp);
74
90
  }
75
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_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
+
76
107
  static VALUE
77
108
  pg_simple_encoder_allocate( VALUE klass )
78
109
  {
79
110
  t_pg_coder *this;
80
- VALUE self = Data_Make_Struct( klass, t_pg_coder, pg_coder_mark, -1, this );
111
+ VALUE self = TypedData_Make_Struct( klass, t_pg_coder, &pg_coder_type, this );
81
112
  pg_coder_init_encoder( self );
82
113
  return self;
83
114
  }
84
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_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
+
85
129
  static VALUE
86
130
  pg_composite_encoder_allocate( VALUE klass )
87
131
  {
88
132
  t_pg_composite_coder *this;
89
- VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, pg_composite_coder_mark, -1, this );
133
+ VALUE self = TypedData_Make_Struct( klass, t_pg_composite_coder, &pg_composite_coder_type, this );
90
134
  pg_coder_init_encoder( self );
91
135
  this->elem = NULL;
92
136
  this->needs_quotation = 1;
93
137
  this->delimiter = ',';
138
+ this->dimensions = -1;
94
139
  rb_iv_set( self, "@elements_type", Qnil );
95
140
  return self;
96
141
  }
@@ -99,7 +144,7 @@ static VALUE
99
144
  pg_simple_decoder_allocate( VALUE klass )
100
145
  {
101
146
  t_pg_coder *this;
102
- VALUE self = Data_Make_Struct( klass, t_pg_coder, pg_coder_mark, -1, this );
147
+ VALUE self = TypedData_Make_Struct( klass, t_pg_coder, &pg_coder_type, this );
103
148
  pg_coder_init_decoder( self );
104
149
  return self;
105
150
  }
@@ -108,11 +153,12 @@ static VALUE
108
153
  pg_composite_decoder_allocate( VALUE klass )
109
154
  {
110
155
  t_pg_composite_coder *this;
111
- VALUE self = Data_Make_Struct( klass, t_pg_composite_coder, pg_composite_coder_mark, -1, this );
156
+ VALUE self = TypedData_Make_Struct( klass, t_pg_composite_coder, &pg_composite_coder_type, this );
112
157
  pg_coder_init_decoder( self );
113
158
  this->elem = NULL;
114
159
  this->needs_quotation = 1;
115
160
  this->delimiter = ',';
161
+ this->dimensions = -1;
116
162
  rb_iv_set( self, "@elements_type", Qnil );
117
163
  return self;
118
164
  }
@@ -131,11 +177,11 @@ static VALUE
131
177
  pg_coder_encode(int argc, VALUE *argv, VALUE self)
132
178
  {
133
179
  VALUE res;
134
- VALUE intermediate;
180
+ VALUE intermediate = Qnil;
135
181
  VALUE value;
136
182
  int len, len2;
137
183
  int enc_idx;
138
- t_pg_coder *this = DATA_PTR(self);
184
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
139
185
 
140
186
  if(argc < 1 || argc > 2){
141
187
  rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc);
@@ -169,8 +215,6 @@ pg_coder_encode(int argc, VALUE *argv, VALUE self)
169
215
  }
170
216
  rb_str_set_len( res, len2 );
171
217
 
172
- RB_GC_GUARD(intermediate);
173
-
174
218
  return res;
175
219
  }
176
220
 
@@ -192,7 +236,7 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
192
236
  int tuple = -1;
193
237
  int field = -1;
194
238
  VALUE res;
195
- t_pg_coder *this = DATA_PTR(self);
239
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
196
240
 
197
241
  if(argc < 1 || argc > 3){
198
242
  rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..3)", argc);
@@ -213,7 +257,7 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
213
257
  rb_raise(rb_eRuntimeError, "no decoder function defined");
214
258
  }
215
259
 
216
- res = this->dec_func(this, val, RSTRING_LEN(argv[0]), tuple, field, ENCODING_GET(argv[0]));
260
+ res = this->dec_func(this, val, RSTRING_LENINT(argv[0]), tuple, field, ENCODING_GET(argv[0]));
217
261
 
218
262
  return res;
219
263
  }
@@ -230,7 +274,8 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
230
274
  static VALUE
231
275
  pg_coder_oid_set(VALUE self, VALUE oid)
232
276
  {
233
- t_pg_coder *this = DATA_PTR(self);
277
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
278
+ rb_check_frozen(self);
234
279
  this->oid = NUM2UINT(oid);
235
280
  return oid;
236
281
  }
@@ -245,7 +290,7 @@ pg_coder_oid_set(VALUE self, VALUE oid)
245
290
  static VALUE
246
291
  pg_coder_oid_get(VALUE self)
247
292
  {
248
- t_pg_coder *this = DATA_PTR(self);
293
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
249
294
  return UINT2NUM(this->oid);
250
295
  }
251
296
 
@@ -261,7 +306,8 @@ pg_coder_oid_get(VALUE self)
261
306
  static VALUE
262
307
  pg_coder_format_set(VALUE self, VALUE format)
263
308
  {
264
- t_pg_coder *this = DATA_PTR(self);
309
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
310
+ rb_check_frozen(self);
265
311
  this->format = NUM2INT(format);
266
312
  return format;
267
313
  }
@@ -276,7 +322,7 @@ pg_coder_format_set(VALUE self, VALUE format)
276
322
  static VALUE
277
323
  pg_coder_format_get(VALUE self)
278
324
  {
279
- t_pg_coder *this = DATA_PTR(self);
325
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
280
326
  return INT2NUM(this->format);
281
327
  }
282
328
 
@@ -292,7 +338,8 @@ pg_coder_format_get(VALUE self)
292
338
  static VALUE
293
339
  pg_coder_flags_set(VALUE self, VALUE flags)
294
340
  {
295
- t_pg_coder *this = DATA_PTR(self);
341
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
342
+ rb_check_frozen(self);
296
343
  this->flags = NUM2INT(flags);
297
344
  return flags;
298
345
  }
@@ -306,7 +353,7 @@ pg_coder_flags_set(VALUE self, VALUE flags)
306
353
  static VALUE
307
354
  pg_coder_flags_get(VALUE self)
308
355
  {
309
- t_pg_coder *this = DATA_PTR(self);
356
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
310
357
  return INT2NUM(this->flags);
311
358
  }
312
359
 
@@ -317,13 +364,15 @@ pg_coder_flags_get(VALUE self)
317
364
  * Specifies whether the assigned #elements_type requires quotation marks to
318
365
  * be transferred safely. Encoding with #needs_quotation=false is somewhat
319
366
  * faster.
367
+ * It is only used by text coders and ignored by binary coders.
320
368
  *
321
369
  * The default is +true+. This option is ignored for decoding of values.
322
370
  */
323
371
  static VALUE
324
372
  pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
325
373
  {
326
- t_pg_composite_coder *this = DATA_PTR(self);
374
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
375
+ rb_check_frozen(self);
327
376
  this->needs_quotation = RTEST(needs_quotation);
328
377
  return needs_quotation;
329
378
  }
@@ -338,7 +387,7 @@ pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
338
387
  static VALUE
339
388
  pg_coder_needs_quotation_get(VALUE self)
340
389
  {
341
- t_pg_composite_coder *this = DATA_PTR(self);
390
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
342
391
  return this->needs_quotation ? Qtrue : Qfalse;
343
392
  }
344
393
 
@@ -349,11 +398,13 @@ pg_coder_needs_quotation_get(VALUE self)
349
398
  * Specifies the character that separates values within the composite type.
350
399
  * The default is a comma.
351
400
  * This must be a single one-byte character.
401
+ * It is only used by text coders and ignored by binary coders.
352
402
  */
353
403
  static VALUE
354
404
  pg_coder_delimiter_set(VALUE self, VALUE delimiter)
355
405
  {
356
- t_pg_composite_coder *this = DATA_PTR(self);
406
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
407
+ rb_check_frozen(self);
357
408
  StringValue(delimiter);
358
409
  if(RSTRING_LEN(delimiter) != 1)
359
410
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -370,10 +421,53 @@ pg_coder_delimiter_set(VALUE self, VALUE delimiter)
370
421
  static VALUE
371
422
  pg_coder_delimiter_get(VALUE self)
372
423
  {
373
- t_pg_composite_coder *this = DATA_PTR(self);
424
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
374
425
  return rb_str_new(&this->delimiter, 1);
375
426
  }
376
427
 
428
+ /*
429
+ * call-seq:
430
+ * coder.dimensions = Integer
431
+ * coder.dimensions = nil
432
+ *
433
+ * Set number of array dimensions to be encoded.
434
+ *
435
+ * This property ensures, that this number of dimensions is always encoded.
436
+ * If less dimensions than this number are in the given value, an ArgumentError is raised.
437
+ * If more dimensions than this number are in the value, the Array value is passed to the next encoder.
438
+ *
439
+ * Setting dimensions is especially useful, when a Record shall be encoded into an Array, since the Array encoder can not distinguish if the array shall be encoded as a higher dimension or as a record otherwise.
440
+ *
441
+ * The default is +nil+.
442
+ *
443
+ * See #dimensions
444
+ */
445
+ static VALUE
446
+ pg_coder_dimensions_set(VALUE self, VALUE dimensions)
447
+ {
448
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
449
+ rb_check_frozen(self);
450
+ if(!NIL_P(dimensions) && NUM2INT(dimensions) < 0)
451
+ rb_raise( rb_eArgError, "dimensions must be nil or >= 0");
452
+ this->dimensions = NIL_P(dimensions) ? -1 : NUM2INT(dimensions);
453
+ return dimensions;
454
+ }
455
+
456
+ /*
457
+ * call-seq:
458
+ * coder.dimensions -> Integer | nil
459
+ *
460
+ * Get number of enforced array dimensions or +nil+ if not set.
461
+ *
462
+ * See #dimensions=
463
+ */
464
+ static VALUE
465
+ pg_coder_dimensions_get(VALUE self)
466
+ {
467
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
468
+ return this->dimensions < 0 ? Qnil : INT2NUM(this->dimensions);
469
+ }
470
+
377
471
  /*
378
472
  * call-seq:
379
473
  * coder.elements_type = coder
@@ -386,12 +480,13 @@ pg_coder_delimiter_get(VALUE self)
386
480
  static VALUE
387
481
  pg_coder_elements_type_set(VALUE self, VALUE elem_type)
388
482
  {
389
- t_pg_composite_coder *this = DATA_PTR( self );
483
+ t_pg_composite_coder *this = RTYPEDDATA_DATA( self );
390
484
 
485
+ rb_check_frozen(self);
391
486
  if ( NIL_P(elem_type) ){
392
487
  this->elem = NULL;
393
488
  } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
394
- this->elem = DATA_PTR( elem_type );
489
+ this->elem = RTYPEDDATA_DATA( elem_type );
395
490
  } else {
396
491
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::Coder)",
397
492
  rb_obj_classname( elem_type ) );
@@ -401,10 +496,22 @@ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
401
496
  return elem_type;
402
497
  }
403
498
 
404
- void
499
+ static const rb_data_type_t pg_coder_cfunc_type = {
500
+ "PG::Coder::CFUNC",
501
+ {
502
+ (RUBY_DATA_FUNC)NULL,
503
+ (RUBY_DATA_FUNC)NULL,
504
+ (size_t (*)(const void *))NULL,
505
+ },
506
+ 0,
507
+ 0,
508
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
509
+ };
510
+
511
+ VALUE
405
512
  pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
406
513
  {
407
- VALUE cfunc_obj = Data_Wrap_Struct( rb_cObject, NULL, NULL, func );
514
+ VALUE cfunc_obj = TypedData_Wrap_Struct( rb_cObject, &pg_coder_cfunc_type, func );
408
515
  VALUE coder_klass = rb_define_class_under( nsp, name, base_klass );
409
516
  if( nsp==rb_mPG_BinaryEncoder || nsp==rb_mPG_BinaryDecoder )
410
517
  rb_include_module( coder_klass, rb_mPG_BinaryFormatting );
@@ -414,9 +521,10 @@ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
414
521
  if( nsp==rb_mPG_BinaryDecoder || nsp==rb_mPG_TextDecoder )
415
522
  rb_define_method( coder_klass, "decode", pg_coder_decode, -1 );
416
523
 
417
- rb_define_const( coder_klass, "CFUNC", cfunc_obj );
524
+ rb_define_const( coder_klass, "CFUNC", rb_obj_freeze(cfunc_obj) );
418
525
 
419
526
  RB_GC_GUARD(cfunc_obj);
527
+ return coder_klass;
420
528
  }
421
529
 
422
530
 
@@ -483,7 +591,7 @@ pg_coder_dec_func(t_pg_coder *this, int binary)
483
591
 
484
592
 
485
593
  void
486
- init_pg_coder()
594
+ init_pg_coder(void)
487
595
  {
488
596
  s_id_encode = rb_intern("encode");
489
597
  s_id_decode = rb_intern("decode");
@@ -541,6 +649,8 @@ init_pg_coder()
541
649
  *
542
650
  * This is the base class for all type cast classes of PostgreSQL types,
543
651
  * that are made up of some sub type.
652
+ *
653
+ * See PG::TextEncoder::Array, PG::TextDecoder::Array, PG::BinaryEncoder::Array, PG::BinaryDecoder::Array, etc.
544
654
  */
545
655
  rb_cPG_CompositeCoder = rb_define_class_under( rb_mPG, "CompositeCoder", rb_cPG_Coder );
546
656
  rb_define_method( rb_cPG_CompositeCoder, "elements_type=", pg_coder_elements_type_set, 1 );
@@ -549,6 +659,8 @@ init_pg_coder()
549
659
  rb_define_method( rb_cPG_CompositeCoder, "needs_quotation?", pg_coder_needs_quotation_get, 0 );
550
660
  rb_define_method( rb_cPG_CompositeCoder, "delimiter=", pg_coder_delimiter_set, 1 );
551
661
  rb_define_method( rb_cPG_CompositeCoder, "delimiter", pg_coder_delimiter_get, 0 );
662
+ rb_define_method( rb_cPG_CompositeCoder, "dimensions=", pg_coder_dimensions_set, 1 );
663
+ rb_define_method( rb_cPG_CompositeCoder, "dimensions", pg_coder_dimensions_get, 0 );
552
664
 
553
665
  /* Document-class: PG::CompositeEncoder < PG::CompositeCoder */
554
666
  rb_cPG_CompositeEncoder = rb_define_class_under( rb_mPG, "CompositeEncoder", rb_cPG_CompositeCoder );