pg 1.1.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  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 +141 -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/Gemfile +14 -0
  15. data/History.md +884 -0
  16. data/Manifest.txt +3 -3
  17. data/README-Windows.rdoc +4 -4
  18. data/README.ja.md +300 -0
  19. data/README.md +286 -0
  20. data/Rakefile +37 -137
  21. data/Rakefile.cross +62 -62
  22. data/certs/ged.pem +24 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/certs/larskanis-2023.pem +24 -0
  25. data/ext/errorcodes.def +80 -0
  26. data/ext/errorcodes.rb +0 -0
  27. data/ext/errorcodes.txt +22 -2
  28. data/ext/extconf.rb +105 -26
  29. data/ext/gvl_wrappers.c +4 -0
  30. data/ext/gvl_wrappers.h +23 -0
  31. data/ext/pg.c +204 -152
  32. data/ext/pg.h +52 -21
  33. data/ext/pg_binary_decoder.c +100 -17
  34. data/ext/pg_binary_encoder.c +238 -13
  35. data/ext/pg_coder.c +109 -34
  36. data/ext/pg_connection.c +1383 -983
  37. data/ext/pg_copy_coder.c +356 -35
  38. data/ext/pg_errors.c +1 -1
  39. data/ext/pg_record_coder.c +522 -0
  40. data/ext/pg_result.c +439 -172
  41. data/ext/pg_text_decoder.c +42 -18
  42. data/ext/pg_text_encoder.c +201 -56
  43. data/ext/pg_tuple.c +97 -66
  44. data/ext/pg_type_map.c +45 -11
  45. data/ext/pg_type_map_all_strings.c +21 -7
  46. data/ext/pg_type_map_by_class.c +59 -27
  47. data/ext/pg_type_map_by_column.c +80 -37
  48. data/ext/pg_type_map_by_mri_type.c +49 -20
  49. data/ext/pg_type_map_by_oid.c +62 -29
  50. data/ext/pg_type_map_in_ruby.c +56 -22
  51. data/ext/{util.c → pg_util.c} +7 -7
  52. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  54. data/lib/pg/basic_type_map_for_results.rb +104 -0
  55. data/lib/pg/basic_type_registry.rb +299 -0
  56. data/lib/pg/binary_decoder/date.rb +9 -0
  57. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  58. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  59. data/lib/pg/coder.rb +35 -12
  60. data/lib/pg/connection.rb +744 -84
  61. data/lib/pg/exceptions.rb +15 -1
  62. data/lib/pg/result.rb +13 -1
  63. data/lib/pg/text_decoder/date.rb +18 -0
  64. data/lib/pg/text_decoder/inet.rb +9 -0
  65. data/lib/pg/text_decoder/json.rb +14 -0
  66. data/lib/pg/text_decoder/numeric.rb +9 -0
  67. data/lib/pg/text_decoder/timestamp.rb +30 -0
  68. data/lib/pg/text_encoder/date.rb +12 -0
  69. data/lib/pg/text_encoder/inet.rb +28 -0
  70. data/lib/pg/text_encoder/json.rb +14 -0
  71. data/lib/pg/text_encoder/numeric.rb +9 -0
  72. data/lib/pg/text_encoder/timestamp.rb +24 -0
  73. data/lib/pg/type_map_by_column.rb +2 -1
  74. data/lib/pg/version.rb +4 -0
  75. data/lib/pg.rb +94 -39
  76. data/misc/openssl-pg-segfault.rb +31 -0
  77. data/misc/postgres/History.txt +9 -0
  78. data/misc/postgres/Manifest.txt +5 -0
  79. data/misc/postgres/README.txt +21 -0
  80. data/misc/postgres/Rakefile +21 -0
  81. data/misc/postgres/lib/postgres.rb +16 -0
  82. data/misc/ruby-pg/History.txt +9 -0
  83. data/misc/ruby-pg/Manifest.txt +5 -0
  84. data/misc/ruby-pg/README.txt +21 -0
  85. data/misc/ruby-pg/Rakefile +21 -0
  86. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  87. data/pg.gemspec +34 -0
  88. data/rakelib/task_extension.rb +46 -0
  89. data/sample/array_insert.rb +20 -0
  90. data/sample/async_api.rb +102 -0
  91. data/sample/async_copyto.rb +39 -0
  92. data/sample/async_mixed.rb +56 -0
  93. data/sample/check_conn.rb +21 -0
  94. data/sample/copydata.rb +71 -0
  95. data/sample/copyfrom.rb +81 -0
  96. data/sample/copyto.rb +19 -0
  97. data/sample/cursor.rb +21 -0
  98. data/sample/disk_usage_report.rb +177 -0
  99. data/sample/issue-119.rb +94 -0
  100. data/sample/losample.rb +69 -0
  101. data/sample/minimal-testcase.rb +17 -0
  102. data/sample/notify_wait.rb +72 -0
  103. data/sample/pg_statistics.rb +285 -0
  104. data/sample/replication_monitor.rb +222 -0
  105. data/sample/test_binary_values.rb +33 -0
  106. data/sample/wal_shipper.rb +434 -0
  107. data/sample/warehouse_partitions.rb +311 -0
  108. data/translation/.po4a-version +7 -0
  109. data/translation/po/all.pot +936 -0
  110. data/translation/po/ja.po +1036 -0
  111. data/translation/po4a.cfg +12 -0
  112. data.tar.gz.sig +0 -0
  113. metadata +144 -222
  114. metadata.gz.sig +0 -0
  115. data/ChangeLog +0 -6595
  116. data/History.rdoc +0 -485
  117. data/README.ja.rdoc +0 -14
  118. data/README.rdoc +0 -178
  119. data/lib/pg/basic_type_mapping.rb +0 -459
  120. data/lib/pg/binary_decoder.rb +0 -22
  121. data/lib/pg/constants.rb +0 -11
  122. data/lib/pg/text_decoder.rb +0 -47
  123. data/lib/pg/text_encoder.rb +0 -69
  124. data/spec/data/expected_trace.out +0 -26
  125. data/spec/data/random_binary_data +0 -0
  126. data/spec/helpers.rb +0 -381
  127. data/spec/pg/basic_type_mapping_spec.rb +0 -508
  128. data/spec/pg/connection_spec.rb +0 -1849
  129. data/spec/pg/connection_sync_spec.rb +0 -41
  130. data/spec/pg/result_spec.rb +0 -491
  131. data/spec/pg/tuple_spec.rb +0 -280
  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 -949
  139. data/spec/pg_spec.rb +0 -50
  140. /data/ext/{util.h → pg_util.h} +0 -0
@@ -1,16 +1,19 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
- #include "util.h"
8
+ #include "pg_util.h"
9
9
  #ifdef HAVE_INTTYPES_H
10
10
  #include <inttypes.h>
11
11
  #endif
12
12
 
13
13
  VALUE rb_mPG_BinaryEncoder;
14
+ static ID s_id_year;
15
+ static ID s_id_month;
16
+ static ID s_id_day;
14
17
 
15
18
 
16
19
  /*
@@ -25,11 +28,12 @@ static int
25
28
  pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
26
29
  {
27
30
  char mybool;
28
- switch(value){
29
- case Qtrue : mybool = 1; break;
30
- case Qfalse : mybool = 0; break;
31
- default :
32
- rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
31
+ if (value == Qtrue) {
32
+ mybool = 1;
33
+ } else if (value == Qfalse) {
34
+ mybool = 0;
35
+ } else {
36
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
33
37
  }
34
38
  if(out) *out = mybool;
35
39
  return 1;
@@ -38,7 +42,7 @@ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
38
42
  /*
39
43
  * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
40
44
  *
41
- * This is the encoder class for the PostgreSQL int2 type.
45
+ * This is the encoder class for the PostgreSQL +int2+ (alias +smallint+) type.
42
46
  *
43
47
  * Non-Number values are expected to have method +to_i+ defined.
44
48
  *
@@ -55,9 +59,9 @@ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
55
59
  }
56
60
 
57
61
  /*
58
- * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
62
+ * Document-class: PG::BinaryEncoder::Int4 < PG::SimpleEncoder
59
63
  *
60
- * This is the encoder class for the PostgreSQL int4 type.
64
+ * This is the encoder class for the PostgreSQL +int4+ (alias +integer+) type.
61
65
  *
62
66
  * Non-Number values are expected to have method +to_i+ defined.
63
67
  *
@@ -74,9 +78,9 @@ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
74
78
  }
75
79
 
76
80
  /*
77
- * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
81
+ * Document-class: PG::BinaryEncoder::Int8 < PG::SimpleEncoder
78
82
  *
79
- * This is the encoder class for the PostgreSQL int8 type.
83
+ * This is the encoder class for the PostgreSQL +int8+ (alias +bigint+) type.
80
84
  *
81
85
  * Non-Number values are expected to have method +to_i+ defined.
82
86
  *
@@ -92,6 +96,215 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
92
96
  return 8;
93
97
  }
94
98
 
99
+ /*
100
+ * Document-class: PG::BinaryEncoder::Float4 < PG::SimpleEncoder
101
+ *
102
+ * This is the binary encoder class for the PostgreSQL +float4+ type.
103
+ *
104
+ */
105
+ static int
106
+ pg_bin_enc_float4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
107
+ {
108
+ union {
109
+ float f;
110
+ int32_t i;
111
+ } swap4;
112
+
113
+ if(out){
114
+ swap4.f = NUM2DBL(*intermediate);
115
+ write_nbo32(swap4.i, out);
116
+ }else{
117
+ *intermediate = value;
118
+ }
119
+ return 4;
120
+ }
121
+
122
+ /*
123
+ * Document-class: PG::BinaryEncoder::Float8 < PG::SimpleEncoder
124
+ *
125
+ * This is the binary encoder class for the PostgreSQL +float8+ type.
126
+ *
127
+ */
128
+ static int
129
+ pg_bin_enc_float8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
130
+ {
131
+ union {
132
+ double f;
133
+ int64_t i;
134
+ } swap8;
135
+
136
+ if(out){
137
+ swap8.f = NUM2DBL(*intermediate);
138
+ write_nbo64(swap8.i, out);
139
+ }else{
140
+ *intermediate = value;
141
+ }
142
+ return 8;
143
+ }
144
+
145
+ #define PG_INT32_MIN (-0x7FFFFFFF-1)
146
+ #define PG_INT32_MAX (0x7FFFFFFF)
147
+ #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
148
+ #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
149
+
150
+ /*
151
+ * Document-class: PG::BinaryEncoder::Timestamp < PG::SimpleEncoder
152
+ *
153
+ * This is a encoder class for conversion of Ruby Time objects to PostgreSQL binary timestamps.
154
+ *
155
+ * The following flags can be used to specify timezone interpretation:
156
+ * * +PG::Coder::TIMESTAMP_DB_UTC+ : Send timestamp as UTC time (default)
157
+ * * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Send timestamp as local time (slower)
158
+ *
159
+ * Example:
160
+ * enco = PG::BinaryEncoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC)
161
+ * enco.encode(Time.utc(2000, 1, 1)) # => "\x00\x00\x00\x00\x00\x00\x00\x00"
162
+ *
163
+ * String values are expected to contain a binary data with a length of 8 byte.
164
+ *
165
+ */
166
+ static int
167
+ pg_bin_enc_timestamp(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
168
+ {
169
+ if(out){
170
+ int64_t timestamp;
171
+ struct timespec ts;
172
+
173
+ /* second call -> write data to *out */
174
+ switch(TYPE(*intermediate)){
175
+ case T_STRING:
176
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
177
+ case T_TRUE:
178
+ write_nbo64(PG_INT64_MAX, out);
179
+ return 8;
180
+ case T_FALSE:
181
+ write_nbo64(PG_INT64_MIN, out);
182
+ return 8;
183
+ }
184
+
185
+ ts = rb_time_timespec(*intermediate);
186
+ /* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
187
+ * Adjust the 30 years difference. */
188
+ timestamp = (ts.tv_sec - 10957L * 24L * 3600L) * 1000000 + (ts.tv_nsec / 1000);
189
+
190
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
191
+ /* send as local time */
192
+ timestamp += NUM2LL(rb_funcall(*intermediate, rb_intern("utc_offset"), 0)) * 1000000;
193
+ }
194
+
195
+ write_nbo64(timestamp, out);
196
+ }else{
197
+ /* first call -> determine the required length */
198
+ if(TYPE(value) == T_STRING){
199
+ char *pstr = RSTRING_PTR(value);
200
+ if(RSTRING_LEN(value) >= 1){
201
+ switch(pstr[0]) {
202
+ case 'I':
203
+ case 'i':
204
+ *intermediate = Qtrue;
205
+ return 8;
206
+ case '-':
207
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
208
+ *intermediate = Qfalse;
209
+ return 8;
210
+ }
211
+ }
212
+ }
213
+
214
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
215
+ }
216
+
217
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
218
+ /* make a local time, so that utc_offset is set */
219
+ value = rb_funcall(value, rb_intern("getlocal"), 0);
220
+ }
221
+ *intermediate = value;
222
+ }
223
+ return 8;
224
+ }
225
+
226
+ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
227
+ int
228
+ date2j(int year, int month, int day)
229
+ {
230
+ int julian;
231
+ int century;
232
+
233
+ if (month > 2)
234
+ {
235
+ month += 1;
236
+ year += 4800;
237
+ }
238
+ else
239
+ {
240
+ month += 13;
241
+ year += 4799;
242
+ }
243
+
244
+ century = year / 100;
245
+ julian = year * 365 - 32167;
246
+ julian += year / 4 - century + century / 4;
247
+ julian += 7834 * month / 256 + day;
248
+
249
+ return julian;
250
+ } /* date2j() */
251
+
252
+ /*
253
+ * Document-class: PG::BinaryEncoder::Date < PG::SimpleEncoder
254
+ *
255
+ * This is a encoder class for conversion of Ruby Date objects to PostgreSQL binary date.
256
+ *
257
+ * String values are expected to contain a binary data with a length of 4 byte.
258
+ *
259
+ */
260
+ static int
261
+ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
262
+ {
263
+ if(out){
264
+ /* second call -> write data to *out */
265
+ switch(TYPE(*intermediate)){
266
+ case T_STRING:
267
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
268
+ case T_TRUE:
269
+ write_nbo32(PG_INT32_MAX, out);
270
+ return 4;
271
+ case T_FALSE:
272
+ write_nbo32(PG_INT32_MIN, out);
273
+ return 4;
274
+ }
275
+
276
+ VALUE year = rb_funcall(value, s_id_year, 0);
277
+ VALUE month = rb_funcall(value, s_id_month, 0);
278
+ VALUE day = rb_funcall(value, s_id_day, 0);
279
+ int jday = date2j(NUM2INT(year), NUM2INT(month), NUM2INT(day)) - POSTGRES_EPOCH_JDATE;
280
+ write_nbo32(jday, out);
281
+
282
+ }else{
283
+ /* first call -> determine the required length */
284
+ if(TYPE(value) == T_STRING){
285
+ char *pstr = RSTRING_PTR(value);
286
+ if(RSTRING_LEN(value) >= 1){
287
+ switch(pstr[0]) {
288
+ case 'I':
289
+ case 'i':
290
+ *intermediate = Qtrue;
291
+ return 4;
292
+ case '-':
293
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
294
+ *intermediate = Qfalse;
295
+ return 4;
296
+ }
297
+ }
298
+ }
299
+
300
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
301
+ }
302
+
303
+ *intermediate = value;
304
+ }
305
+ return 4;
306
+ }
307
+
95
308
  /*
96
309
  * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
97
310
  *
@@ -138,8 +351,12 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
138
351
  }
139
352
 
140
353
  void
141
- init_pg_binary_encoder()
354
+ init_pg_binary_encoder(void)
142
355
  {
356
+ s_id_year = rb_intern("year");
357
+ s_id_month = rb_intern("month");
358
+ s_id_day = rb_intern("day");
359
+
143
360
  /* This module encapsulates all encoder classes with binary output format */
144
361
  rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
145
362
 
@@ -152,10 +369,18 @@ init_pg_binary_encoder()
152
369
  pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
153
370
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
154
371
  pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
372
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float4", rb_cPG_SimpleEncoder ); */
373
+ pg_define_coder( "Float4", pg_bin_enc_float4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
374
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float8", rb_cPG_SimpleEncoder ); */
375
+ pg_define_coder( "Float8", pg_bin_enc_float8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
155
376
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
156
377
  pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
157
378
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
158
379
  pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
380
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Timestamp", rb_cPG_SimpleEncoder ); */
381
+ pg_define_coder( "Timestamp", pg_bin_enc_timestamp, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
382
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Date", rb_cPG_SimpleEncoder ); */
383
+ pg_define_coder( "Date", pg_bin_enc_date, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
159
384
 
160
385
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
161
386
  pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
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,36 +45,92 @@ 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
+
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
+
64
107
  static VALUE
65
108
  pg_simple_encoder_allocate( VALUE klass )
66
109
  {
67
110
  t_pg_coder *this;
68
- 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 );
69
112
  pg_coder_init_encoder( self );
70
113
  return self;
71
114
  }
72
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
+
73
129
  static VALUE
74
130
  pg_composite_encoder_allocate( VALUE klass )
75
131
  {
76
132
  t_pg_composite_coder *this;
77
- 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 );
78
134
  pg_coder_init_encoder( self );
79
135
  this->elem = NULL;
80
136
  this->needs_quotation = 1;
@@ -87,7 +143,7 @@ static VALUE
87
143
  pg_simple_decoder_allocate( VALUE klass )
88
144
  {
89
145
  t_pg_coder *this;
90
- 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 );
91
147
  pg_coder_init_decoder( self );
92
148
  return self;
93
149
  }
@@ -96,7 +152,7 @@ static VALUE
96
152
  pg_composite_decoder_allocate( VALUE klass )
97
153
  {
98
154
  t_pg_composite_coder *this;
99
- 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 );
100
156
  pg_coder_init_decoder( self );
101
157
  this->elem = NULL;
102
158
  this->needs_quotation = 1;
@@ -123,7 +179,7 @@ pg_coder_encode(int argc, VALUE *argv, VALUE self)
123
179
  VALUE value;
124
180
  int len, len2;
125
181
  int enc_idx;
126
- t_pg_coder *this = DATA_PTR(self);
182
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
127
183
 
128
184
  if(argc < 1 || argc > 2){
129
185
  rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc);
@@ -145,7 +201,6 @@ pg_coder_encode(int argc, VALUE *argv, VALUE self)
145
201
 
146
202
  if( len == -1 ){
147
203
  /* The intermediate value is a String that can be used directly. */
148
- OBJ_INFECT(intermediate, value);
149
204
  return intermediate;
150
205
  }
151
206
 
@@ -157,7 +212,6 @@ pg_coder_encode(int argc, VALUE *argv, VALUE self)
157
212
  rb_obj_classname( self ), len, len2 );
158
213
  }
159
214
  rb_str_set_len( res, len2 );
160
- OBJ_INFECT(res, value);
161
215
 
162
216
  RB_GC_GUARD(intermediate);
163
217
 
@@ -182,7 +236,7 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
182
236
  int tuple = -1;
183
237
  int field = -1;
184
238
  VALUE res;
185
- t_pg_coder *this = DATA_PTR(self);
239
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
186
240
 
187
241
  if(argc < 1 || argc > 3){
188
242
  rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..3)", argc);
@@ -203,8 +257,7 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
203
257
  rb_raise(rb_eRuntimeError, "no decoder function defined");
204
258
  }
205
259
 
206
- res = this->dec_func(this, val, RSTRING_LEN(argv[0]), tuple, field, ENCODING_GET(argv[0]));
207
- OBJ_INFECT(res, argv[0]);
260
+ res = this->dec_func(this, val, RSTRING_LENINT(argv[0]), tuple, field, ENCODING_GET(argv[0]));
208
261
 
209
262
  return res;
210
263
  }
@@ -221,7 +274,8 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
221
274
  static VALUE
222
275
  pg_coder_oid_set(VALUE self, VALUE oid)
223
276
  {
224
- t_pg_coder *this = DATA_PTR(self);
277
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
278
+ rb_check_frozen(self);
225
279
  this->oid = NUM2UINT(oid);
226
280
  return oid;
227
281
  }
@@ -236,7 +290,7 @@ pg_coder_oid_set(VALUE self, VALUE oid)
236
290
  static VALUE
237
291
  pg_coder_oid_get(VALUE self)
238
292
  {
239
- t_pg_coder *this = DATA_PTR(self);
293
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
240
294
  return UINT2NUM(this->oid);
241
295
  }
242
296
 
@@ -252,7 +306,8 @@ pg_coder_oid_get(VALUE self)
252
306
  static VALUE
253
307
  pg_coder_format_set(VALUE self, VALUE format)
254
308
  {
255
- t_pg_coder *this = DATA_PTR(self);
309
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
310
+ rb_check_frozen(self);
256
311
  this->format = NUM2INT(format);
257
312
  return format;
258
313
  }
@@ -267,7 +322,7 @@ pg_coder_format_set(VALUE self, VALUE format)
267
322
  static VALUE
268
323
  pg_coder_format_get(VALUE self)
269
324
  {
270
- t_pg_coder *this = DATA_PTR(self);
325
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
271
326
  return INT2NUM(this->format);
272
327
  }
273
328
 
@@ -283,7 +338,8 @@ pg_coder_format_get(VALUE self)
283
338
  static VALUE
284
339
  pg_coder_flags_set(VALUE self, VALUE flags)
285
340
  {
286
- t_pg_coder *this = DATA_PTR(self);
341
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
342
+ rb_check_frozen(self);
287
343
  this->flags = NUM2INT(flags);
288
344
  return flags;
289
345
  }
@@ -297,7 +353,7 @@ pg_coder_flags_set(VALUE self, VALUE flags)
297
353
  static VALUE
298
354
  pg_coder_flags_get(VALUE self)
299
355
  {
300
- t_pg_coder *this = DATA_PTR(self);
356
+ t_pg_coder *this = RTYPEDDATA_DATA(self);
301
357
  return INT2NUM(this->flags);
302
358
  }
303
359
 
@@ -314,7 +370,8 @@ pg_coder_flags_get(VALUE self)
314
370
  static VALUE
315
371
  pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
316
372
  {
317
- t_pg_composite_coder *this = DATA_PTR(self);
373
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
374
+ rb_check_frozen(self);
318
375
  this->needs_quotation = RTEST(needs_quotation);
319
376
  return needs_quotation;
320
377
  }
@@ -329,7 +386,7 @@ pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
329
386
  static VALUE
330
387
  pg_coder_needs_quotation_get(VALUE self)
331
388
  {
332
- t_pg_composite_coder *this = DATA_PTR(self);
389
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
333
390
  return this->needs_quotation ? Qtrue : Qfalse;
334
391
  }
335
392
 
@@ -344,7 +401,8 @@ pg_coder_needs_quotation_get(VALUE self)
344
401
  static VALUE
345
402
  pg_coder_delimiter_set(VALUE self, VALUE delimiter)
346
403
  {
347
- t_pg_composite_coder *this = DATA_PTR(self);
404
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
405
+ rb_check_frozen(self);
348
406
  StringValue(delimiter);
349
407
  if(RSTRING_LEN(delimiter) != 1)
350
408
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -361,7 +419,7 @@ pg_coder_delimiter_set(VALUE self, VALUE delimiter)
361
419
  static VALUE
362
420
  pg_coder_delimiter_get(VALUE self)
363
421
  {
364
- t_pg_composite_coder *this = DATA_PTR(self);
422
+ t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
365
423
  return rb_str_new(&this->delimiter, 1);
366
424
  }
367
425
 
@@ -377,12 +435,13 @@ pg_coder_delimiter_get(VALUE self)
377
435
  static VALUE
378
436
  pg_coder_elements_type_set(VALUE self, VALUE elem_type)
379
437
  {
380
- t_pg_composite_coder *this = DATA_PTR( self );
438
+ t_pg_composite_coder *this = RTYPEDDATA_DATA( self );
381
439
 
440
+ rb_check_frozen(self);
382
441
  if ( NIL_P(elem_type) ){
383
442
  this->elem = NULL;
384
443
  } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
385
- this->elem = DATA_PTR( elem_type );
444
+ this->elem = RTYPEDDATA_DATA( elem_type );
386
445
  } else {
387
446
  rb_raise( rb_eTypeError, "wrong elements type %s (expected some kind of PG::Coder)",
388
447
  rb_obj_classname( elem_type ) );
@@ -392,17 +451,35 @@ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
392
451
  return elem_type;
393
452
  }
394
453
 
395
- 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
396
467
  pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
397
468
  {
398
- 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 );
399
470
  VALUE coder_klass = rb_define_class_under( nsp, name, base_klass );
400
471
  if( nsp==rb_mPG_BinaryEncoder || nsp==rb_mPG_BinaryDecoder )
401
472
  rb_include_module( coder_klass, rb_mPG_BinaryFormatting );
402
473
 
403
- 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) );
404
480
 
405
481
  RB_GC_GUARD(cfunc_obj);
482
+ return coder_klass;
406
483
  }
407
484
 
408
485
 
@@ -469,7 +546,7 @@ pg_coder_dec_func(t_pg_coder *this, int binary)
469
546
 
470
547
 
471
548
  void
472
- init_pg_coder()
549
+ init_pg_coder(void)
473
550
  {
474
551
  s_id_encode = rb_intern("encode");
475
552
  s_id_decode = rb_intern("decode");
@@ -512,8 +589,6 @@ init_pg_coder()
512
589
  * This accessor is only used in PG::Coder#inspect .
513
590
  */
514
591
  rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
515
- rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, -1 );
516
- rb_define_method( rb_cPG_Coder, "decode", pg_coder_decode, -1 );
517
592
 
518
593
  /* Document-class: PG::SimpleCoder < PG::Coder */
519
594
  rb_cPG_SimpleCoder = rb_define_class_under( rb_mPG, "SimpleCoder", rb_cPG_Coder );