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_tuple.c CHANGED
@@ -52,64 +52,90 @@ typedef struct {
52
52
  VALUE values[0];
53
53
  } t_pg_tuple;
54
54
 
55
- static inline VALUE
56
- pg_tuple_get_field_names( t_pg_tuple *this )
55
+ static inline VALUE *
56
+ pg_tuple_get_field_names_ptr( t_pg_tuple *this )
57
57
  {
58
58
  if( this->num_fields != (int)RHASH_SIZE(this->field_map) ){
59
- return this->values[this->num_fields];
59
+ return &this->values[this->num_fields];
60
60
  } else {
61
- return Qfalse;
61
+ static VALUE f = Qfalse;
62
+ return &f;
62
63
  }
63
64
  }
64
65
 
66
+ static inline VALUE
67
+ pg_tuple_get_field_names( t_pg_tuple *this )
68
+ {
69
+ return *pg_tuple_get_field_names_ptr(this);
70
+ }
71
+
65
72
  static void
66
- pg_tuple_gc_mark( t_pg_tuple *this )
73
+ pg_tuple_gc_mark( void *_this )
67
74
  {
75
+ t_pg_tuple *this = (t_pg_tuple *)_this;
68
76
  int i;
69
77
 
70
78
  if( !this ) return;
71
- rb_gc_mark( this->result );
72
- rb_gc_mark( this->typemap );
73
- rb_gc_mark( this->field_map );
79
+ rb_gc_mark_movable( this->result );
80
+ rb_gc_mark_movable( this->typemap );
81
+ rb_gc_mark_movable( this->field_map );
74
82
 
75
83
  for( i = 0; i < this->num_fields; i++ ){
76
- rb_gc_mark( this->values[i] );
84
+ rb_gc_mark_movable( this->values[i] );
77
85
  }
78
- rb_gc_mark( pg_tuple_get_field_names(this) );
86
+ rb_gc_mark_movable( pg_tuple_get_field_names(this) );
79
87
  }
80
88
 
81
89
  static void
82
- pg_tuple_gc_free( t_pg_tuple *this )
90
+ pg_tuple_gc_compact( void *_this )
83
91
  {
92
+ t_pg_tuple *this = (t_pg_tuple *)_this;
93
+ int i;
94
+
95
+ if( !this ) return;
96
+ pg_gc_location( this->result );
97
+ pg_gc_location( this->typemap );
98
+ pg_gc_location( this->field_map );
99
+
100
+ for( i = 0; i < this->num_fields; i++ ){
101
+ pg_gc_location( this->values[i] );
102
+ }
103
+ pg_gc_location( *pg_tuple_get_field_names_ptr(this) );
104
+ }
105
+
106
+ static void
107
+ pg_tuple_gc_free( void *_this )
108
+ {
109
+ t_pg_tuple *this = (t_pg_tuple *)_this;
84
110
  if( !this ) return;
85
111
  xfree(this);
86
112
  }
87
113
 
88
114
  static size_t
89
- pg_tuple_memsize( t_pg_tuple *this )
115
+ pg_tuple_memsize( const void *_this )
90
116
  {
117
+ const t_pg_tuple *this = (const t_pg_tuple *)_this;
91
118
  if( this==NULL ) return 0;
92
119
  return sizeof(*this) + sizeof(*this->values) * this->num_fields;
93
120
  }
94
121
 
95
122
  static const rb_data_type_t pg_tuple_type = {
96
- "pg",
123
+ "PG::Tuple",
97
124
  {
98
- (void (*)(void*))pg_tuple_gc_mark,
99
- (void (*)(void*))pg_tuple_gc_free,
100
- (size_t (*)(const void *))pg_tuple_memsize,
125
+ pg_tuple_gc_mark,
126
+ pg_tuple_gc_free,
127
+ pg_tuple_memsize,
128
+ pg_tuple_gc_compact,
101
129
  },
102
130
  0, 0,
103
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
104
- RUBY_TYPED_FREE_IMMEDIATELY,
105
- #endif
131
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
106
132
  };
107
133
 
108
134
  /*
109
135
  * Document-method: allocate
110
136
  *
111
137
  * call-seq:
112
- * PG::VeryTuple.allocate -> obj
138
+ * PG::Tuple.allocate -> obj
113
139
  */
114
140
  static VALUE
115
141
  pg_tuple_s_allocate( VALUE klass )
@@ -133,9 +159,9 @@ pg_tuple_new(VALUE result, int row_num)
133
159
  sizeof(*this->values) * num_fields +
134
160
  sizeof(*this->values) * (dup_names ? 1 : 0));
135
161
 
136
- this->result = result;
137
- this->typemap = p_result->typemap;
138
- this->field_map = field_map;
162
+ RB_OBJ_WRITE(self, &this->result, result);
163
+ RB_OBJ_WRITE(self, &this->typemap, p_result->typemap);
164
+ RB_OBJ_WRITE(self, &this->field_map, field_map);
139
165
  this->row_num = row_num;
140
166
  this->num_fields = num_fields;
141
167
 
@@ -147,7 +173,8 @@ pg_tuple_new(VALUE result, int row_num)
147
173
  /* Some of the column names are duplicated -> we need the keys as Array in addition.
148
174
  * Store it behind the values to save the space in the common case of no dups.
149
175
  */
150
- this->values[num_fields] = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
176
+ VALUE keys_array = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
177
+ RB_OBJ_WRITE(self, &this->values[num_fields], keys_array);
151
178
  }
152
179
 
153
180
  RTYPEDDATA_DATA(self) = this;
@@ -167,38 +194,41 @@ pg_tuple_get_this( VALUE self )
167
194
  }
168
195
 
169
196
  static VALUE
170
- pg_tuple_materialize_field(t_pg_tuple *this, int col)
197
+ pg_tuple_materialize_field(VALUE self, int col)
171
198
  {
199
+ t_pg_tuple *this = RTYPEDDATA_DATA( self );
172
200
  VALUE value = this->values[col];
173
201
 
174
202
  if( value == Qundef ){
175
- t_typemap *p_typemap = DATA_PTR( this->typemap );
203
+ t_typemap *p_typemap = RTYPEDDATA_DATA( this->typemap );
176
204
 
177
205
  pgresult_get(this->result); /* make sure we have a valid PGresult object */
178
206
  value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
179
- this->values[col] = value;
207
+ RB_OBJ_WRITE(self, &this->values[col], value);
180
208
  }
181
209
 
182
210
  return value;
183
211
  }
184
212
 
185
213
  static void
186
- pg_tuple_detach(t_pg_tuple *this)
214
+ pg_tuple_detach(VALUE self)
187
215
  {
188
- this->result = Qnil;
189
- this->typemap = Qnil;
216
+ t_pg_tuple *this = RTYPEDDATA_DATA( self );
217
+ RB_OBJ_WRITE(self, &this->result, Qnil);
218
+ RB_OBJ_WRITE(self, &this->typemap, Qnil);
190
219
  this->row_num = -1;
191
220
  }
192
221
 
193
222
  static void
194
- pg_tuple_materialize(t_pg_tuple *this)
223
+ pg_tuple_materialize(VALUE self)
195
224
  {
225
+ t_pg_tuple *this = RTYPEDDATA_DATA( self );
196
226
  int field_num;
197
227
  for(field_num = 0; field_num < this->num_fields; field_num++) {
198
- pg_tuple_materialize_field(this, field_num);
228
+ pg_tuple_materialize_field(self, field_num);
199
229
  }
200
230
 
201
- pg_tuple_detach(this);
231
+ pg_tuple_detach(self);
202
232
  }
203
233
 
204
234
  /*
@@ -260,7 +290,7 @@ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
260
290
  field_num = NUM2INT(index);
261
291
  }
262
292
 
263
- return pg_tuple_materialize_field(this, field_num);
293
+ return pg_tuple_materialize_field(self, field_num);
264
294
  }
265
295
 
266
296
  /*
@@ -298,7 +328,7 @@ pg_tuple_aref(VALUE self, VALUE key)
298
328
  field_num = NUM2INT(index);
299
329
  }
300
330
 
301
- return pg_tuple_materialize_field(this, field_num);
331
+ return pg_tuple_materialize_field(self, field_num);
302
332
  }
303
333
 
304
334
  static VALUE
@@ -309,10 +339,9 @@ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
309
339
  }
310
340
 
311
341
  static int
312
- pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
342
+ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE self)
313
343
  {
314
- t_pg_tuple *this = (t_pg_tuple *)_this;
315
- VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
344
+ VALUE value = pg_tuple_materialize_field(self, NUM2INT(index));
316
345
  rb_yield_values(2, key, value);
317
346
  return ST_CONTINUE;
318
347
  }
@@ -334,16 +363,16 @@ pg_tuple_each(VALUE self)
334
363
  field_names = pg_tuple_get_field_names(this);
335
364
 
336
365
  if( field_names == Qfalse ){
337
- rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, (VALUE)this);
366
+ rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, self);
338
367
  } else {
339
368
  int i;
340
369
  for( i = 0; i < this->num_fields; i++ ){
341
- VALUE value = pg_tuple_materialize_field(this, i);
370
+ VALUE value = pg_tuple_materialize_field(self, i);
342
371
  rb_yield_values(2, RARRAY_AREF(field_names, i), value);
343
372
  }
344
373
  }
345
374
 
346
- pg_tuple_detach(this);
375
+ pg_tuple_detach(self);
347
376
  return self;
348
377
  }
349
378
 
@@ -362,11 +391,11 @@ pg_tuple_each_value(VALUE self)
362
391
  RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
363
392
 
364
393
  for(field_num = 0; field_num < this->num_fields; field_num++) {
365
- VALUE value = pg_tuple_materialize_field(this, field_num);
394
+ VALUE value = pg_tuple_materialize_field(self, field_num);
366
395
  rb_yield(value);
367
396
  }
368
397
 
369
- pg_tuple_detach(this);
398
+ pg_tuple_detach(self);
370
399
  return self;
371
400
  }
372
401
 
@@ -383,7 +412,7 @@ pg_tuple_values(VALUE self)
383
412
  {
384
413
  t_pg_tuple *this = pg_tuple_get_this(self);
385
414
 
386
- pg_tuple_materialize(this);
415
+ pg_tuple_materialize(self);
387
416
  return rb_ary_new4(this->num_fields, &this->values[0]);
388
417
  }
389
418
 
@@ -436,7 +465,7 @@ pg_tuple_dump(VALUE self)
436
465
  VALUE a;
437
466
  t_pg_tuple *this = pg_tuple_get_this(self);
438
467
 
439
- pg_tuple_materialize(this);
468
+ pg_tuple_materialize(self);
440
469
 
441
470
  field_names = pg_tuple_get_field_names(this);
442
471
  if( field_names == Qfalse )
@@ -445,10 +474,7 @@ pg_tuple_dump(VALUE self)
445
474
  values = rb_ary_new4(this->num_fields, &this->values[0]);
446
475
  a = rb_ary_new3(2, field_names, values);
447
476
 
448
- if (FL_TEST(self, FL_EXIVAR)) {
449
- rb_copy_generic_ivar(a, self);
450
- FL_SET(a, FL_EXIVAR);
451
- }
477
+ rb_copy_generic_ivar(a, self);
452
478
 
453
479
  return a;
454
480
  }
@@ -479,9 +505,9 @@ pg_tuple_load(VALUE self, VALUE a)
479
505
  rb_obj_freeze(field_names);
480
506
  values = RARRAY_AREF(a, 1);
481
507
  Check_Type(values, T_ARRAY);
482
- num_fields = RARRAY_LEN(values);
508
+ num_fields = RARRAY_LENINT(values);
483
509
 
484
- if (RARRAY_LEN(field_names) != num_fields)
510
+ if (RARRAY_LENINT(field_names) != num_fields)
485
511
  rb_raise(rb_eTypeError, "different number of fields and values");
486
512
 
487
513
  field_map = rb_hash_new();
@@ -497,35 +523,32 @@ pg_tuple_load(VALUE self, VALUE a)
497
523
  sizeof(*this->values) * num_fields +
498
524
  sizeof(*this->values) * (dup_names ? 1 : 0));
499
525
 
500
- this->result = Qnil;
501
- this->typemap = Qnil;
526
+ RB_OBJ_WRITE(self, &this->result, Qnil);
527
+ RB_OBJ_WRITE(self, &this->typemap, Qnil);
502
528
  this->row_num = -1;
503
529
  this->num_fields = num_fields;
504
- this->field_map = field_map;
530
+ RB_OBJ_WRITE(self, &this->field_map, field_map);
505
531
 
506
532
  for( i = 0; i < num_fields; i++ ){
507
533
  VALUE v = RARRAY_AREF(values, i);
508
534
  if( v == Qundef )
509
535
  rb_raise(rb_eTypeError, "field %d is not materialized", i);
510
- this->values[i] = v;
536
+ RB_OBJ_WRITE(self, &this->values[i], v);
511
537
  }
512
538
 
513
539
  if( dup_names ){
514
- this->values[num_fields] = field_names;
540
+ RB_OBJ_WRITE(self, &this->values[num_fields], field_names);
515
541
  }
516
542
 
517
543
  RTYPEDDATA_DATA(self) = this;
518
544
 
519
- if (FL_TEST(a, FL_EXIVAR)) {
520
- rb_copy_generic_ivar(self, a);
521
- FL_SET(self, FL_EXIVAR);
522
- }
545
+ rb_copy_generic_ivar(self, a);
523
546
 
524
547
  return self;
525
548
  }
526
549
 
527
550
  void
528
- init_pg_tuple()
551
+ init_pg_tuple(void)
529
552
  {
530
553
  rb_cPG_Tuple = rb_define_class_under( rb_mPG, "Tuple", rb_cObject );
531
554
  rb_define_alloc_func( rb_cPG_Tuple, pg_tuple_s_allocate );
data/ext/pg_type_map.c CHANGED
@@ -6,6 +6,40 @@
6
6
 
7
7
  #include "pg.h"
8
8
 
9
+ void
10
+ pg_typemap_mark( void *_this )
11
+ {
12
+ t_typemap *this = (t_typemap *)_this;
13
+ rb_gc_mark_movable(this->default_typemap);
14
+ }
15
+
16
+ size_t
17
+ pg_typemap_memsize( const void *_this )
18
+ {
19
+ t_typemap *this = (t_typemap *)_this;
20
+ return sizeof(*this);
21
+ }
22
+
23
+ void
24
+ pg_typemap_compact( void *_this )
25
+ {
26
+ t_typemap *this = (t_typemap *)_this;
27
+ pg_gc_location(this->default_typemap);
28
+ }
29
+
30
+ const rb_data_type_t pg_typemap_type = {
31
+ "PG::TypeMap",
32
+ {
33
+ pg_typemap_mark,
34
+ RUBY_TYPED_DEFAULT_FREE,
35
+ pg_typemap_memsize,
36
+ pg_typemap_compact,
37
+ },
38
+ 0,
39
+ 0,
40
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
41
+ };
42
+
9
43
  VALUE rb_cTypeMap;
10
44
  VALUE rb_mDefaultTypeMappable;
11
45
  static ID s_id_fit_to_query;
@@ -75,7 +109,7 @@ pg_typemap_s_allocate( VALUE klass )
75
109
  VALUE self;
76
110
  t_typemap *this;
77
111
 
78
- self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
112
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_typemap_type, this );
79
113
  this->funcs = pg_typemap_funcs;
80
114
 
81
115
  return self;
@@ -94,14 +128,14 @@ pg_typemap_s_allocate( VALUE klass )
94
128
  static VALUE
95
129
  pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
96
130
  {
97
- t_typemap *this = DATA_PTR( self );
131
+ t_typemap *this = RTYPEDDATA_DATA( self );
132
+ t_typemap *tm;
133
+ UNUSED(tm);
98
134
 
99
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
100
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
101
- rb_obj_classname( typemap ) );
102
- }
103
- Check_Type(typemap, T_DATA);
104
- this->default_typemap = typemap;
135
+ rb_check_frozen(self);
136
+ /* Check type of method param */
137
+ TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
138
+ RB_OBJ_WRITE(self, &this->default_typemap, typemap);
105
139
 
106
140
  return typemap;
107
141
  }
@@ -119,7 +153,7 @@ pg_typemap_default_type_map_set(VALUE self, VALUE typemap)
119
153
  static VALUE
120
154
  pg_typemap_default_type_map_get(VALUE self)
121
155
  {
122
- t_typemap *this = DATA_PTR( self );
156
+ t_typemap *this = RTYPEDDATA_DATA( self );
123
157
 
124
158
  return this->default_typemap;
125
159
  }
@@ -143,7 +177,7 @@ pg_typemap_with_default_type_map(VALUE self, VALUE typemap)
143
177
  }
144
178
 
145
179
  void
146
- init_pg_type_map()
180
+ init_pg_type_map(void)
147
181
  {
148
182
  s_id_fit_to_query = rb_intern("fit_to_query");
149
183
  s_id_fit_to_result = rb_intern("fit_to_result");
@@ -8,6 +8,19 @@
8
8
 
9
9
  #include "pg.h"
10
10
 
11
+ static const rb_data_type_t pg_tmas_type = {
12
+ "PG::TypeMapAllStrings",
13
+ {
14
+ pg_typemap_mark,
15
+ RUBY_TYPED_DEFAULT_FREE,
16
+ pg_typemap_memsize,
17
+ pg_typemap_compact,
18
+ },
19
+ &pg_typemap_type,
20
+ 0,
21
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
22
+ };
23
+
11
24
  VALUE rb_cTypeMapAllStrings;
12
25
  VALUE pg_typemap_all_strings;
13
26
 
@@ -63,6 +76,7 @@ pg_tmas_fit_to_copy_get( VALUE self )
63
76
  static VALUE
64
77
  pg_tmas_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format, int enc_idx )
65
78
  {
79
+ rb_str_modify(field_str);
66
80
  if( format == 0 ){
67
81
  PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
68
82
  } else {
@@ -77,7 +91,7 @@ pg_tmas_s_allocate( VALUE klass )
77
91
  t_typemap *this;
78
92
  VALUE self;
79
93
 
80
- self = Data_Make_Struct( klass, t_typemap, NULL, -1, this );
94
+ self = TypedData_Make_Struct( klass, t_typemap, &pg_tmas_type, this );
81
95
 
82
96
  this->funcs.fit_to_result = pg_tmas_fit_to_result;
83
97
  this->funcs.fit_to_query = pg_tmas_fit_to_query;
@@ -91,7 +105,7 @@ pg_tmas_s_allocate( VALUE klass )
91
105
 
92
106
 
93
107
  void
94
- init_pg_type_map_all_strings()
108
+ init_pg_type_map_all_strings(void)
95
109
  {
96
110
  /*
97
111
  * Document-class: PG::TypeMapAllStrings < PG::TypeMap
@@ -111,6 +125,6 @@ init_pg_type_map_all_strings()
111
125
  rb_cTypeMapAllStrings = rb_define_class_under( rb_mPG, "TypeMapAllStrings", rb_cTypeMap );
112
126
  rb_define_alloc_func( rb_cTypeMapAllStrings, pg_tmas_s_allocate );
113
127
 
114
- pg_typemap_all_strings = rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 );
128
+ pg_typemap_all_strings = rb_obj_freeze( rb_funcall( rb_cTypeMapAllStrings, rb_intern("new"), 0 ));
115
129
  rb_gc_register_address( &pg_typemap_all_strings );
116
130
  }
@@ -10,7 +10,6 @@
10
10
  #include "pg.h"
11
11
 
12
12
  static VALUE rb_cTypeMapByClass;
13
- static ID s_id_ancestors;
14
13
 
15
14
  typedef struct {
16
15
  t_typemap typemap;
@@ -48,7 +47,7 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
48
47
 
49
48
  if( NIL_P(obj) ){
50
49
  int i;
51
- VALUE ancestors = rb_funcall( klass, s_id_ancestors, 0 );
50
+ VALUE ancestors = rb_mod_ancestors( klass );
52
51
 
53
52
  Check_Type( ancestors, T_ARRAY );
54
53
  /* Don't look at the first element, it's expected to equal klass. */
@@ -63,7 +62,7 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
63
62
  if(NIL_P(obj)){
64
63
  p_coder = NULL;
65
64
  }else if(rb_obj_is_kind_of(obj, rb_cPG_Coder)){
66
- Data_Get_Struct(obj, t_pg_coder, p_coder);
65
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
67
66
  }else{
68
67
  if( RB_TYPE_P(obj, T_SYMBOL) ){
69
68
  /* A Symbol: Call the method with this name. */
@@ -75,11 +74,9 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value)
75
74
 
76
75
  if( NIL_P(obj) ){
77
76
  p_coder = NULL;
78
- }else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
79
- Data_Get_Struct(obj, t_pg_coder, p_coder);
80
77
  }else{
81
- rb_raise(rb_eTypeError, "argument has invalid type %s (should be nil or some kind of PG::Coder)",
82
- rb_obj_classname( obj ));
78
+ /* Check retrieved coder type */
79
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
83
80
  }
84
81
 
85
82
  /* We can not cache coders retrieved by ruby code, because we can not anticipate
@@ -104,7 +101,7 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
104
101
  p_coder = pg_tmbk_lookup_klass( this, rb_obj_class(param_value), param_value );
105
102
 
106
103
  if( !p_coder ){
107
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
104
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
108
105
  return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
109
106
  }
110
107
 
@@ -114,46 +111,76 @@ pg_tmbk_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
114
111
  static VALUE
115
112
  pg_tmbk_fit_to_query( VALUE self, VALUE params )
116
113
  {
117
- t_tmbk *this = (t_tmbk *)DATA_PTR(self);
114
+ t_tmbk *this = (t_tmbk *)RTYPEDDATA_DATA(self);
118
115
  /* Nothing to check at this typemap, but ensure that the default type map fits. */
119
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
116
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
120
117
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
121
118
  return self;
122
119
  }
123
120
 
124
121
  static void
125
- pg_tmbk_mark( t_tmbk *this )
122
+ pg_tmbk_mark( void *_this )
126
123
  {
127
- rb_gc_mark(this->typemap.default_typemap);
128
- rb_gc_mark(this->klass_to_coder);
129
- rb_gc_mark(this->self);
130
- /* Clear the cache, to be safe from changes of klass VALUE by GC.compact.
131
- * TODO: Move cache clearing to compactation callback provided by Ruby-2.7+.
132
- */
124
+ t_tmbk *this = (t_tmbk *)_this;
125
+ pg_typemap_mark(&this->typemap);
126
+ rb_gc_mark_movable(this->klass_to_coder);
127
+ rb_gc_mark_movable(this->self);
128
+ }
129
+
130
+ static size_t
131
+ pg_tmbk_memsize( const void *_this )
132
+ {
133
+ const t_tmbk *this = (const t_tmbk *)_this;
134
+ return sizeof(*this);
135
+ }
136
+
137
+ static void
138
+ pg_tmbk_compact(void *ptr)
139
+ {
140
+ t_tmbk *this = (t_tmbk *)ptr;
141
+
142
+ pg_typemap_compact(&this->typemap);
143
+ pg_gc_location(this->klass_to_coder);
144
+ pg_gc_location(this->self);
145
+
146
+ /* Clear the cache, to be safe from changes of klass VALUE by GC.compact. */
133
147
  memset(&this->cache_row, 0, sizeof(this->cache_row));
134
148
  }
135
149
 
150
+ static const rb_data_type_t pg_tmbk_type = {
151
+ "PG::TypeMapByClass",
152
+ {
153
+ pg_tmbk_mark,
154
+ RUBY_TYPED_DEFAULT_FREE,
155
+ pg_tmbk_memsize,
156
+ pg_tmbk_compact,
157
+ },
158
+ &pg_typemap_type,
159
+ 0,
160
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
161
+ };
162
+
136
163
  static VALUE
137
164
  pg_tmbk_s_allocate( VALUE klass )
138
165
  {
139
166
  t_tmbk *this;
140
167
  VALUE self;
141
168
 
142
- self = Data_Make_Struct( klass, t_tmbk, pg_tmbk_mark, -1, this );
169
+ self = TypedData_Make_Struct( klass, t_tmbk, &pg_tmbk_type, this );
143
170
  this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
144
171
  this->typemap.funcs.fit_to_query = pg_tmbk_fit_to_query;
145
172
  this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
146
173
  this->typemap.funcs.typecast_result_value = pg_typemap_result_value;
147
174
  this->typemap.funcs.typecast_query_param = pg_tmbk_typecast_query_param;
148
175
  this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
149
- this->typemap.default_typemap = pg_typemap_all_strings;
176
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
150
177
 
151
178
  /* We need to store self in the this-struct, because pg_tmbk_typecast_query_param(),
152
179
  * is called with the this-pointer only. */
153
180
  this->self = self;
154
- this->klass_to_coder = rb_hash_new();
181
+ RB_OBJ_WRITE(self, &this->klass_to_coder, rb_hash_new());
155
182
 
156
- /* The cache is properly initialized by Data_Make_Struct(). */
183
+ /* The cache is properly initialized by TypedData_Make_Struct(). */
157
184
 
158
185
  return self;
159
186
  }
@@ -176,7 +203,9 @@ pg_tmbk_s_allocate( VALUE klass )
176
203
  static VALUE
177
204
  pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
178
205
  {
179
- t_tmbk *this = DATA_PTR( self );
206
+ t_tmbk *this = RTYPEDDATA_DATA( self );
207
+
208
+ rb_check_frozen(self);
180
209
 
181
210
  if(NIL_P(coder)){
182
211
  rb_hash_delete( this->klass_to_coder, klass );
@@ -200,7 +229,7 @@ pg_tmbk_aset( VALUE self, VALUE klass, VALUE coder )
200
229
  static VALUE
201
230
  pg_tmbk_aref( VALUE self, VALUE klass )
202
231
  {
203
- t_tmbk *this = DATA_PTR( self );
232
+ t_tmbk *this = RTYPEDDATA_DATA( self );
204
233
 
205
234
  return rb_hash_lookup(this->klass_to_coder, klass);
206
235
  }
@@ -214,16 +243,14 @@ pg_tmbk_aref( VALUE self, VALUE klass )
214
243
  static VALUE
215
244
  pg_tmbk_coders( VALUE self )
216
245
  {
217
- t_tmbk *this = DATA_PTR( self );
246
+ t_tmbk *this = RTYPEDDATA_DATA( self );
218
247
 
219
248
  return rb_obj_freeze(rb_hash_dup(this->klass_to_coder));
220
249
  }
221
250
 
222
251
  void
223
- init_pg_type_map_by_class()
252
+ init_pg_type_map_by_class(void)
224
253
  {
225
- s_id_ancestors = rb_intern("ancestors");
226
-
227
254
  /*
228
255
  * Document-class: PG::TypeMapByClass < PG::TypeMap
229
256
  *