pg 1.4.1 → 1.5.6

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 (72) 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 +45 -14
  5. data/.github/workflows/source-gem.yml +35 -23
  6. data/.gitignore +11 -2
  7. data/.travis.yml +2 -2
  8. data/Gemfile +3 -0
  9. data/{History.rdoc → History.md} +285 -140
  10. data/README.ja.md +300 -0
  11. data/README.md +286 -0
  12. data/Rakefile +18 -6
  13. data/Rakefile.cross +8 -11
  14. data/certs/kanis@comcard.de.pem +20 -0
  15. data/certs/larskanis-2023.pem +24 -0
  16. data/certs/larskanis-2024.pem +24 -0
  17. data/ext/errorcodes.def +4 -0
  18. data/ext/errorcodes.txt +2 -1
  19. data/ext/extconf.rb +4 -0
  20. data/ext/pg.c +15 -55
  21. data/ext/pg.h +11 -6
  22. data/ext/pg_binary_decoder.c +80 -1
  23. data/ext/pg_binary_encoder.c +225 -1
  24. data/ext/pg_coder.c +17 -8
  25. data/ext/pg_connection.c +201 -73
  26. data/ext/pg_copy_coder.c +307 -18
  27. data/ext/pg_errors.c +1 -1
  28. data/ext/pg_record_coder.c +6 -5
  29. data/ext/pg_result.c +102 -26
  30. data/ext/pg_text_decoder.c +28 -10
  31. data/ext/pg_text_encoder.c +23 -10
  32. data/ext/pg_tuple.c +35 -32
  33. data/ext/pg_type_map.c +4 -3
  34. data/ext/pg_type_map_all_strings.c +3 -3
  35. data/ext/pg_type_map_by_class.c +6 -4
  36. data/ext/pg_type_map_by_column.c +9 -5
  37. data/ext/pg_type_map_by_mri_type.c +1 -1
  38. data/ext/pg_type_map_by_oid.c +8 -5
  39. data/ext/pg_type_map_in_ruby.c +6 -3
  40. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  41. data/lib/pg/basic_type_map_for_queries.rb +19 -10
  42. data/lib/pg/basic_type_map_for_results.rb +26 -3
  43. data/lib/pg/basic_type_registry.rb +35 -33
  44. data/lib/pg/binary_decoder/date.rb +9 -0
  45. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  46. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  47. data/lib/pg/coder.rb +15 -13
  48. data/lib/pg/connection.rb +186 -104
  49. data/lib/pg/exceptions.rb +7 -0
  50. data/lib/pg/text_decoder/date.rb +18 -0
  51. data/lib/pg/text_decoder/inet.rb +9 -0
  52. data/lib/pg/text_decoder/json.rb +14 -0
  53. data/lib/pg/text_decoder/numeric.rb +9 -0
  54. data/lib/pg/text_decoder/timestamp.rb +30 -0
  55. data/lib/pg/text_encoder/date.rb +12 -0
  56. data/lib/pg/text_encoder/inet.rb +28 -0
  57. data/lib/pg/text_encoder/json.rb +14 -0
  58. data/lib/pg/text_encoder/numeric.rb +9 -0
  59. data/lib/pg/text_encoder/timestamp.rb +24 -0
  60. data/lib/pg/version.rb +1 -1
  61. data/lib/pg.rb +55 -15
  62. data/pg.gemspec +5 -3
  63. data/rakelib/task_extension.rb +1 -1
  64. data.tar.gz.sig +0 -0
  65. metadata +96 -32
  66. metadata.gz.sig +0 -0
  67. data/README.ja.rdoc +0 -13
  68. data/README.rdoc +0 -214
  69. data/lib/pg/binary_decoder.rb +0 -23
  70. data/lib/pg/constants.rb +0 -12
  71. data/lib/pg/text_decoder.rb +0 -46
  72. 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,15 @@ 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);
266
+ rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
269
267
 
270
268
  return self;
271
269
  }
@@ -565,6 +563,27 @@ pgconn_sync_reset( VALUE self )
565
563
  return self;
566
564
  }
567
565
 
566
+ static VALUE
567
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
568
+ {
569
+ t_pg_connection *this = pg_get_connection( self );
570
+
571
+ /* Close old connection */
572
+ pgconn_close_socket_io( self );
573
+ PQfinish( this->pgconn );
574
+
575
+ /* Start new connection */
576
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
577
+
578
+ if( this->pgconn == NULL )
579
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
580
+
581
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
582
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
583
+
584
+ return Qnil;
585
+ }
586
+
568
587
  /*
569
588
  * call-seq:
570
589
  * conn.reset_start() -> nil
@@ -701,7 +720,10 @@ static VALUE
701
720
  pgconn_port(VALUE self)
702
721
  {
703
722
  char* port = PQport(pg_get_pgconn(self));
704
- return INT2NUM(atoi(port));
723
+ if (!port || port[0] == '\0')
724
+ return INT2NUM(DEF_PGPORT);
725
+ else
726
+ return INT2NUM(atoi(port));
705
727
  }
706
728
 
707
729
  /*
@@ -762,6 +784,10 @@ pgconn_conninfo( VALUE self )
762
784
  *
763
785
  * ... and other constants of kind PG::Constants::CONNECTION_*
764
786
  *
787
+ * This method returns the status of the last command from memory.
788
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
789
+ * See check_socket for a way to verify the socket state.
790
+ *
765
791
  * Example:
766
792
  * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
767
793
  */
@@ -937,7 +963,7 @@ pgconn_socket_io(VALUE self)
937
963
  /* Disable autoclose feature */
938
964
  rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
939
965
 
940
- this->socket_io = socket_io;
966
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
941
967
  }
942
968
 
943
969
  return socket_io;
@@ -1154,7 +1180,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
1154
1180
  },
1155
1181
  0,
1156
1182
  0,
1157
- RUBY_TYPED_FREE_IMMEDIATELY,
1183
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1158
1184
  };
1159
1185
 
1160
1186
  static char *
@@ -1187,7 +1213,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
1187
1213
  },
1188
1214
  0,
1189
1215
  0,
1190
- RUBY_TYPED_FREE_IMMEDIATELY,
1216
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1191
1217
  };
1192
1218
 
1193
1219
  static int
@@ -1526,8 +1552,7 @@ pgconn_sync_describe_prepared(VALUE self, VALUE stmt_name)
1526
1552
  * It's not recommended to use explicit sync or async variants but #describe_portal instead, unless you have a good reason to do so.
1527
1553
  */
1528
1554
  static VALUE
1529
- pgconn_sync_describe_portal(self, stmt_name)
1530
- VALUE self, stmt_name;
1555
+ pgconn_sync_describe_portal(VALUE self, VALUE stmt_name)
1531
1556
  {
1532
1557
  PGresult *result;
1533
1558
  VALUE rb_pgresult;
@@ -1811,6 +1836,7 @@ pgconn_set_single_row_mode(VALUE self)
1811
1836
  {
1812
1837
  PGconn *conn = pg_get_pgconn(self);
1813
1838
 
1839
+ rb_check_frozen(self);
1814
1840
  if( PQsetSingleRowMode(conn) == 0 )
1815
1841
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1816
1842
 
@@ -2145,6 +2171,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2145
2171
  {
2146
2172
  int arg;
2147
2173
  PGconn *conn = pg_get_pgconn(self);
2174
+ rb_check_frozen(self);
2148
2175
  if(state == Qtrue)
2149
2176
  arg = 1;
2150
2177
  else if (state == Qfalse)
@@ -2443,8 +2470,9 @@ pgconn_async_flush(VALUE self)
2443
2470
  VALUE socket_io = pgconn_socket_io(self);
2444
2471
  events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2445
2472
 
2446
- if (events & PG_RUBY_IO_READABLE)
2473
+ if (events & PG_RUBY_IO_READABLE){
2447
2474
  pgconn_consume_input(self);
2475
+ }
2448
2476
  }
2449
2477
  return Qtrue;
2450
2478
  }
@@ -2460,6 +2488,7 @@ pgconn_wait_for_flush( VALUE self ){
2460
2488
  static VALUE
2461
2489
  pgconn_flush_data_set( VALUE self, VALUE enabled ){
2462
2490
  t_pg_connection *conn = pg_get_connection(self);
2491
+ rb_check_frozen(self);
2463
2492
  conn->flush_data = RTEST(enabled);
2464
2493
  return enabled;
2465
2494
  }
@@ -2714,6 +2743,7 @@ pgconn_trace(VALUE self, VALUE stream)
2714
2743
  VALUE new_file;
2715
2744
  t_pg_connection *this = pg_get_connection_safe( self );
2716
2745
 
2746
+ rb_check_frozen(self);
2717
2747
  if(!rb_respond_to(stream,rb_intern("fileno")))
2718
2748
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2719
2749
 
@@ -2735,7 +2765,7 @@ pgconn_trace(VALUE self, VALUE stream)
2735
2765
  rb_raise(rb_eArgError, "stream is not writable");
2736
2766
 
2737
2767
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2738
- this->trace_stream = new_file;
2768
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2739
2769
 
2740
2770
  PQtrace(this->pgconn, new_fp);
2741
2771
  return Qnil;
@@ -2754,7 +2784,7 @@ pgconn_untrace(VALUE self)
2754
2784
 
2755
2785
  PQuntrace(this->pgconn);
2756
2786
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2757
- this->trace_stream = Qnil;
2787
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2758
2788
  return Qnil;
2759
2789
  }
2760
2790
 
@@ -2813,13 +2843,14 @@ pgconn_set_notice_receiver(VALUE self)
2813
2843
  VALUE proc, old_proc;
2814
2844
  t_pg_connection *this = pg_get_connection_safe( self );
2815
2845
 
2846
+ rb_check_frozen(self);
2816
2847
  /* If default_notice_receiver is unset, assume that the current
2817
2848
  * notice receiver is the default, and save it to a global variable.
2818
2849
  * This should not be a problem because the default receiver is
2819
2850
  * always the same, so won't vary among connections.
2820
2851
  */
2821
- if(default_notice_receiver == NULL)
2822
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2852
+ if(this->default_notice_receiver == NULL)
2853
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2823
2854
 
2824
2855
  old_proc = this->notice_receiver;
2825
2856
  if( rb_block_given_p() ) {
@@ -2828,10 +2859,10 @@ pgconn_set_notice_receiver(VALUE self)
2828
2859
  } else {
2829
2860
  /* if no block is given, set back to default */
2830
2861
  proc = Qnil;
2831
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2862
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2832
2863
  }
2833
2864
 
2834
- this->notice_receiver = proc;
2865
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2835
2866
  return old_proc;
2836
2867
  }
2837
2868
 
@@ -2846,10 +2877,10 @@ notice_processor_proxy(void *arg, const char *message)
2846
2877
  VALUE self = (VALUE)arg;
2847
2878
  t_pg_connection *this = pg_get_connection( self );
2848
2879
 
2849
- if (this->notice_receiver != Qnil) {
2880
+ if (this->notice_processor != Qnil) {
2850
2881
  VALUE message_str = rb_str_new2(message);
2851
2882
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2852
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2883
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2853
2884
  }
2854
2885
  return;
2855
2886
  }
@@ -2873,25 +2904,26 @@ pgconn_set_notice_processor(VALUE self)
2873
2904
  VALUE proc, old_proc;
2874
2905
  t_pg_connection *this = pg_get_connection_safe( self );
2875
2906
 
2907
+ rb_check_frozen(self);
2876
2908
  /* If default_notice_processor is unset, assume that the current
2877
2909
  * notice processor is the default, and save it to a global variable.
2878
2910
  * This should not be a problem because the default processor is
2879
2911
  * always the same, so won't vary among connections.
2880
2912
  */
2881
- if(default_notice_processor == NULL)
2882
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2913
+ if(this->default_notice_processor == NULL)
2914
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2883
2915
 
2884
- old_proc = this->notice_receiver;
2916
+ old_proc = this->notice_processor;
2885
2917
  if( rb_block_given_p() ) {
2886
2918
  proc = rb_block_proc();
2887
2919
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2888
2920
  } else {
2889
2921
  /* if no block is given, set back to default */
2890
2922
  proc = Qnil;
2891
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2923
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2892
2924
  }
2893
2925
 
2894
- this->notice_receiver = proc;
2926
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2895
2927
  return old_proc;
2896
2928
  }
2897
2929
 
@@ -2923,6 +2955,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2923
2955
  {
2924
2956
  PGconn *conn = pg_get_pgconn( self );
2925
2957
 
2958
+ rb_check_frozen(self);
2926
2959
  Check_Type(str, T_STRING);
2927
2960
 
2928
2961
  if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
@@ -3091,7 +3124,7 @@ pgconn_async_get_last_result(VALUE self)
3091
3124
  VALUE rb_pgresult = Qnil;
3092
3125
  PGresult *cur, *prev;
3093
3126
 
3094
- cur = prev = NULL;
3127
+ cur = prev = NULL;
3095
3128
  for(;;) {
3096
3129
  int status;
3097
3130
 
@@ -3123,8 +3156,14 @@ pgconn_async_get_last_result(VALUE self)
3123
3156
  * conn.discard_results()
3124
3157
  *
3125
3158
  * 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.
3159
+ * This is internally used prior to Connection#exec and sibling methods.
3160
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3161
+ *
3162
+ * Returns:
3163
+ * * +nil+ when the connection is already idle
3164
+ * * +true+ when some results have been discarded
3165
+ * * +false+ when a failure occured and the connection was closed
3166
+ *
3128
3167
  */
3129
3168
  static VALUE
3130
3169
  pgconn_discard_results(VALUE self)
@@ -3132,8 +3171,12 @@ pgconn_discard_results(VALUE self)
3132
3171
  PGconn *conn = pg_get_pgconn(self);
3133
3172
  VALUE socket_io;
3134
3173
 
3135
- if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3136
- return Qnil;
3174
+ switch( PQtransactionStatus(conn) ) {
3175
+ case PQTRANS_IDLE:
3176
+ case PQTRANS_INTRANS:
3177
+ case PQTRANS_INERROR:
3178
+ return Qnil;
3179
+ default:;
3137
3180
  }
3138
3181
 
3139
3182
  socket_io = pgconn_socket_io(self);
@@ -3146,10 +3189,21 @@ pgconn_discard_results(VALUE self)
3146
3189
  * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3147
3190
  */
3148
3191
  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;
3192
+ int events;
3193
+
3194
+ switch( PQflush(conn) ) {
3195
+ case 1:
3196
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3197
+ if (events & PG_RUBY_IO_READABLE){
3198
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3199
+ }
3200
+ break;
3201
+ case 0:
3202
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3203
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3204
+ break;
3205
+ default:
3206
+ goto error;
3153
3207
  }
3154
3208
  }
3155
3209
 
@@ -3159,7 +3213,9 @@ pgconn_discard_results(VALUE self)
3159
3213
  status = PQresultStatus(cur);
3160
3214
  PQclear(cur);
3161
3215
  if (status == PGRES_COPY_IN){
3162
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3216
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3217
+ pgconn_async_flush(self);
3218
+ }
3163
3219
  }
3164
3220
  if (status == PGRES_COPY_OUT){
3165
3221
  for(;;) {
@@ -3168,10 +3224,7 @@ pgconn_discard_results(VALUE self)
3168
3224
  if( st == 0 ) {
3169
3225
  /* would block -> wait for readable data */
3170
3226
  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
- }
3227
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3175
3228
  } else if( st > 0 ) {
3176
3229
  /* some data retrieved -> discard it */
3177
3230
  PQfreemem(buffer);
@@ -3184,6 +3237,10 @@ pgconn_discard_results(VALUE self)
3184
3237
  }
3185
3238
 
3186
3239
  return Qtrue;
3240
+
3241
+ error:
3242
+ pgconn_close_socket_io(self);
3243
+ return Qfalse;
3187
3244
  }
3188
3245
 
3189
3246
  /*
@@ -3640,6 +3697,14 @@ pgconn_send_flush_request(VALUE self)
3640
3697
  * LARGE OBJECT SUPPORT
3641
3698
  **************************************************************************/
3642
3699
 
3700
+ #define BLOCKING_BEGIN(conn) do { \
3701
+ int old_nonblocking = PQisnonblocking(conn); \
3702
+ PQsetnonblocking(conn, 0);
3703
+
3704
+ #define BLOCKING_END(th) \
3705
+ PQsetnonblocking(conn, old_nonblocking); \
3706
+ } while(0);
3707
+
3643
3708
  /*
3644
3709
  * call-seq:
3645
3710
  * conn.lo_creat( [mode] ) -> Integer
@@ -3660,7 +3725,10 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3660
3725
  else
3661
3726
  mode = NUM2INT(nmode);
3662
3727
 
3663
- lo_oid = lo_creat(conn, mode);
3728
+ BLOCKING_BEGIN(conn)
3729
+ lo_oid = lo_creat(conn, mode);
3730
+ BLOCKING_END(conn)
3731
+
3664
3732
  if (lo_oid == 0)
3665
3733
  pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3666
3734
 
@@ -3705,7 +3773,10 @@ pgconn_loimport(VALUE self, VALUE filename)
3705
3773
 
3706
3774
  Check_Type(filename, T_STRING);
3707
3775
 
3708
- lo_oid = lo_import(conn, StringValueCStr(filename));
3776
+ BLOCKING_BEGIN(conn)
3777
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3778
+ BLOCKING_END(conn)
3779
+
3709
3780
  if (lo_oid == 0) {
3710
3781
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3711
3782
  }
@@ -3723,11 +3794,16 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3723
3794
  {
3724
3795
  PGconn *conn = pg_get_pgconn(self);
3725
3796
  Oid oid;
3797
+ int ret;
3726
3798
  Check_Type(filename, T_STRING);
3727
3799
 
3728
3800
  oid = NUM2UINT(lo_oid);
3729
3801
 
3730
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3802
+ BLOCKING_BEGIN(conn)
3803
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3804
+ BLOCKING_END(conn)
3805
+
3806
+ if (ret < 0) {
3731
3807
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3732
3808
  }
3733
3809
  return Qnil;
@@ -3758,7 +3834,11 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3758
3834
  else
3759
3835
  mode = NUM2INT(nmode);
3760
3836
 
3761
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3837
+ BLOCKING_BEGIN(conn)
3838
+ fd = lo_open(conn, lo_oid, mode);
3839
+ BLOCKING_END(conn)
3840
+
3841
+ if(fd < 0) {
3762
3842
  pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3763
3843
  }
3764
3844
  return INT2FIX(fd);
@@ -3783,8 +3863,12 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3783
3863
  if( RSTRING_LEN(buffer) < 0) {
3784
3864
  pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3785
3865
  }
3786
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3787
- RSTRING_LEN(buffer))) < 0) {
3866
+ BLOCKING_BEGIN(conn)
3867
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3868
+ RSTRING_LEN(buffer));
3869
+ BLOCKING_END(conn)
3870
+
3871
+ if(n < 0) {
3788
3872
  pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3789
3873
  }
3790
3874
 
@@ -3812,7 +3896,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3812
3896
  pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3813
3897
 
3814
3898
  buffer = ALLOC_N(char, len);
3815
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3899
+
3900
+ BLOCKING_BEGIN(conn)
3901
+ ret = lo_read(conn, lo_desc, buffer, len);
3902
+ BLOCKING_END(conn)
3903
+
3904
+ if(ret < 0)
3816
3905
  pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3817
3906
 
3818
3907
  if(ret == 0) {
@@ -3842,7 +3931,11 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3842
3931
  int lo_desc = NUM2INT(in_lo_desc);
3843
3932
  int ret;
3844
3933
 
3845
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3934
+ BLOCKING_BEGIN(conn)
3935
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3936
+ BLOCKING_END(conn)
3937
+
3938
+ if(ret < 0) {
3846
3939
  pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3847
3940
  }
3848
3941
 
@@ -3862,7 +3955,11 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3862
3955
  PGconn *conn = pg_get_pgconn(self);
3863
3956
  int lo_desc = NUM2INT(in_lo_desc);
3864
3957
 
3865
- if((position = lo_tell(conn, lo_desc)) < 0)
3958
+ BLOCKING_BEGIN(conn)
3959
+ position = lo_tell(conn, lo_desc);
3960
+ BLOCKING_END(conn)
3961
+
3962
+ if(position < 0)
3866
3963
  pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3867
3964
 
3868
3965
  return INT2FIX(position);
@@ -3880,8 +3977,13 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3880
3977
  PGconn *conn = pg_get_pgconn(self);
3881
3978
  int lo_desc = NUM2INT(in_lo_desc);
3882
3979
  size_t len = NUM2INT(in_len);
3980
+ int ret;
3981
+
3982
+ BLOCKING_BEGIN(conn)
3983
+ ret = lo_truncate(conn,lo_desc,len);
3984
+ BLOCKING_END(conn)
3883
3985
 
3884
- if(lo_truncate(conn,lo_desc,len) < 0)
3986
+ if(ret < 0)
3885
3987
  pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3886
3988
 
3887
3989
  return Qnil;
@@ -3898,8 +4000,13 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3898
4000
  {
3899
4001
  PGconn *conn = pg_get_pgconn(self);
3900
4002
  int lo_desc = NUM2INT(in_lo_desc);
4003
+ int ret;
4004
+
4005
+ BLOCKING_BEGIN(conn)
4006
+ ret = lo_close(conn,lo_desc);
4007
+ BLOCKING_END(conn)
3901
4008
 
3902
- if(lo_close(conn,lo_desc) < 0)
4009
+ if(ret < 0)
3903
4010
  pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3904
4011
 
3905
4012
  return Qnil;
@@ -3916,8 +4023,13 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3916
4023
  {
3917
4024
  PGconn *conn = pg_get_pgconn(self);
3918
4025
  Oid oid = NUM2UINT(in_oid);
4026
+ int ret;
4027
+
4028
+ BLOCKING_BEGIN(conn)
4029
+ ret = lo_unlink(conn,oid);
4030
+ BLOCKING_END(conn)
3919
4031
 
3920
- if(lo_unlink(conn,oid) < 0)
4032
+ if(ret < 0)
3921
4033
  pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3922
4034
 
3923
4035
  return Qnil;
@@ -3975,6 +4087,7 @@ static VALUE pgconn_external_encoding(VALUE self);
3975
4087
  static VALUE
3976
4088
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3977
4089
  {
4090
+ rb_check_frozen(self);
3978
4091
  if (NIL_P(enc)) {
3979
4092
  pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3980
4093
  return enc;
@@ -4029,6 +4142,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4029
4142
  {
4030
4143
  VALUE query_format, query;
4031
4144
 
4145
+ rb_check_frozen(self);
4032
4146
  Check_Type(encname, T_STRING);
4033
4147
  query_format = rb_str_new_cstr("set client_encoding to '%s'");
4034
4148
  query = rb_funcall(query_format, rb_intern("%"), 1, encname);
@@ -4078,15 +4192,23 @@ static VALUE
4078
4192
  pgconn_set_default_encoding( VALUE self )
4079
4193
  {
4080
4194
  PGconn *conn = pg_get_pgconn( self );
4081
- rb_encoding *enc;
4082
- const char *encname;
4083
-
4084
- if (( enc = rb_default_internal_encoding() )) {
4085
- encname = pg_get_rb_encoding_as_pg_encoding( enc );
4086
- if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4087
- rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4088
- encname, PQerrorMessage(conn) );
4089
- return rb_enc_from_encoding( enc );
4195
+ rb_encoding *rb_enc;
4196
+
4197
+ rb_check_frozen(self);
4198
+ if (( rb_enc = rb_default_internal_encoding() )) {
4199
+ rb_encoding * conn_encoding = pg_conn_enc_get( conn );
4200
+
4201
+ /* Don't set the server encoding, if it's unnecessary.
4202
+ * This is important for connection proxies, who disallow configuration settings.
4203
+ */
4204
+ if ( conn_encoding != rb_enc ) {
4205
+ const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
4206
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4207
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4208
+ encname, PQerrorMessage(conn) );
4209
+ }
4210
+ pgconn_set_internal_encoding_index( self );
4211
+ return rb_enc_from_encoding( rb_enc );
4090
4212
  } else {
4091
4213
  pgconn_set_internal_encoding_index( self );
4092
4214
  return Qnil;
@@ -4110,10 +4232,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4110
4232
  t_typemap *tm;
4111
4233
  UNUSED(tm);
4112
4234
 
4235
+ rb_check_frozen(self);
4113
4236
  /* Check type of method param */
4114
4237
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4115
4238
 
4116
- this->type_map_for_queries = typemap;
4239
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
4117
4240
 
4118
4241
  return typemap;
4119
4242
  }
@@ -4150,8 +4273,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4150
4273
  t_typemap *tm;
4151
4274
  UNUSED(tm);
4152
4275
 
4276
+ rb_check_frozen(self);
4153
4277
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4154
- this->type_map_for_results = typemap;
4278
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
4155
4279
 
4156
4280
  return typemap;
4157
4281
  }
@@ -4189,13 +4313,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4189
4313
  {
4190
4314
  t_pg_connection *this = pg_get_connection( self );
4191
4315
 
4316
+ rb_check_frozen(self);
4192
4317
  if( encoder != Qnil ){
4193
4318
  t_pg_coder *co;
4194
4319
  UNUSED(co);
4195
4320
  /* Check argument type */
4196
4321
  TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4197
4322
  }
4198
- this->encoder_for_put_copy_data = encoder;
4323
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4199
4324
 
4200
4325
  return encoder;
4201
4326
  }
@@ -4237,13 +4362,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4237
4362
  {
4238
4363
  t_pg_connection *this = pg_get_connection( self );
4239
4364
 
4365
+ rb_check_frozen(self);
4240
4366
  if( decoder != Qnil ){
4241
4367
  t_pg_coder *co;
4242
4368
  UNUSED(co);
4243
4369
  /* Check argument type */
4244
4370
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4245
4371
  }
4246
- this->decoder_for_get_copy_data = decoder;
4372
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4247
4373
 
4248
4374
  return decoder;
4249
4375
  }
@@ -4289,6 +4415,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4289
4415
  {
4290
4416
  t_pg_connection *this = pg_get_connection( self );
4291
4417
 
4418
+ rb_check_frozen(self);
4292
4419
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4293
4420
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4294
4421
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
@@ -4325,7 +4452,7 @@ pgconn_field_name_type_get(VALUE self)
4325
4452
  * Document-class: PG::Connection
4326
4453
  */
4327
4454
  void
4328
- init_pg_connection()
4455
+ init_pg_connection(void)
4329
4456
  {
4330
4457
  s_id_encode = rb_intern("encode");
4331
4458
  s_id_autoclose_set = rb_intern("autoclose=");
@@ -4362,6 +4489,7 @@ init_pg_connection()
4362
4489
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4363
4490
  rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4364
4491
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4492
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
4365
4493
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4366
4494
  rb_define_alias(rb_cPGconn, "close", "finish");
4367
4495