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
@@ -16,7 +16,7 @@ static VALUE
16
16
  pg_tmbc_fit_to_result( VALUE self, VALUE result )
17
17
  {
18
18
  int nfields;
19
- t_tmbc *this = DATA_PTR( self );
19
+ t_tmbc *this = RTYPEDDATA_DATA( self );
20
20
  t_typemap *default_tm;
21
21
  VALUE sub_typemap;
22
22
 
@@ -26,8 +26,8 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
26
26
  nfields, this->nfields );
27
27
  }
28
28
 
29
- /* Ensure that the default type map fits equaly. */
30
- default_tm = DATA_PTR( this->typemap.default_typemap );
29
+ /* Ensure that the default type map fits equally. */
30
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
31
31
  sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
32
32
 
33
33
  /* Did the default type return the same object ? */
@@ -42,7 +42,7 @@ pg_tmbc_fit_to_result( VALUE self, VALUE result )
42
42
 
43
43
  memcpy( p_new_typemap, this, struct_size );
44
44
  p_new_typemap->typemap.default_typemap = sub_typemap;
45
- DATA_PTR(new_typemap) = p_new_typemap;
45
+ RTYPEDDATA_DATA(new_typemap) = p_new_typemap;
46
46
  return new_typemap;
47
47
  }
48
48
  }
@@ -51,17 +51,18 @@ static VALUE
51
51
  pg_tmbc_fit_to_query( VALUE self, VALUE params )
52
52
  {
53
53
  int nfields;
54
- t_tmbc *this = DATA_PTR( self );
54
+ t_tmbc *this = RTYPEDDATA_DATA( self );
55
55
  t_typemap *default_tm;
56
56
 
57
+ Check_Type(params, T_ARRAY);
57
58
  nfields = (int)RARRAY_LEN( params );
58
59
  if ( this->nfields != nfields ) {
59
60
  rb_raise( rb_eArgError, "number of result fields (%d) does not match number of mapped columns (%d)",
60
61
  nfields, this->nfields );
61
62
  }
62
63
 
63
- /* Ensure that the default type map fits equaly. */
64
- default_tm = DATA_PTR( this->typemap.default_typemap );
64
+ /* Ensure that the default type map fits equally. */
65
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
65
66
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
66
67
 
67
68
  return self;
@@ -70,10 +71,10 @@ pg_tmbc_fit_to_query( VALUE self, VALUE params )
70
71
  static int
71
72
  pg_tmbc_fit_to_copy_get( VALUE self )
72
73
  {
73
- t_tmbc *this = DATA_PTR( self );
74
+ t_tmbc *this = RTYPEDDATA_DATA( self );
74
75
 
75
- /* Ensure that the default type map fits equaly. */
76
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
76
+ /* Ensure that the default type map fits equally. */
77
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
77
78
  default_tm->funcs.fit_to_copy_get( this->typemap.default_typemap );
78
79
 
79
80
  return this->nfields;
@@ -107,7 +108,7 @@ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field )
107
108
  }
108
109
  }
109
110
 
110
- default_tm = DATA_PTR( this->typemap.default_typemap );
111
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
111
112
  return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
112
113
  }
113
114
 
@@ -120,7 +121,7 @@ pg_tmbc_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int field
120
121
  t_pg_coder *p_coder = this->convs[field].cconv;
121
122
 
122
123
  if( !p_coder ){
123
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
124
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
124
125
  return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
125
126
  }
126
127
 
@@ -142,7 +143,7 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
142
143
  p_coder = this->convs[fieldno].cconv;
143
144
 
144
145
  if( !p_coder ){
145
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
146
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
146
147
  return default_tm->funcs.typecast_copy_get( default_tm, field_str, fieldno, format, enc_idx );
147
148
  }
148
149
 
@@ -150,15 +151,17 @@ pg_tmbc_typecast_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, i
150
151
 
151
152
  /* Is it a pure String conversion? Then we can directly send field_str to the user. */
152
153
  if( dec_func == pg_text_dec_string ){
154
+ rb_str_modify(field_str);
153
155
  PG_ENCODING_SET_NOCHECK( field_str, enc_idx );
154
156
  return field_str;
155
157
  }
156
158
  if( dec_func == pg_bin_dec_bytea ){
159
+ rb_str_modify(field_str);
157
160
  PG_ENCODING_SET_NOCHECK( field_str, rb_ascii8bit_encindex() );
158
161
  return field_str;
159
162
  }
160
163
 
161
- return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LEN(field_str), 0, fieldno, enc_idx );
164
+ return dec_func( p_coder, RSTRING_PTR(field_str), RSTRING_LENINT(field_str), 0, fieldno, enc_idx );
162
165
  }
163
166
 
164
167
  const struct pg_typemap_funcs pg_tmbc_funcs = {
@@ -171,38 +174,77 @@ const struct pg_typemap_funcs pg_tmbc_funcs = {
171
174
  };
172
175
 
173
176
  static void
174
- pg_tmbc_mark( t_tmbc *this )
177
+ pg_tmbc_mark( void *_this )
175
178
  {
179
+ t_tmbc *this = (t_tmbc *)_this;
176
180
  int i;
177
181
 
178
182
  /* allocated but not initialized ? */
179
183
  if( this == (t_tmbc *)&pg_typemap_funcs ) return;
180
184
 
181
- rb_gc_mark(this->typemap.default_typemap);
185
+ pg_typemap_mark(&this->typemap);
182
186
  for( i=0; i<this->nfields; i++){
183
187
  t_pg_coder *p_coder = this->convs[i].cconv;
184
188
  if( p_coder )
185
- rb_gc_mark(p_coder->coder_obj);
189
+ rb_gc_mark_movable(p_coder->coder_obj);
190
+ }
191
+ }
192
+
193
+ static size_t
194
+ pg_tmbc_memsize( const void *_this )
195
+ {
196
+ const t_tmbc *this = (const t_tmbc *)_this;
197
+ return sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * this->nfields;
198
+ }
199
+
200
+ static void
201
+ pg_tmbc_compact( void *_this )
202
+ {
203
+ t_tmbc *this = (t_tmbc *)_this;
204
+ int i;
205
+
206
+ /* allocated but not initialized ? */
207
+ if( this == (t_tmbc *)&pg_typemap_funcs ) return;
208
+
209
+ pg_typemap_compact(&this->typemap);
210
+ for( i=0; i<this->nfields; i++){
211
+ t_pg_coder *p_coder = this->convs[i].cconv;
212
+ if( p_coder )
213
+ pg_gc_location(p_coder->coder_obj);
186
214
  }
187
215
  }
188
216
 
189
217
  static void
190
- pg_tmbc_free( t_tmbc *this )
218
+ pg_tmbc_free( void *_this )
191
219
  {
220
+ t_tmbc *this = (t_tmbc *)_this;
192
221
  /* allocated but not initialized ? */
193
222
  if( this == (t_tmbc *)&pg_typemap_funcs ) return;
194
223
  xfree( this );
195
224
  }
196
225
 
226
+ static const rb_data_type_t pg_tmbc_type = {
227
+ "PG::TypeMapByColumn",
228
+ {
229
+ pg_tmbc_mark,
230
+ pg_tmbc_free,
231
+ pg_tmbc_memsize,
232
+ pg_tmbc_compact,
233
+ },
234
+ &pg_typemap_type,
235
+ 0,
236
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
237
+ };
238
+
197
239
  static VALUE
198
240
  pg_tmbc_s_allocate( VALUE klass )
199
241
  {
200
242
  /* Use pg_typemap_funcs as interim struct until #initialize is called. */
201
- return Data_Wrap_Struct( klass, pg_tmbc_mark, pg_tmbc_free, (t_tmbc *)&pg_typemap_funcs );
243
+ return TypedData_Wrap_Struct( klass, &pg_tmbc_type, (t_tmbc *)&pg_typemap_funcs );
202
244
  }
203
245
 
204
246
  VALUE
205
- pg_tmbc_allocate()
247
+ pg_tmbc_allocate(void)
206
248
  {
207
249
  return pg_tmbc_s_allocate(rb_cTypeMapByColumn);
208
250
  }
@@ -221,19 +263,19 @@ pg_tmbc_allocate()
221
263
  static VALUE
222
264
  pg_tmbc_init(VALUE self, VALUE conv_ary)
223
265
  {
224
- int i;
266
+ long i;
225
267
  t_tmbc *this;
226
268
  int conv_ary_len;
227
269
 
228
- Check_Type(self, T_DATA);
270
+ rb_check_frozen(self);
229
271
  Check_Type(conv_ary, T_ARRAY);
230
- conv_ary_len = RARRAY_LEN(conv_ary);
272
+ conv_ary_len = RARRAY_LENINT(conv_ary);
231
273
  this = xmalloc(sizeof(t_tmbc) + sizeof(struct pg_tmbc_converter) * conv_ary_len);
232
274
  /* Set nfields to 0 at first, so that GC mark function doesn't access uninitialized memory. */
233
275
  this->nfields = 0;
234
276
  this->typemap.funcs = pg_tmbc_funcs;
235
- this->typemap.default_typemap = pg_typemap_all_strings;
236
- DATA_PTR(self) = this;
277
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
278
+ RTYPEDDATA_DATA(self) = this;
237
279
 
238
280
  for(i=0; i<conv_ary_len; i++)
239
281
  {
@@ -242,11 +284,12 @@ pg_tmbc_init(VALUE self, VALUE conv_ary)
242
284
  if( obj == Qnil ){
243
285
  /* no type cast */
244
286
  this->convs[i].cconv = NULL;
245
- } else if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
246
- Data_Get_Struct(obj, t_pg_coder, this->convs[i].cconv);
247
287
  } else {
248
- rb_raise(rb_eArgError, "argument %d has invalid type %s (should be nil or some kind of PG::Coder)",
249
- i+1, rb_obj_classname( obj ));
288
+ t_pg_coder *p_coder;
289
+ /* Check argument type and store the coder pointer */
290
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
291
+ RB_OBJ_WRITTEN(self, Qnil, p_coder->coder_obj);
292
+ this->convs[i].cconv = p_coder;
250
293
  }
251
294
  }
252
295
 
@@ -266,7 +309,7 @@ static VALUE
266
309
  pg_tmbc_coders(VALUE self)
267
310
  {
268
311
  int i;
269
- t_tmbc *this = DATA_PTR( self );
312
+ t_tmbc *this = RTYPEDDATA_DATA( self );
270
313
  VALUE ary_coders = rb_ary_new();
271
314
 
272
315
  for( i=0; i<this->nfields; i++){
@@ -282,7 +325,7 @@ pg_tmbc_coders(VALUE self)
282
325
  }
283
326
 
284
327
  void
285
- init_pg_type_map_by_column()
328
+ init_pg_type_map_by_column(void)
286
329
  {
287
330
  s_id_decode = rb_intern("decode");
288
331
  s_id_encode = rb_intern("encode");
@@ -71,16 +71,12 @@ pg_tmbmt_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int fiel
71
71
 
72
72
  obj = rb_funcall(ask_for_coder, rb_intern("call"), 1, param_value);
73
73
 
74
- if( rb_obj_is_kind_of(obj, rb_cPG_Coder) ){
75
- Data_Get_Struct(obj, t_pg_coder, p_coder);
76
- }else{
77
- rb_raise(rb_eTypeError, "argument %d has invalid type %s (should be nil or some kind of PG::Coder)",
78
- field+1, rb_obj_classname( obj ));
79
- }
74
+ /* Check argument type and store the coder pointer */
75
+ TypedData_Get_Struct(obj, t_pg_coder, &pg_coder_type, p_coder);
80
76
  }
81
77
 
82
78
  if( !p_coder ){
83
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
79
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
84
80
  return default_tm->funcs.typecast_query_param( default_tm, param_value, field );
85
81
  }
86
82
 
@@ -90,24 +86,57 @@ pg_tmbmt_typecast_query_param( t_typemap *p_typemap, VALUE param_value, int fiel
90
86
  static VALUE
91
87
  pg_tmbmt_fit_to_query( VALUE self, VALUE params )
92
88
  {
93
- t_tmbmt *this = (t_tmbmt *)DATA_PTR(self);
89
+ t_tmbmt *this = (t_tmbmt *)RTYPEDDATA_DATA(self);
94
90
  /* Nothing to check at this typemap, but ensure that the default type map fits. */
95
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
91
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
96
92
  default_tm->funcs.fit_to_query( this->typemap.default_typemap, params );
97
93
  return self;
98
94
  }
99
95
 
100
96
  #define GC_MARK_AS_USED(type) \
101
- rb_gc_mark( this->coders.ask_##type ); \
102
- rb_gc_mark( this->coders.coder_obj_##type );
97
+ rb_gc_mark_movable( this->coders.ask_##type ); \
98
+ rb_gc_mark_movable( this->coders.coder_obj_##type );
103
99
 
104
100
  static void
105
- pg_tmbmt_mark( t_tmbmt *this )
101
+ pg_tmbmt_mark( void *_this )
106
102
  {
107
- rb_gc_mark(this->typemap.default_typemap);
103
+ t_tmbmt *this = (t_tmbmt *)_this;
104
+ pg_typemap_mark(&this->typemap);
108
105
  FOR_EACH_MRI_TYPE( GC_MARK_AS_USED );
109
106
  }
110
107
 
108
+ static size_t
109
+ pg_tmbmt_memsize( const void *_this )
110
+ {
111
+ const t_tmbmt *this = (const t_tmbmt *)_this;
112
+ return sizeof(*this);
113
+ }
114
+
115
+ #define GC_COMPACT(type) \
116
+ pg_gc_location( this->coders.ask_##type ); \
117
+ pg_gc_location( this->coders.coder_obj_##type );
118
+
119
+ static void
120
+ pg_tmbmt_compact( void *_this )
121
+ {
122
+ t_tmbmt *this = (t_tmbmt *)_this;
123
+ pg_typemap_compact(&this->typemap);
124
+ FOR_EACH_MRI_TYPE( GC_COMPACT );
125
+ }
126
+
127
+ static const rb_data_type_t pg_tmbmt_type = {
128
+ "PG::TypeMapByMriType",
129
+ {
130
+ pg_tmbmt_mark,
131
+ RUBY_TYPED_DEFAULT_FREE,
132
+ pg_tmbmt_memsize,
133
+ pg_tmbmt_compact,
134
+ },
135
+ &pg_typemap_type,
136
+ 0,
137
+ RUBY_TYPED_FREE_IMMEDIATELY,
138
+ };
139
+
111
140
  #define INIT_VARIABLES(type) \
112
141
  this->coders.coder_##type = NULL; \
113
142
  this->coders.ask_##type = Qnil; \
@@ -119,7 +148,7 @@ pg_tmbmt_s_allocate( VALUE klass )
119
148
  t_tmbmt *this;
120
149
  VALUE self;
121
150
 
122
- self = Data_Make_Struct( klass, t_tmbmt, pg_tmbmt_mark, -1, this );
151
+ self = TypedData_Make_Struct( klass, t_tmbmt, &pg_tmbmt_type, this );
123
152
  this->typemap.funcs.fit_to_result = pg_typemap_fit_to_result;
124
153
  this->typemap.funcs.fit_to_query = pg_tmbmt_fit_to_query;
125
154
  this->typemap.funcs.fit_to_copy_get = pg_typemap_fit_to_copy_get;
@@ -140,7 +169,7 @@ pg_tmbmt_s_allocate( VALUE klass )
140
169
  this->coders.coder_##type = NULL; \
141
170
  this->coders.ask_##type = Qnil; \
142
171
  }else if(rb_obj_is_kind_of(coder, rb_cPG_Coder)){ \
143
- Data_Get_Struct(coder, t_pg_coder, this->coders.coder_##type); \
172
+ TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, this->coders.coder_##type); \
144
173
  this->coders.ask_##type = Qnil; \
145
174
  }else if(RB_TYPE_P(coder, T_SYMBOL)){ \
146
175
  this->coders.coder_##type = NULL; \
@@ -188,7 +217,7 @@ pg_tmbmt_s_allocate( VALUE klass )
188
217
  static VALUE
189
218
  pg_tmbmt_aset( VALUE self, VALUE mri_type, VALUE coder )
190
219
  {
191
- t_tmbmt *this = DATA_PTR( self );
220
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
192
221
  char *p_mri_type;
193
222
 
194
223
  p_mri_type = StringValueCStr(mri_type);
@@ -220,7 +249,7 @@ static VALUE
220
249
  pg_tmbmt_aref( VALUE self, VALUE mri_type )
221
250
  {
222
251
  VALUE coder;
223
- t_tmbmt *this = DATA_PTR( self );
252
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
224
253
  char *p_mri_type;
225
254
 
226
255
  p_mri_type = StringValueCStr(mri_type);
@@ -248,7 +277,7 @@ pg_tmbmt_aref( VALUE self, VALUE mri_type )
248
277
  static VALUE
249
278
  pg_tmbmt_coders( VALUE self )
250
279
  {
251
- t_tmbmt *this = DATA_PTR( self );
280
+ t_tmbmt *this = RTYPEDDATA_DATA( self );
252
281
  VALUE hash_coders = rb_hash_new();
253
282
 
254
283
  FOR_EACH_MRI_TYPE( ADD_TO_HASH );
@@ -257,7 +286,7 @@ pg_tmbmt_coders( VALUE self )
257
286
  }
258
287
 
259
288
  void
260
- init_pg_type_map_by_mri_type()
289
+ init_pg_type_map_by_mri_type(void)
261
290
  {
262
291
  /*
263
292
  * Document-class: PG::TypeMapByMriType < PG::TypeMap
@@ -46,7 +46,7 @@ pg_tmbo_lookup_oid(t_tmbo *this, int format, Oid oid)
46
46
  } else {
47
47
  VALUE obj = rb_hash_lookup( this->format[format].oid_to_coder, UINT2NUM( oid ));
48
48
  /* obj must be nil or some kind of PG::Coder, this is checked at insertion */
49
- conv = NIL_P(obj) ? NULL : DATA_PTR(obj);
49
+ conv = NIL_P(obj) ? NULL : RTYPEDDATA_DATA(obj);
50
50
  /* Write the retrieved coder to the cache */
51
51
  p_ce->oid = oid;
52
52
  p_ce->p_coder = conv;
@@ -70,7 +70,7 @@ pg_tmbo_build_type_map_for_result2( t_tmbo *this, PGresult *pgresult )
70
70
  p_colmap->typemap.default_typemap = pg_typemap_all_strings;
71
71
 
72
72
  colmap = pg_tmbc_allocate();
73
- DATA_PTR(colmap) = p_colmap;
73
+ RTYPEDDATA_DATA(colmap) = p_colmap;
74
74
 
75
75
  for(i=0; i<nfields; i++)
76
76
  {
@@ -113,18 +113,18 @@ pg_tmbo_result_value(t_typemap *p_typemap, VALUE result, int tuple, int field)
113
113
  return dec_func( p_coder, val, len, tuple, field, p_result->enc_idx );
114
114
  }
115
115
 
116
- default_tm = DATA_PTR( this->typemap.default_typemap );
116
+ default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
117
117
  return default_tm->funcs.typecast_result_value( default_tm, result, tuple, field );
118
118
  }
119
119
 
120
120
  static VALUE
121
121
  pg_tmbo_fit_to_result( VALUE self, VALUE result )
122
122
  {
123
- t_tmbo *this = DATA_PTR( self );
123
+ t_tmbo *this = RTYPEDDATA_DATA( self );
124
124
  PGresult *pgresult = pgresult_get( result );
125
125
 
126
- /* Ensure that the default type map fits equaly. */
127
- t_typemap *default_tm = DATA_PTR( this->typemap.default_typemap );
126
+ /* Ensure that the default type map fits equally. */
127
+ t_typemap *default_tm = RTYPEDDATA_DATA( this->typemap.default_typemap );
128
128
  VALUE sub_typemap = default_tm->funcs.fit_to_result( this->typemap.default_typemap, result );
129
129
 
130
130
  if( PQntuples( pgresult ) <= this->max_rows_for_online_lookup ){
@@ -137,7 +137,7 @@ pg_tmbo_fit_to_result( VALUE self, VALUE result )
137
137
  /* The default type map built a new object, so we need to propagate it
138
138
  * and build a copy of this type map. */
139
139
  VALUE new_typemap = pg_tmbo_s_allocate( rb_cTypeMapByOid );
140
- t_tmbo *p_new_typemap = DATA_PTR(new_typemap);
140
+ t_tmbo *p_new_typemap = RTYPEDDATA_DATA(new_typemap);
141
141
  *p_new_typemap = *this;
142
142
  p_new_typemap->typemap.default_typemap = sub_typemap;
143
143
  return new_typemap;
@@ -147,23 +147,56 @@ pg_tmbo_fit_to_result( VALUE self, VALUE result )
147
147
  * uses a fast array lookup.
148
148
  */
149
149
  VALUE new_typemap = pg_tmbo_build_type_map_for_result2( this, pgresult );
150
- t_tmbo *p_new_typemap = DATA_PTR(new_typemap);
150
+ t_tmbo *p_new_typemap = RTYPEDDATA_DATA(new_typemap);
151
151
  p_new_typemap->typemap.default_typemap = sub_typemap;
152
152
  return new_typemap;
153
153
  }
154
154
  }
155
155
 
156
156
  static void
157
- pg_tmbo_mark( t_tmbo *this )
157
+ pg_tmbo_mark( void *_this )
158
158
  {
159
+ t_tmbo *this = (t_tmbo *)_this;
159
160
  int i;
160
161
 
161
- rb_gc_mark(this->typemap.default_typemap);
162
+ pg_typemap_mark(&this->typemap);
162
163
  for( i=0; i<2; i++){
163
- rb_gc_mark(this->format[i].oid_to_coder);
164
+ rb_gc_mark_movable(this->format[i].oid_to_coder);
164
165
  }
165
166
  }
166
167
 
168
+ static size_t
169
+ pg_tmbo_memsize( const void *_this )
170
+ {
171
+ const t_tmbo *this = (const t_tmbo *)_this;
172
+ return sizeof(*this);
173
+ }
174
+
175
+ static void
176
+ pg_tmbo_compact( void *_this )
177
+ {
178
+ t_tmbo *this = (t_tmbo *)_this;
179
+ int i;
180
+
181
+ pg_typemap_compact(&this->typemap);
182
+ for( i=0; i<2; i++){
183
+ pg_gc_location(this->format[i].oid_to_coder);
184
+ }
185
+ }
186
+
187
+ static const rb_data_type_t pg_tmbo_type = {
188
+ "PG::TypeMapByOid",
189
+ {
190
+ pg_tmbo_mark,
191
+ RUBY_TYPED_DEFAULT_FREE,
192
+ pg_tmbo_memsize,
193
+ pg_tmbo_compact,
194
+ },
195
+ &pg_typemap_type,
196
+ 0,
197
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
198
+ };
199
+
167
200
  static VALUE
168
201
  pg_tmbo_s_allocate( VALUE klass )
169
202
  {
@@ -171,7 +204,7 @@ pg_tmbo_s_allocate( VALUE klass )
171
204
  VALUE self;
172
205
  int i;
173
206
 
174
- self = Data_Make_Struct( klass, t_tmbo, pg_tmbo_mark, -1, this );
207
+ self = TypedData_Make_Struct( klass, t_tmbo, &pg_tmbo_type, this );
175
208
 
176
209
  this->typemap.funcs.fit_to_result = pg_tmbo_fit_to_result;
177
210
  this->typemap.funcs.fit_to_query = pg_typemap_fit_to_query;
@@ -179,11 +212,11 @@ pg_tmbo_s_allocate( VALUE klass )
179
212
  this->typemap.funcs.typecast_result_value = pg_tmbo_result_value;
180
213
  this->typemap.funcs.typecast_query_param = pg_typemap_typecast_query_param;
181
214
  this->typemap.funcs.typecast_copy_get = pg_typemap_typecast_copy_get;
182
- this->typemap.default_typemap = pg_typemap_all_strings;
215
+ RB_OBJ_WRITE(self, &this->typemap.default_typemap, pg_typemap_all_strings);
183
216
  this->max_rows_for_online_lookup = 10;
184
217
 
185
218
  for( i=0; i<2; i++){
186
- this->format[i].oid_to_coder = rb_hash_new();
219
+ RB_OBJ_WRITE(self, &this->format[i].oid_to_coder, rb_hash_new());
187
220
  }
188
221
 
189
222
  return self;
@@ -205,15 +238,12 @@ static VALUE
205
238
  pg_tmbo_add_coder( VALUE self, VALUE coder )
206
239
  {
207
240
  VALUE hash;
208
- t_tmbo *this = DATA_PTR( self );
241
+ t_tmbo *this = RTYPEDDATA_DATA( self );
209
242
  t_pg_coder *p_coder;
210
243
  struct pg_tmbo_oid_cache_entry *p_ce;
211
244
 
212
- if( !rb_obj_is_kind_of(coder, rb_cPG_Coder) )
213
- rb_raise(rb_eArgError, "invalid type %s (should be some kind of PG::Coder)",
214
- rb_obj_classname( coder ));
215
-
216
- Data_Get_Struct(coder, t_pg_coder, p_coder);
245
+ rb_check_frozen(self);
246
+ TypedData_Get_Struct(coder, t_pg_coder, &pg_coder_type, p_coder);
217
247
 
218
248
  if( p_coder->format < 0 || p_coder->format > 1 )
219
249
  rb_raise(rb_eArgError, "invalid format code %d", p_coder->format);
@@ -243,10 +273,11 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
243
273
  {
244
274
  VALUE hash;
245
275
  VALUE coder;
246
- t_tmbo *this = DATA_PTR( self );
276
+ t_tmbo *this = RTYPEDDATA_DATA( self );
247
277
  int i_format = NUM2INT(format);
248
278
  struct pg_tmbo_oid_cache_entry *p_ce;
249
279
 
280
+ rb_check_frozen(self);
250
281
  if( i_format < 0 || i_format > 1 )
251
282
  rb_raise(rb_eArgError, "invalid format code %d", i_format);
252
283
 
@@ -269,7 +300,7 @@ pg_tmbo_rm_coder( VALUE self, VALUE format, VALUE oid )
269
300
  static VALUE
270
301
  pg_tmbo_coders( VALUE self )
271
302
  {
272
- t_tmbo *this = DATA_PTR( self );
303
+ t_tmbo *this = RTYPEDDATA_DATA( self );
273
304
 
274
305
  return rb_ary_concat(
275
306
  rb_funcall(this->format[0].oid_to_coder, rb_intern("values"), 0),
@@ -284,11 +315,14 @@ pg_tmbo_coders( VALUE self )
284
315
  * The type map will do Hash lookups for each result value, if the number of rows
285
316
  * is below or equal +number+.
286
317
  *
318
+ * Default is 10.
319
+ *
287
320
  */
288
321
  static VALUE
289
322
  pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
290
323
  {
291
- t_tmbo *this = DATA_PTR( self );
324
+ t_tmbo *this = RTYPEDDATA_DATA( self );
325
+ rb_check_frozen(self);
292
326
  this->max_rows_for_online_lookup = NUM2INT(value);
293
327
  return value;
294
328
  }
@@ -300,7 +334,7 @@ pg_tmbo_max_rows_for_online_lookup_set( VALUE self, VALUE value )
300
334
  static VALUE
301
335
  pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
302
336
  {
303
- t_tmbo *this = DATA_PTR( self );
337
+ t_tmbo *this = RTYPEDDATA_DATA( self );
304
338
  return INT2NUM(this->max_rows_for_online_lookup);
305
339
  }
306
340
 
@@ -309,13 +343,13 @@ pg_tmbo_max_rows_for_online_lookup_get( VALUE self )
309
343
  * typemap.build_column_map( result )
310
344
  *
311
345
  * This builds a PG::TypeMapByColumn that fits to the given PG::Result object
312
- * based on it's type OIDs.
346
+ * based on it's type OIDs and binary/text format.
313
347
  *
314
348
  */
315
349
  static VALUE
316
350
  pg_tmbo_build_column_map( VALUE self, VALUE result )
317
351
  {
318
- t_tmbo *this = DATA_PTR( self );
352
+ t_tmbo *this = RTYPEDDATA_DATA( self );
319
353
 
320
354
  if ( !rb_obj_is_kind_of(result, rb_cPGresult) ) {
321
355
  rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::Result)",
@@ -327,7 +361,7 @@ pg_tmbo_build_column_map( VALUE self, VALUE result )
327
361
 
328
362
 
329
363
  void
330
- init_pg_type_map_by_oid()
364
+ init_pg_type_map_by_oid(void)
331
365
  {
332
366
  s_id_decode = rb_intern("decode");
333
367