pg 1.1.3 → 1.5.4

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 (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 );