pg 1.4.4 → 1.5.3

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 (70) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +15 -9
  4. data/.github/workflows/binary-gems.yml +42 -11
  5. data/.github/workflows/source-gem.yml +24 -18
  6. data/.gitignore +11 -2
  7. data/.travis.yml +2 -2
  8. data/{History.rdoc → History.md} +246 -150
  9. data/README.ja.md +276 -0
  10. data/README.md +286 -0
  11. data/Rakefile +13 -4
  12. data/Rakefile.cross +7 -11
  13. data/certs/larskanis-2023.pem +24 -0
  14. data/ext/errorcodes.def +4 -0
  15. data/ext/errorcodes.txt +2 -1
  16. data/ext/pg.c +13 -28
  17. data/ext/pg.h +10 -5
  18. data/ext/pg_binary_decoder.c +79 -0
  19. data/ext/pg_binary_encoder.c +224 -0
  20. data/ext/pg_coder.c +16 -7
  21. data/ext/pg_connection.c +160 -61
  22. data/ext/pg_copy_coder.c +306 -17
  23. data/ext/pg_record_coder.c +5 -4
  24. data/ext/pg_result.c +91 -17
  25. data/ext/pg_text_decoder.c +28 -10
  26. data/ext/pg_text_encoder.c +22 -9
  27. data/ext/pg_tuple.c +34 -31
  28. data/ext/pg_type_map.c +3 -2
  29. data/ext/pg_type_map_all_strings.c +2 -2
  30. data/ext/pg_type_map_by_class.c +5 -3
  31. data/ext/pg_type_map_by_column.c +7 -3
  32. data/ext/pg_type_map_by_oid.c +7 -4
  33. data/ext/pg_type_map_in_ruby.c +5 -2
  34. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  35. data/lib/pg/basic_type_map_for_queries.rb +13 -8
  36. data/lib/pg/basic_type_map_for_results.rb +26 -3
  37. data/lib/pg/basic_type_registry.rb +30 -32
  38. data/lib/pg/binary_decoder/date.rb +9 -0
  39. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  40. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  41. data/lib/pg/coder.rb +15 -13
  42. data/lib/pg/connection.rb +104 -30
  43. data/lib/pg/exceptions.rb +7 -0
  44. data/lib/pg/text_decoder/date.rb +18 -0
  45. data/lib/pg/text_decoder/inet.rb +9 -0
  46. data/lib/pg/text_decoder/json.rb +14 -0
  47. data/lib/pg/text_decoder/numeric.rb +9 -0
  48. data/lib/pg/text_decoder/timestamp.rb +30 -0
  49. data/lib/pg/text_encoder/date.rb +12 -0
  50. data/lib/pg/text_encoder/inet.rb +28 -0
  51. data/lib/pg/text_encoder/json.rb +14 -0
  52. data/lib/pg/text_encoder/numeric.rb +9 -0
  53. data/lib/pg/text_encoder/timestamp.rb +24 -0
  54. data/lib/pg/version.rb +1 -1
  55. data/lib/pg.rb +55 -15
  56. data/pg.gemspec +4 -2
  57. data/rakelib/task_extension.rb +1 -1
  58. data/translation/.po4a-version +7 -0
  59. data/translation/po/all.pot +910 -0
  60. data/translation/po/ja.po +1047 -0
  61. data/translation/po4a.cfg +12 -0
  62. data.tar.gz.sig +0 -0
  63. metadata +109 -34
  64. metadata.gz.sig +0 -0
  65. data/README.ja.rdoc +0 -13
  66. data/README.rdoc +0 -233
  67. data/lib/pg/binary_decoder.rb +0 -23
  68. data/lib/pg/constants.rb +0 -12
  69. data/lib/pg/text_decoder.rb +0 -46
  70. data/lib/pg/text_encoder.rb +0 -59
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;
@@ -702,7 +699,10 @@ static VALUE
702
699
  pgconn_port(VALUE self)
703
700
  {
704
701
  char* port = PQport(pg_get_pgconn(self));
705
- return INT2NUM(atoi(port));
702
+ if (!port || port[0] == '\0')
703
+ return INT2NUM(DEF_PGPORT);
704
+ else
705
+ return INT2NUM(atoi(port));
706
706
  }
707
707
 
708
708
  /*
@@ -763,6 +763,10 @@ pgconn_conninfo( VALUE self )
763
763
  *
764
764
  * ... and other constants of kind PG::Constants::CONNECTION_*
765
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
+ *
766
770
  * Example:
767
771
  * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
768
772
  */
@@ -938,7 +942,7 @@ pgconn_socket_io(VALUE self)
938
942
  /* Disable autoclose feature */
939
943
  rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
940
944
 
941
- this->socket_io = socket_io;
945
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
942
946
  }
943
947
 
944
948
  return socket_io;
@@ -1155,7 +1159,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
1155
1159
  },
1156
1160
  0,
1157
1161
  0,
1158
- RUBY_TYPED_FREE_IMMEDIATELY,
1162
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1159
1163
  };
1160
1164
 
1161
1165
  static char *
@@ -1188,7 +1192,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
1188
1192
  },
1189
1193
  0,
1190
1194
  0,
1191
- RUBY_TYPED_FREE_IMMEDIATELY,
1195
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1192
1196
  };
1193
1197
 
1194
1198
  static int
@@ -1811,6 +1815,7 @@ pgconn_set_single_row_mode(VALUE self)
1811
1815
  {
1812
1816
  PGconn *conn = pg_get_pgconn(self);
1813
1817
 
1818
+ rb_check_frozen(self);
1814
1819
  if( PQsetSingleRowMode(conn) == 0 )
1815
1820
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1816
1821
 
@@ -2145,6 +2150,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2145
2150
  {
2146
2151
  int arg;
2147
2152
  PGconn *conn = pg_get_pgconn(self);
2153
+ rb_check_frozen(self);
2148
2154
  if(state == Qtrue)
2149
2155
  arg = 1;
2150
2156
  else if (state == Qfalse)
@@ -2443,8 +2449,9 @@ pgconn_async_flush(VALUE self)
2443
2449
  VALUE socket_io = pgconn_socket_io(self);
2444
2450
  events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2445
2451
 
2446
- if (events & PG_RUBY_IO_READABLE)
2452
+ if (events & PG_RUBY_IO_READABLE){
2447
2453
  pgconn_consume_input(self);
2454
+ }
2448
2455
  }
2449
2456
  return Qtrue;
2450
2457
  }
@@ -2460,6 +2467,7 @@ pgconn_wait_for_flush( VALUE self ){
2460
2467
  static VALUE
2461
2468
  pgconn_flush_data_set( VALUE self, VALUE enabled ){
2462
2469
  t_pg_connection *conn = pg_get_connection(self);
2470
+ rb_check_frozen(self);
2463
2471
  conn->flush_data = RTEST(enabled);
2464
2472
  return enabled;
2465
2473
  }
@@ -2714,6 +2722,7 @@ pgconn_trace(VALUE self, VALUE stream)
2714
2722
  VALUE new_file;
2715
2723
  t_pg_connection *this = pg_get_connection_safe( self );
2716
2724
 
2725
+ rb_check_frozen(self);
2717
2726
  if(!rb_respond_to(stream,rb_intern("fileno")))
2718
2727
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2719
2728
 
@@ -2735,7 +2744,7 @@ pgconn_trace(VALUE self, VALUE stream)
2735
2744
  rb_raise(rb_eArgError, "stream is not writable");
2736
2745
 
2737
2746
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2738
- this->trace_stream = new_file;
2747
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2739
2748
 
2740
2749
  PQtrace(this->pgconn, new_fp);
2741
2750
  return Qnil;
@@ -2754,7 +2763,7 @@ pgconn_untrace(VALUE self)
2754
2763
 
2755
2764
  PQuntrace(this->pgconn);
2756
2765
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2757
- this->trace_stream = Qnil;
2766
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2758
2767
  return Qnil;
2759
2768
  }
2760
2769
 
@@ -2813,13 +2822,14 @@ pgconn_set_notice_receiver(VALUE self)
2813
2822
  VALUE proc, old_proc;
2814
2823
  t_pg_connection *this = pg_get_connection_safe( self );
2815
2824
 
2825
+ rb_check_frozen(self);
2816
2826
  /* If default_notice_receiver is unset, assume that the current
2817
2827
  * notice receiver is the default, and save it to a global variable.
2818
2828
  * This should not be a problem because the default receiver is
2819
2829
  * always the same, so won't vary among connections.
2820
2830
  */
2821
- if(default_notice_receiver == NULL)
2822
- 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);
2823
2833
 
2824
2834
  old_proc = this->notice_receiver;
2825
2835
  if( rb_block_given_p() ) {
@@ -2828,10 +2838,10 @@ pgconn_set_notice_receiver(VALUE self)
2828
2838
  } else {
2829
2839
  /* if no block is given, set back to default */
2830
2840
  proc = Qnil;
2831
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2841
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2832
2842
  }
2833
2843
 
2834
- this->notice_receiver = proc;
2844
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2835
2845
  return old_proc;
2836
2846
  }
2837
2847
 
@@ -2846,10 +2856,10 @@ notice_processor_proxy(void *arg, const char *message)
2846
2856
  VALUE self = (VALUE)arg;
2847
2857
  t_pg_connection *this = pg_get_connection( self );
2848
2858
 
2849
- if (this->notice_receiver != Qnil) {
2859
+ if (this->notice_processor != Qnil) {
2850
2860
  VALUE message_str = rb_str_new2(message);
2851
2861
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2852
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2862
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2853
2863
  }
2854
2864
  return;
2855
2865
  }
@@ -2873,25 +2883,26 @@ pgconn_set_notice_processor(VALUE self)
2873
2883
  VALUE proc, old_proc;
2874
2884
  t_pg_connection *this = pg_get_connection_safe( self );
2875
2885
 
2886
+ rb_check_frozen(self);
2876
2887
  /* If default_notice_processor is unset, assume that the current
2877
2888
  * notice processor is the default, and save it to a global variable.
2878
2889
  * This should not be a problem because the default processor is
2879
2890
  * always the same, so won't vary among connections.
2880
2891
  */
2881
- if(default_notice_processor == NULL)
2882
- 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);
2883
2894
 
2884
- old_proc = this->notice_receiver;
2895
+ old_proc = this->notice_processor;
2885
2896
  if( rb_block_given_p() ) {
2886
2897
  proc = rb_block_proc();
2887
2898
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2888
2899
  } else {
2889
2900
  /* if no block is given, set back to default */
2890
2901
  proc = Qnil;
2891
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2902
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2892
2903
  }
2893
2904
 
2894
- this->notice_receiver = proc;
2905
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2895
2906
  return old_proc;
2896
2907
  }
2897
2908
 
@@ -2923,6 +2934,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2923
2934
  {
2924
2935
  PGconn *conn = pg_get_pgconn( self );
2925
2936
 
2937
+ rb_check_frozen(self);
2926
2938
  Check_Type(str, T_STRING);
2927
2939
 
2928
2940
  if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
@@ -3091,7 +3103,7 @@ pgconn_async_get_last_result(VALUE self)
3091
3103
  VALUE rb_pgresult = Qnil;
3092
3104
  PGresult *cur, *prev;
3093
3105
 
3094
- cur = prev = NULL;
3106
+ cur = prev = NULL;
3095
3107
  for(;;) {
3096
3108
  int status;
3097
3109
 
@@ -3123,8 +3135,14 @@ pgconn_async_get_last_result(VALUE self)
3123
3135
  * conn.discard_results()
3124
3136
  *
3125
3137
  * Silently discard any prior query result that application didn't eat.
3126
- * This is done prior of Connection#exec and sibling methods and can
3127
- * be called explicitly when using the async API.
3138
+ * This is internally used prior to Connection#exec and sibling methods.
3139
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3140
+ *
3141
+ * Returns:
3142
+ * * +nil+ when the connection is already idle
3143
+ * * +true+ when some results have been discarded
3144
+ * * +false+ when a failure occured and the connection was closed
3145
+ *
3128
3146
  */
3129
3147
  static VALUE
3130
3148
  pgconn_discard_results(VALUE self)
@@ -3132,8 +3150,12 @@ pgconn_discard_results(VALUE self)
3132
3150
  PGconn *conn = pg_get_pgconn(self);
3133
3151
  VALUE socket_io;
3134
3152
 
3135
- if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3136
- return Qnil;
3153
+ switch( PQtransactionStatus(conn) ) {
3154
+ case PQTRANS_IDLE:
3155
+ case PQTRANS_INTRANS:
3156
+ case PQTRANS_INERROR:
3157
+ return Qnil;
3158
+ default:;
3137
3159
  }
3138
3160
 
3139
3161
  socket_io = pgconn_socket_io(self);
@@ -3146,10 +3168,21 @@ pgconn_discard_results(VALUE self)
3146
3168
  * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3147
3169
  */
3148
3170
  while( gvl_PQisBusy(conn) ){
3149
- pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3150
- if ( PQconsumeInput(conn) == 0 ) {
3151
- pgconn_close_socket_io(self);
3152
- return Qfalse;
3171
+ int events;
3172
+
3173
+ switch( PQflush(conn) ) {
3174
+ case 1:
3175
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3176
+ if (events & PG_RUBY_IO_READABLE){
3177
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3178
+ }
3179
+ break;
3180
+ case 0:
3181
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3182
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3183
+ break;
3184
+ default:
3185
+ goto error;
3153
3186
  }
3154
3187
  }
3155
3188
 
@@ -3159,7 +3192,9 @@ pgconn_discard_results(VALUE self)
3159
3192
  status = PQresultStatus(cur);
3160
3193
  PQclear(cur);
3161
3194
  if (status == PGRES_COPY_IN){
3162
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3195
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3196
+ pgconn_async_flush(self);
3197
+ }
3163
3198
  }
3164
3199
  if (status == PGRES_COPY_OUT){
3165
3200
  for(;;) {
@@ -3168,10 +3203,7 @@ pgconn_discard_results(VALUE self)
3168
3203
  if( st == 0 ) {
3169
3204
  /* would block -> wait for readable data */
3170
3205
  pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3171
- if ( PQconsumeInput(conn) == 0 ) {
3172
- pgconn_close_socket_io(self);
3173
- return Qfalse;
3174
- }
3206
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3175
3207
  } else if( st > 0 ) {
3176
3208
  /* some data retrieved -> discard it */
3177
3209
  PQfreemem(buffer);
@@ -3184,6 +3216,10 @@ pgconn_discard_results(VALUE self)
3184
3216
  }
3185
3217
 
3186
3218
  return Qtrue;
3219
+
3220
+ error:
3221
+ pgconn_close_socket_io(self);
3222
+ return Qfalse;
3187
3223
  }
3188
3224
 
3189
3225
  /*
@@ -3640,6 +3676,14 @@ pgconn_send_flush_request(VALUE self)
3640
3676
  * LARGE OBJECT SUPPORT
3641
3677
  **************************************************************************/
3642
3678
 
3679
+ #define BLOCKING_BEGIN(conn) do { \
3680
+ int old_nonblocking = PQisnonblocking(conn); \
3681
+ PQsetnonblocking(conn, 0);
3682
+
3683
+ #define BLOCKING_END(th) \
3684
+ PQsetnonblocking(conn, old_nonblocking); \
3685
+ } while(0);
3686
+
3643
3687
  /*
3644
3688
  * call-seq:
3645
3689
  * conn.lo_creat( [mode] ) -> Integer
@@ -3660,7 +3704,10 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3660
3704
  else
3661
3705
  mode = NUM2INT(nmode);
3662
3706
 
3663
- lo_oid = lo_creat(conn, mode);
3707
+ BLOCKING_BEGIN(conn)
3708
+ lo_oid = lo_creat(conn, mode);
3709
+ BLOCKING_END(conn)
3710
+
3664
3711
  if (lo_oid == 0)
3665
3712
  pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3666
3713
 
@@ -3705,7 +3752,10 @@ pgconn_loimport(VALUE self, VALUE filename)
3705
3752
 
3706
3753
  Check_Type(filename, T_STRING);
3707
3754
 
3708
- lo_oid = lo_import(conn, StringValueCStr(filename));
3755
+ BLOCKING_BEGIN(conn)
3756
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3757
+ BLOCKING_END(conn)
3758
+
3709
3759
  if (lo_oid == 0) {
3710
3760
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3711
3761
  }
@@ -3723,11 +3773,16 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3723
3773
  {
3724
3774
  PGconn *conn = pg_get_pgconn(self);
3725
3775
  Oid oid;
3776
+ int ret;
3726
3777
  Check_Type(filename, T_STRING);
3727
3778
 
3728
3779
  oid = NUM2UINT(lo_oid);
3729
3780
 
3730
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3781
+ BLOCKING_BEGIN(conn)
3782
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3783
+ BLOCKING_END(conn)
3784
+
3785
+ if (ret < 0) {
3731
3786
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3732
3787
  }
3733
3788
  return Qnil;
@@ -3758,7 +3813,11 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3758
3813
  else
3759
3814
  mode = NUM2INT(nmode);
3760
3815
 
3761
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3816
+ BLOCKING_BEGIN(conn)
3817
+ fd = lo_open(conn, lo_oid, mode);
3818
+ BLOCKING_END(conn)
3819
+
3820
+ if(fd < 0) {
3762
3821
  pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3763
3822
  }
3764
3823
  return INT2FIX(fd);
@@ -3783,8 +3842,12 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3783
3842
  if( RSTRING_LEN(buffer) < 0) {
3784
3843
  pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3785
3844
  }
3786
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3787
- RSTRING_LEN(buffer))) < 0) {
3845
+ BLOCKING_BEGIN(conn)
3846
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3847
+ RSTRING_LEN(buffer));
3848
+ BLOCKING_END(conn)
3849
+
3850
+ if(n < 0) {
3788
3851
  pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3789
3852
  }
3790
3853
 
@@ -3812,7 +3875,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3812
3875
  pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3813
3876
 
3814
3877
  buffer = ALLOC_N(char, len);
3815
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3878
+
3879
+ BLOCKING_BEGIN(conn)
3880
+ ret = lo_read(conn, lo_desc, buffer, len);
3881
+ BLOCKING_END(conn)
3882
+
3883
+ if(ret < 0)
3816
3884
  pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3817
3885
 
3818
3886
  if(ret == 0) {
@@ -3842,7 +3910,11 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3842
3910
  int lo_desc = NUM2INT(in_lo_desc);
3843
3911
  int ret;
3844
3912
 
3845
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3913
+ BLOCKING_BEGIN(conn)
3914
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3915
+ BLOCKING_END(conn)
3916
+
3917
+ if(ret < 0) {
3846
3918
  pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3847
3919
  }
3848
3920
 
@@ -3862,7 +3934,11 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3862
3934
  PGconn *conn = pg_get_pgconn(self);
3863
3935
  int lo_desc = NUM2INT(in_lo_desc);
3864
3936
 
3865
- if((position = lo_tell(conn, lo_desc)) < 0)
3937
+ BLOCKING_BEGIN(conn)
3938
+ position = lo_tell(conn, lo_desc);
3939
+ BLOCKING_END(conn)
3940
+
3941
+ if(position < 0)
3866
3942
  pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3867
3943
 
3868
3944
  return INT2FIX(position);
@@ -3880,8 +3956,13 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3880
3956
  PGconn *conn = pg_get_pgconn(self);
3881
3957
  int lo_desc = NUM2INT(in_lo_desc);
3882
3958
  size_t len = NUM2INT(in_len);
3959
+ int ret;
3960
+
3961
+ BLOCKING_BEGIN(conn)
3962
+ ret = lo_truncate(conn,lo_desc,len);
3963
+ BLOCKING_END(conn)
3883
3964
 
3884
- if(lo_truncate(conn,lo_desc,len) < 0)
3965
+ if(ret < 0)
3885
3966
  pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3886
3967
 
3887
3968
  return Qnil;
@@ -3898,8 +3979,13 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3898
3979
  {
3899
3980
  PGconn *conn = pg_get_pgconn(self);
3900
3981
  int lo_desc = NUM2INT(in_lo_desc);
3982
+ int ret;
3983
+
3984
+ BLOCKING_BEGIN(conn)
3985
+ ret = lo_close(conn,lo_desc);
3986
+ BLOCKING_END(conn)
3901
3987
 
3902
- if(lo_close(conn,lo_desc) < 0)
3988
+ if(ret < 0)
3903
3989
  pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3904
3990
 
3905
3991
  return Qnil;
@@ -3916,8 +4002,13 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3916
4002
  {
3917
4003
  PGconn *conn = pg_get_pgconn(self);
3918
4004
  Oid oid = NUM2UINT(in_oid);
4005
+ int ret;
4006
+
4007
+ BLOCKING_BEGIN(conn)
4008
+ ret = lo_unlink(conn,oid);
4009
+ BLOCKING_END(conn)
3919
4010
 
3920
- if(lo_unlink(conn,oid) < 0)
4011
+ if(ret < 0)
3921
4012
  pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3922
4013
 
3923
4014
  return Qnil;
@@ -3975,6 +4066,7 @@ static VALUE pgconn_external_encoding(VALUE self);
3975
4066
  static VALUE
3976
4067
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3977
4068
  {
4069
+ rb_check_frozen(self);
3978
4070
  if (NIL_P(enc)) {
3979
4071
  pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3980
4072
  return enc;
@@ -4029,6 +4121,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4029
4121
  {
4030
4122
  VALUE query_format, query;
4031
4123
 
4124
+ rb_check_frozen(self);
4032
4125
  Check_Type(encname, T_STRING);
4033
4126
  query_format = rb_str_new_cstr("set client_encoding to '%s'");
4034
4127
  query = rb_funcall(query_format, rb_intern("%"), 1, encname);
@@ -4081,6 +4174,7 @@ pgconn_set_default_encoding( VALUE self )
4081
4174
  rb_encoding *enc;
4082
4175
  const char *encname;
4083
4176
 
4177
+ rb_check_frozen(self);
4084
4178
  if (( enc = rb_default_internal_encoding() )) {
4085
4179
  encname = pg_get_rb_encoding_as_pg_encoding( enc );
4086
4180
  if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
@@ -4110,10 +4204,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4110
4204
  t_typemap *tm;
4111
4205
  UNUSED(tm);
4112
4206
 
4207
+ rb_check_frozen(self);
4113
4208
  /* Check type of method param */
4114
4209
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4115
4210
 
4116
- this->type_map_for_queries = typemap;
4211
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
4117
4212
 
4118
4213
  return typemap;
4119
4214
  }
@@ -4150,8 +4245,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4150
4245
  t_typemap *tm;
4151
4246
  UNUSED(tm);
4152
4247
 
4248
+ rb_check_frozen(self);
4153
4249
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4154
- this->type_map_for_results = typemap;
4250
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
4155
4251
 
4156
4252
  return typemap;
4157
4253
  }
@@ -4189,13 +4285,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4189
4285
  {
4190
4286
  t_pg_connection *this = pg_get_connection( self );
4191
4287
 
4288
+ rb_check_frozen(self);
4192
4289
  if( encoder != Qnil ){
4193
4290
  t_pg_coder *co;
4194
4291
  UNUSED(co);
4195
4292
  /* Check argument type */
4196
4293
  TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4197
4294
  }
4198
- this->encoder_for_put_copy_data = encoder;
4295
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4199
4296
 
4200
4297
  return encoder;
4201
4298
  }
@@ -4237,13 +4334,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4237
4334
  {
4238
4335
  t_pg_connection *this = pg_get_connection( self );
4239
4336
 
4337
+ rb_check_frozen(self);
4240
4338
  if( decoder != Qnil ){
4241
4339
  t_pg_coder *co;
4242
4340
  UNUSED(co);
4243
4341
  /* Check argument type */
4244
4342
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4245
4343
  }
4246
- this->decoder_for_get_copy_data = decoder;
4344
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4247
4345
 
4248
4346
  return decoder;
4249
4347
  }
@@ -4289,6 +4387,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4289
4387
  {
4290
4388
  t_pg_connection *this = pg_get_connection( self );
4291
4389
 
4390
+ rb_check_frozen(self);
4292
4391
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4293
4392
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4294
4393
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;