pg 1.4.6 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +1 -1
  4. data/.gitignore +3 -0
  5. data/History.md +55 -0
  6. data/README.ja.md +29 -19
  7. data/README.md +29 -15
  8. data/Rakefile.cross +1 -1
  9. data/ext/pg.c +10 -28
  10. data/ext/pg.h +10 -5
  11. data/ext/pg_binary_decoder.c +79 -0
  12. data/ext/pg_binary_encoder.c +224 -0
  13. data/ext/pg_coder.c +16 -7
  14. data/ext/pg_connection.c +50 -34
  15. data/ext/pg_copy_coder.c +306 -17
  16. data/ext/pg_record_coder.c +5 -4
  17. data/ext/pg_result.c +88 -17
  18. data/ext/pg_text_decoder.c +28 -10
  19. data/ext/pg_text_encoder.c +22 -9
  20. data/ext/pg_tuple.c +34 -31
  21. data/ext/pg_type_map.c +3 -2
  22. data/ext/pg_type_map_all_strings.c +2 -2
  23. data/ext/pg_type_map_by_class.c +5 -3
  24. data/ext/pg_type_map_by_column.c +9 -3
  25. data/ext/pg_type_map_by_oid.c +7 -4
  26. data/ext/pg_type_map_in_ruby.c +5 -2
  27. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  28. data/lib/pg/basic_type_map_for_queries.rb +13 -8
  29. data/lib/pg/basic_type_map_for_results.rb +26 -3
  30. data/lib/pg/basic_type_registry.rb +30 -32
  31. data/lib/pg/binary_decoder/date.rb +9 -0
  32. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  33. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  34. data/lib/pg/coder.rb +15 -13
  35. data/lib/pg/connection.rb +63 -12
  36. data/lib/pg/text_decoder/date.rb +18 -0
  37. data/lib/pg/text_decoder/inet.rb +9 -0
  38. data/lib/pg/text_decoder/json.rb +14 -0
  39. data/lib/pg/text_decoder/numeric.rb +9 -0
  40. data/lib/pg/text_decoder/timestamp.rb +30 -0
  41. data/lib/pg/text_encoder/date.rb +12 -0
  42. data/lib/pg/text_encoder/inet.rb +28 -0
  43. data/lib/pg/text_encoder/json.rb +14 -0
  44. data/lib/pg/text_encoder/numeric.rb +9 -0
  45. data/lib/pg/text_encoder/timestamp.rb +24 -0
  46. data/lib/pg/version.rb +1 -1
  47. data/lib/pg.rb +44 -9
  48. data/pg.gemspec +1 -1
  49. data/translation/po/all.pot +170 -135
  50. data/translation/po/ja.po +365 -186
  51. data/translation/po4a.cfg +4 -1
  52. data.tar.gz.sig +0 -0
  53. metadata +28 -10
  54. metadata.gz.sig +0 -0
  55. data/lib/pg/binary_decoder.rb +0 -23
  56. data/lib/pg/constants.rb +0 -12
  57. data/lib/pg/text_decoder.rb +0 -46
  58. data/lib/pg/text_encoder.rb +0 -59
@@ -11,6 +11,9 @@
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
  /*
@@ -93,6 +96,215 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
93
96
  return 8;
94
97
  }
95
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
+
96
308
  /*
97
309
  * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
98
310
  *
@@ -141,6 +353,10 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
141
353
  void
142
354
  init_pg_binary_encoder(void)
143
355
  {
356
+ s_id_year = rb_intern("year");
357
+ s_id_month = rb_intern("month");
358
+ s_id_day = rb_intern("day");
359
+
144
360
  /* This module encapsulates all encoder classes with binary output format */
145
361
  rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
146
362
 
@@ -153,10 +369,18 @@ init_pg_binary_encoder(void)
153
369
  pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
154
370
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
155
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 );
156
376
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
157
377
  pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
158
378
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
159
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 );
160
384
 
161
385
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
162
386
  pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
data/ext/pg_coder.c CHANGED
@@ -35,7 +35,7 @@ pg_coder_init_encoder( VALUE self )
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;
@@ -54,7 +54,7 @@ pg_coder_init_decoder( VALUE self )
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;
@@ -99,7 +99,9 @@ const rb_data_type_t pg_coder_type = {
99
99
  },
100
100
  0,
101
101
  0,
102
- RUBY_TYPED_FREE_IMMEDIATELY,
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,
103
105
  };
104
106
 
105
107
  static VALUE
@@ -121,7 +123,7 @@ static const rb_data_type_t pg_composite_coder_type = {
121
123
  },
122
124
  &pg_coder_type,
123
125
  0,
124
- RUBY_TYPED_FREE_IMMEDIATELY,
126
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
125
127
  };
126
128
 
127
129
  static VALUE
@@ -273,6 +275,7 @@ static VALUE
273
275
  pg_coder_oid_set(VALUE self, VALUE oid)
274
276
  {
275
277
  t_pg_coder *this = RTYPEDDATA_DATA(self);
278
+ rb_check_frozen(self);
276
279
  this->oid = NUM2UINT(oid);
277
280
  return oid;
278
281
  }
@@ -304,6 +307,7 @@ static VALUE
304
307
  pg_coder_format_set(VALUE self, VALUE format)
305
308
  {
306
309
  t_pg_coder *this = RTYPEDDATA_DATA(self);
310
+ rb_check_frozen(self);
307
311
  this->format = NUM2INT(format);
308
312
  return format;
309
313
  }
@@ -335,6 +339,7 @@ static VALUE
335
339
  pg_coder_flags_set(VALUE self, VALUE flags)
336
340
  {
337
341
  t_pg_coder *this = RTYPEDDATA_DATA(self);
342
+ rb_check_frozen(self);
338
343
  this->flags = NUM2INT(flags);
339
344
  return flags;
340
345
  }
@@ -366,6 +371,7 @@ static VALUE
366
371
  pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
367
372
  {
368
373
  t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
374
+ rb_check_frozen(self);
369
375
  this->needs_quotation = RTEST(needs_quotation);
370
376
  return needs_quotation;
371
377
  }
@@ -396,6 +402,7 @@ static VALUE
396
402
  pg_coder_delimiter_set(VALUE self, VALUE delimiter)
397
403
  {
398
404
  t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
405
+ rb_check_frozen(self);
399
406
  StringValue(delimiter);
400
407
  if(RSTRING_LEN(delimiter) != 1)
401
408
  rb_raise( rb_eArgError, "delimiter size must be one byte");
@@ -430,6 +437,7 @@ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
430
437
  {
431
438
  t_pg_composite_coder *this = RTYPEDDATA_DATA( self );
432
439
 
440
+ rb_check_frozen(self);
433
441
  if ( NIL_P(elem_type) ){
434
442
  this->elem = NULL;
435
443
  } else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
@@ -452,10 +460,10 @@ static const rb_data_type_t pg_coder_cfunc_type = {
452
460
  },
453
461
  0,
454
462
  0,
455
- RUBY_TYPED_FREE_IMMEDIATELY,
463
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
456
464
  };
457
465
 
458
- void
466
+ VALUE
459
467
  pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
460
468
  {
461
469
  VALUE cfunc_obj = TypedData_Wrap_Struct( rb_cObject, &pg_coder_cfunc_type, func );
@@ -468,9 +476,10 @@ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
468
476
  if( nsp==rb_mPG_BinaryDecoder || nsp==rb_mPG_TextDecoder )
469
477
  rb_define_method( coder_klass, "decode", pg_coder_decode, -1 );
470
478
 
471
- rb_define_const( coder_klass, "CFUNC", cfunc_obj );
479
+ rb_define_const( coder_klass, "CFUNC", rb_obj_freeze(cfunc_obj) );
472
480
 
473
481
  RB_GC_GUARD(cfunc_obj);
482
+ return coder_klass;
474
483
  }
475
484
 
476
485
 
data/ext/pg_connection.c CHANGED
@@ -16,9 +16,6 @@ static ID s_id_autoclose_set;
16
16
  static VALUE sym_type, sym_format, sym_value;
17
17
  static VALUE sym_symbol, sym_string, sym_static_symbol;
18
18
 
19
- static PQnoticeReceiver default_notice_receiver = NULL;
20
- static PQnoticeProcessor default_notice_processor = NULL;
21
-
22
19
  static VALUE pgconn_finish( VALUE );
23
20
  static VALUE pgconn_set_default_encoding( VALUE self );
24
21
  static VALUE pgconn_wait_for_flush( VALUE self );
@@ -117,7 +114,7 @@ pgconn_close_socket_io( VALUE self )
117
114
  rb_funcall( socket_io, rb_intern("close"), 0 );
118
115
  }
119
116
 
120
- this->socket_io = Qnil;
117
+ RB_OBJ_WRITE(self, &this->socket_io, Qnil);
121
118
  }
122
119
 
123
120
 
@@ -237,7 +234,7 @@ static const rb_data_type_t pg_connection_type = {
237
234
  },
238
235
  0,
239
236
  0,
240
- 0,
237
+ RUBY_TYPED_WB_PROTECTED,
241
238
  };
242
239
 
243
240
 
@@ -258,14 +255,14 @@ pgconn_s_allocate( VALUE klass )
258
255
  VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
259
256
 
260
257
  this->pgconn = NULL;
261
- this->socket_io = Qnil;
262
- this->notice_receiver = Qnil;
263
- this->notice_processor = Qnil;
264
- this->type_map_for_queries = pg_typemap_all_strings;
265
- this->type_map_for_results = pg_typemap_all_strings;
266
- this->encoder_for_put_copy_data = Qnil;
267
- this->decoder_for_get_copy_data = Qnil;
268
- this->trace_stream = Qnil;
258
+ RB_OBJ_WRITE(self, &this->socket_io, Qnil);
259
+ RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
260
+ RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
261
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
262
+ RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
263
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
264
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
265
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
269
266
  rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
270
267
 
271
268
  return self;
@@ -766,6 +763,10 @@ pgconn_conninfo( VALUE self )
766
763
  *
767
764
  * ... and other constants of kind PG::Constants::CONNECTION_*
768
765
  *
766
+ * This method returns the status of the last command from memory.
767
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
768
+ * See check_socket for a way to verify the socket state.
769
+ *
769
770
  * Example:
770
771
  * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
771
772
  */
@@ -941,7 +942,7 @@ pgconn_socket_io(VALUE self)
941
942
  /* Disable autoclose feature */
942
943
  rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
943
944
 
944
- this->socket_io = socket_io;
945
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
945
946
  }
946
947
 
947
948
  return socket_io;
@@ -1158,7 +1159,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
1158
1159
  },
1159
1160
  0,
1160
1161
  0,
1161
- RUBY_TYPED_FREE_IMMEDIATELY,
1162
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1162
1163
  };
1163
1164
 
1164
1165
  static char *
@@ -1191,7 +1192,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
1191
1192
  },
1192
1193
  0,
1193
1194
  0,
1194
- RUBY_TYPED_FREE_IMMEDIATELY,
1195
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1195
1196
  };
1196
1197
 
1197
1198
  static int
@@ -1814,6 +1815,7 @@ pgconn_set_single_row_mode(VALUE self)
1814
1815
  {
1815
1816
  PGconn *conn = pg_get_pgconn(self);
1816
1817
 
1818
+ rb_check_frozen(self);
1817
1819
  if( PQsetSingleRowMode(conn) == 0 )
1818
1820
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1819
1821
 
@@ -2148,6 +2150,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2148
2150
  {
2149
2151
  int arg;
2150
2152
  PGconn *conn = pg_get_pgconn(self);
2153
+ rb_check_frozen(self);
2151
2154
  if(state == Qtrue)
2152
2155
  arg = 1;
2153
2156
  else if (state == Qfalse)
@@ -2464,6 +2467,7 @@ pgconn_wait_for_flush( VALUE self ){
2464
2467
  static VALUE
2465
2468
  pgconn_flush_data_set( VALUE self, VALUE enabled ){
2466
2469
  t_pg_connection *conn = pg_get_connection(self);
2470
+ rb_check_frozen(self);
2467
2471
  conn->flush_data = RTEST(enabled);
2468
2472
  return enabled;
2469
2473
  }
@@ -2718,6 +2722,7 @@ pgconn_trace(VALUE self, VALUE stream)
2718
2722
  VALUE new_file;
2719
2723
  t_pg_connection *this = pg_get_connection_safe( self );
2720
2724
 
2725
+ rb_check_frozen(self);
2721
2726
  if(!rb_respond_to(stream,rb_intern("fileno")))
2722
2727
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2723
2728
 
@@ -2739,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
2739
2744
  rb_raise(rb_eArgError, "stream is not writable");
2740
2745
 
2741
2746
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2742
- this->trace_stream = new_file;
2747
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2743
2748
 
2744
2749
  PQtrace(this->pgconn, new_fp);
2745
2750
  return Qnil;
@@ -2758,7 +2763,7 @@ pgconn_untrace(VALUE self)
2758
2763
 
2759
2764
  PQuntrace(this->pgconn);
2760
2765
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2761
- this->trace_stream = Qnil;
2766
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2762
2767
  return Qnil;
2763
2768
  }
2764
2769
 
@@ -2817,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
2817
2822
  VALUE proc, old_proc;
2818
2823
  t_pg_connection *this = pg_get_connection_safe( self );
2819
2824
 
2825
+ rb_check_frozen(self);
2820
2826
  /* If default_notice_receiver is unset, assume that the current
2821
2827
  * notice receiver is the default, and save it to a global variable.
2822
2828
  * This should not be a problem because the default receiver is
2823
2829
  * always the same, so won't vary among connections.
2824
2830
  */
2825
- if(default_notice_receiver == NULL)
2826
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2831
+ if(this->default_notice_receiver == NULL)
2832
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2827
2833
 
2828
2834
  old_proc = this->notice_receiver;
2829
2835
  if( rb_block_given_p() ) {
@@ -2832,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
2832
2838
  } else {
2833
2839
  /* if no block is given, set back to default */
2834
2840
  proc = Qnil;
2835
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2841
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2836
2842
  }
2837
2843
 
2838
- this->notice_receiver = proc;
2844
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2839
2845
  return old_proc;
2840
2846
  }
2841
2847
 
@@ -2850,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
2850
2856
  VALUE self = (VALUE)arg;
2851
2857
  t_pg_connection *this = pg_get_connection( self );
2852
2858
 
2853
- if (this->notice_receiver != Qnil) {
2859
+ if (this->notice_processor != Qnil) {
2854
2860
  VALUE message_str = rb_str_new2(message);
2855
2861
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2856
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2862
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2857
2863
  }
2858
2864
  return;
2859
2865
  }
@@ -2877,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
2877
2883
  VALUE proc, old_proc;
2878
2884
  t_pg_connection *this = pg_get_connection_safe( self );
2879
2885
 
2886
+ rb_check_frozen(self);
2880
2887
  /* If default_notice_processor is unset, assume that the current
2881
2888
  * notice processor is the default, and save it to a global variable.
2882
2889
  * This should not be a problem because the default processor is
2883
2890
  * always the same, so won't vary among connections.
2884
2891
  */
2885
- if(default_notice_processor == NULL)
2886
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2892
+ if(this->default_notice_processor == NULL)
2893
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2887
2894
 
2888
- old_proc = this->notice_receiver;
2895
+ old_proc = this->notice_processor;
2889
2896
  if( rb_block_given_p() ) {
2890
2897
  proc = rb_block_proc();
2891
2898
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2892
2899
  } else {
2893
2900
  /* if no block is given, set back to default */
2894
2901
  proc = Qnil;
2895
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2902
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2896
2903
  }
2897
2904
 
2898
- this->notice_receiver = proc;
2905
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2899
2906
  return old_proc;
2900
2907
  }
2901
2908
 
@@ -2927,6 +2934,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2927
2934
  {
2928
2935
  PGconn *conn = pg_get_pgconn( self );
2929
2936
 
2937
+ rb_check_frozen(self);
2930
2938
  Check_Type(str, T_STRING);
2931
2939
 
2932
2940
  if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
@@ -3095,7 +3103,7 @@ pgconn_async_get_last_result(VALUE self)
3095
3103
  VALUE rb_pgresult = Qnil;
3096
3104
  PGresult *cur, *prev;
3097
3105
 
3098
- cur = prev = NULL;
3106
+ cur = prev = NULL;
3099
3107
  for(;;) {
3100
3108
  int status;
3101
3109
 
@@ -4058,6 +4066,7 @@ static VALUE pgconn_external_encoding(VALUE self);
4058
4066
  static VALUE
4059
4067
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
4060
4068
  {
4069
+ rb_check_frozen(self);
4061
4070
  if (NIL_P(enc)) {
4062
4071
  pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
4063
4072
  return enc;
@@ -4112,6 +4121,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4112
4121
  {
4113
4122
  VALUE query_format, query;
4114
4123
 
4124
+ rb_check_frozen(self);
4115
4125
  Check_Type(encname, T_STRING);
4116
4126
  query_format = rb_str_new_cstr("set client_encoding to '%s'");
4117
4127
  query = rb_funcall(query_format, rb_intern("%"), 1, encname);
@@ -4164,6 +4174,7 @@ pgconn_set_default_encoding( VALUE self )
4164
4174
  rb_encoding *enc;
4165
4175
  const char *encname;
4166
4176
 
4177
+ rb_check_frozen(self);
4167
4178
  if (( enc = rb_default_internal_encoding() )) {
4168
4179
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
4169
4180
  if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
@@ -4193,10 +4204,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4193
4204
  t_typemap *tm;
4194
4205
  UNUSED(tm);
4195
4206
 
4207
+ rb_check_frozen(self);
4196
4208
  /* Check type of method param */
4197
4209
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4198
4210
 
4199
- this->type_map_for_queries = typemap;
4211
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
4200
4212
 
4201
4213
  return typemap;
4202
4214
  }
@@ -4233,8 +4245,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4233
4245
  t_typemap *tm;
4234
4246
  UNUSED(tm);
4235
4247
 
4248
+ rb_check_frozen(self);
4236
4249
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4237
- this->type_map_for_results = typemap;
4250
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
4238
4251
 
4239
4252
  return typemap;
4240
4253
  }
@@ -4272,13 +4285,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4272
4285
  {
4273
4286
  t_pg_connection *this = pg_get_connection( self );
4274
4287
 
4288
+ rb_check_frozen(self);
4275
4289
  if( encoder != Qnil ){
4276
4290
  t_pg_coder *co;
4277
4291
  UNUSED(co);
4278
4292
  /* Check argument type */
4279
4293
  TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4280
4294
  }
4281
- this->encoder_for_put_copy_data = encoder;
4295
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4282
4296
 
4283
4297
  return encoder;
4284
4298
  }
@@ -4320,13 +4334,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4320
4334
  {
4321
4335
  t_pg_connection *this = pg_get_connection( self );
4322
4336
 
4337
+ rb_check_frozen(self);
4323
4338
  if( decoder != Qnil ){
4324
4339
  t_pg_coder *co;
4325
4340
  UNUSED(co);
4326
4341
  /* Check argument type */
4327
4342
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4328
4343
  }
4329
- this->decoder_for_get_copy_data = decoder;
4344
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4330
4345
 
4331
4346
  return decoder;
4332
4347
  }
@@ -4372,6 +4387,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4372
4387
  {
4373
4388
  t_pg_connection *this = pg_get_connection( self );
4374
4389
 
4390
+ rb_check_frozen(self);
4375
4391
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4376
4392
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4377
4393
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;