pg 1.4.4 → 1.5.9

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 (77) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +6 -0
  4. data/{History.rdoc → History.md} +303 -151
  5. data/README.ja.md +300 -0
  6. data/README.md +286 -0
  7. data/Rakefile +16 -4
  8. data/Rakefile.cross +15 -14
  9. data/certs/kanis@comcard.de.pem +20 -0
  10. data/certs/larskanis-2023.pem +24 -0
  11. data/certs/larskanis-2024.pem +24 -0
  12. data/ext/errorcodes.def +8 -5
  13. data/ext/errorcodes.txt +3 -5
  14. data/ext/extconf.rb +7 -0
  15. data/ext/pg.c +15 -30
  16. data/ext/pg.h +10 -6
  17. data/ext/pg_binary_decoder.c +81 -0
  18. data/ext/pg_binary_encoder.c +224 -0
  19. data/ext/pg_coder.c +16 -7
  20. data/ext/pg_connection.c +220 -82
  21. data/ext/pg_copy_coder.c +315 -22
  22. data/ext/pg_record_coder.c +11 -10
  23. data/ext/pg_result.c +93 -19
  24. data/ext/pg_text_decoder.c +31 -10
  25. data/ext/pg_text_encoder.c +38 -19
  26. data/ext/pg_tuple.c +34 -31
  27. data/ext/pg_type_map.c +3 -2
  28. data/ext/pg_type_map_all_strings.c +2 -2
  29. data/ext/pg_type_map_by_class.c +5 -3
  30. data/ext/pg_type_map_by_column.c +7 -3
  31. data/ext/pg_type_map_by_oid.c +7 -4
  32. data/ext/pg_type_map_in_ruby.c +5 -2
  33. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  34. data/lib/pg/basic_type_map_for_queries.rb +19 -10
  35. data/lib/pg/basic_type_map_for_results.rb +26 -3
  36. data/lib/pg/basic_type_registry.rb +44 -34
  37. data/lib/pg/binary_decoder/date.rb +9 -0
  38. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  39. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  40. data/lib/pg/coder.rb +15 -13
  41. data/lib/pg/connection.rb +158 -64
  42. data/lib/pg/exceptions.rb +13 -0
  43. data/lib/pg/text_decoder/date.rb +21 -0
  44. data/lib/pg/text_decoder/inet.rb +9 -0
  45. data/lib/pg/text_decoder/json.rb +17 -0
  46. data/lib/pg/text_decoder/numeric.rb +9 -0
  47. data/lib/pg/text_decoder/timestamp.rb +30 -0
  48. data/lib/pg/text_encoder/date.rb +13 -0
  49. data/lib/pg/text_encoder/inet.rb +31 -0
  50. data/lib/pg/text_encoder/json.rb +17 -0
  51. data/lib/pg/text_encoder/numeric.rb +9 -0
  52. data/lib/pg/text_encoder/timestamp.rb +24 -0
  53. data/lib/pg/version.rb +1 -1
  54. data/lib/pg.rb +65 -15
  55. data/pg.gemspec +7 -3
  56. data/rakelib/task_extension.rb +1 -1
  57. data.tar.gz.sig +2 -4
  58. metadata +104 -46
  59. metadata.gz.sig +0 -0
  60. data/.appveyor.yml +0 -36
  61. data/.gems +0 -6
  62. data/.gemtest +0 -0
  63. data/.github/workflows/binary-gems.yml +0 -86
  64. data/.github/workflows/source-gem.yml +0 -131
  65. data/.gitignore +0 -13
  66. data/.hgsigs +0 -34
  67. data/.hgtags +0 -41
  68. data/.irbrc +0 -23
  69. data/.pryrc +0 -23
  70. data/.tm_properties +0 -21
  71. data/.travis.yml +0 -49
  72. data/README.ja.rdoc +0 -13
  73. data/README.rdoc +0 -233
  74. data/lib/pg/binary_decoder.rb +0 -23
  75. data/lib/pg/constants.rb +0 -12
  76. data/lib/pg/text_decoder.rb +0 -46
  77. 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 );
@@ -36,8 +33,8 @@ static VALUE pgconn_async_flush(VALUE self);
36
33
  #ifdef __GNUC__
37
34
  __attribute__((format(printf, 3, 4)))
38
35
  #endif
39
- static void
40
- pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
36
+ NORETURN( static void
37
+ pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...))
41
38
  {
42
39
  VALUE msg, error;
43
40
  va_list ap;
@@ -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,15 +255,16 @@ 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));
267
+ rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
270
268
 
271
269
  return self;
272
270
  }
@@ -518,9 +516,9 @@ static VALUE
518
516
  pgconn_connect_poll(VALUE self)
519
517
  {
520
518
  PostgresPollingStatusType status;
521
- status = gvl_PQconnectPoll(pg_get_pgconn(self));
522
519
 
523
520
  pgconn_close_socket_io(self);
521
+ status = gvl_PQconnectPoll(pg_get_pgconn(self));
524
522
 
525
523
  return INT2FIX((int)status);
526
524
  }
@@ -566,6 +564,27 @@ pgconn_sync_reset( VALUE self )
566
564
  return self;
567
565
  }
568
566
 
567
+ static VALUE
568
+ pgconn_reset_start2( VALUE self, VALUE conninfo )
569
+ {
570
+ t_pg_connection *this = pg_get_connection( self );
571
+
572
+ /* Close old connection */
573
+ pgconn_close_socket_io( self );
574
+ PQfinish( this->pgconn );
575
+
576
+ /* Start new connection */
577
+ this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
578
+
579
+ if( this->pgconn == NULL )
580
+ rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
581
+
582
+ if ( PQstatus(this->pgconn) == CONNECTION_BAD )
583
+ pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
584
+
585
+ return Qnil;
586
+ }
587
+
569
588
  /*
570
589
  * call-seq:
571
590
  * conn.reset_start() -> nil
@@ -597,9 +616,9 @@ static VALUE
597
616
  pgconn_reset_poll(VALUE self)
598
617
  {
599
618
  PostgresPollingStatusType status;
600
- status = gvl_PQresetPoll(pg_get_pgconn(self));
601
619
 
602
620
  pgconn_close_socket_io(self);
621
+ status = gvl_PQresetPoll(pg_get_pgconn(self));
603
622
 
604
623
  return INT2FIX((int)status);
605
624
  }
@@ -702,7 +721,10 @@ static VALUE
702
721
  pgconn_port(VALUE self)
703
722
  {
704
723
  char* port = PQport(pg_get_pgconn(self));
705
- return INT2NUM(atoi(port));
724
+ if (!port || port[0] == '\0')
725
+ return INT2NUM(DEF_PGPORT);
726
+ else
727
+ return INT2NUM(atoi(port));
706
728
  }
707
729
 
708
730
  /*
@@ -763,6 +785,10 @@ pgconn_conninfo( VALUE self )
763
785
  *
764
786
  * ... and other constants of kind PG::Constants::CONNECTION_*
765
787
  *
788
+ * This method returns the status of the last command from memory.
789
+ * It doesn't do any socket access hence is not suitable to test the connectivity.
790
+ * See check_socket for a way to verify the socket state.
791
+ *
766
792
  * Example:
767
793
  * PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
768
794
  */
@@ -938,7 +964,7 @@ pgconn_socket_io(VALUE self)
938
964
  /* Disable autoclose feature */
939
965
  rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
940
966
 
941
- this->socket_io = socket_io;
967
+ RB_OBJ_WRITE(self, &this->socket_io, socket_io);
942
968
  }
943
969
 
944
970
  return socket_io;
@@ -1155,7 +1181,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
1155
1181
  },
1156
1182
  0,
1157
1183
  0,
1158
- RUBY_TYPED_FREE_IMMEDIATELY,
1184
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1159
1185
  };
1160
1186
 
1161
1187
  static char *
@@ -1188,7 +1214,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
1188
1214
  },
1189
1215
  0,
1190
1216
  0,
1191
- RUBY_TYPED_FREE_IMMEDIATELY,
1217
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1192
1218
  };
1193
1219
 
1194
1220
  static int
@@ -1811,6 +1837,7 @@ pgconn_set_single_row_mode(VALUE self)
1811
1837
  {
1812
1838
  PGconn *conn = pg_get_pgconn(self);
1813
1839
 
1840
+ rb_check_frozen(self);
1814
1841
  if( PQsetSingleRowMode(conn) == 0 )
1815
1842
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
1816
1843
 
@@ -2145,6 +2172,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
2145
2172
  {
2146
2173
  int arg;
2147
2174
  PGconn *conn = pg_get_pgconn(self);
2175
+ rb_check_frozen(self);
2148
2176
  if(state == Qtrue)
2149
2177
  arg = 1;
2150
2178
  else if (state == Qfalse)
@@ -2239,6 +2267,17 @@ pgconn_notifies(VALUE self)
2239
2267
  return hash;
2240
2268
  }
2241
2269
 
2270
+ #ifndef HAVE_RB_IO_DESCRIPTOR
2271
+ static int
2272
+ rb_io_descriptor(VALUE io)
2273
+ {
2274
+ Check_Type(io, T_FILE);
2275
+ rb_io_t *fptr = RFILE(io)->fptr;
2276
+ rb_io_check_closed(fptr);
2277
+ return fptr->fd;
2278
+ }
2279
+ #endif
2280
+
2242
2281
  #if defined(_WIN32)
2243
2282
 
2244
2283
  /* We use a specialized implementation of rb_io_wait() on Windows.
@@ -2259,7 +2298,6 @@ int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
2259
2298
 
2260
2299
  static VALUE
2261
2300
  pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2262
- rb_io_t *fptr;
2263
2301
  struct timeval ptimeout;
2264
2302
 
2265
2303
  struct timeval aborttime={0,0}, currtime, waittime;
@@ -2270,7 +2308,6 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2270
2308
  long w32_events = 0;
2271
2309
  DWORD wait_ret;
2272
2310
 
2273
- GetOpenFile((io), fptr);
2274
2311
  if( !NIL_P(timeout) ){
2275
2312
  ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
2276
2313
  ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
@@ -2284,7 +2321,7 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
2284
2321
  if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
2285
2322
 
2286
2323
  for(;;) {
2287
- if ( WSAEventSelect(_get_osfhandle(fptr->fd), hEvent, w32_events) == SOCKET_ERROR ) {
2324
+ if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
2288
2325
  WSACloseEvent( hEvent );
2289
2326
  rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
2290
2327
  }
@@ -2327,7 +2364,7 @@ static VALUE
2327
2364
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2328
2365
  #if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
2329
2366
  /* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
2330
- * Fortunatelly ruby-3.1 offers a C-API for it.
2367
+ * Fortunately ruby-3.1 offers a C-API for it.
2331
2368
  */
2332
2369
  VALUE scheduler = rb_fiber_scheduler_current();
2333
2370
 
@@ -2357,16 +2394,14 @@ typedef enum {
2357
2394
 
2358
2395
  static VALUE
2359
2396
  pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
2360
- rb_io_t *fptr;
2361
2397
  struct timeval waittime;
2362
2398
  int res;
2363
2399
 
2364
- GetOpenFile((io), fptr);
2365
2400
  if( !NIL_P(timeout) ){
2366
2401
  waittime.tv_sec = (time_t)(NUM2DBL(timeout));
2367
2402
  waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
2368
2403
  }
2369
- res = rb_wait_for_single_fd(fptr->fd, NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2404
+ res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
2370
2405
 
2371
2406
  return UINT2NUM(res);
2372
2407
  }
@@ -2443,8 +2478,9 @@ pgconn_async_flush(VALUE self)
2443
2478
  VALUE socket_io = pgconn_socket_io(self);
2444
2479
  events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
2445
2480
 
2446
- if (events & PG_RUBY_IO_READABLE)
2481
+ if (events & PG_RUBY_IO_READABLE){
2447
2482
  pgconn_consume_input(self);
2483
+ }
2448
2484
  }
2449
2485
  return Qtrue;
2450
2486
  }
@@ -2460,6 +2496,7 @@ pgconn_wait_for_flush( VALUE self ){
2460
2496
  static VALUE
2461
2497
  pgconn_flush_data_set( VALUE self, VALUE enabled ){
2462
2498
  t_pg_connection *conn = pg_get_connection(self);
2499
+ rb_check_frozen(self);
2463
2500
  conn->flush_data = RTEST(enabled);
2464
2501
  return enabled;
2465
2502
  }
@@ -2714,6 +2751,7 @@ pgconn_trace(VALUE self, VALUE stream)
2714
2751
  VALUE new_file;
2715
2752
  t_pg_connection *this = pg_get_connection_safe( self );
2716
2753
 
2754
+ rb_check_frozen(self);
2717
2755
  if(!rb_respond_to(stream,rb_intern("fileno")))
2718
2756
  rb_raise(rb_eArgError, "stream does not respond to method: fileno");
2719
2757
 
@@ -2735,7 +2773,7 @@ pgconn_trace(VALUE self, VALUE stream)
2735
2773
  rb_raise(rb_eArgError, "stream is not writable");
2736
2774
 
2737
2775
  new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
2738
- this->trace_stream = new_file;
2776
+ RB_OBJ_WRITE(self, &this->trace_stream, new_file);
2739
2777
 
2740
2778
  PQtrace(this->pgconn, new_fp);
2741
2779
  return Qnil;
@@ -2754,7 +2792,7 @@ pgconn_untrace(VALUE self)
2754
2792
 
2755
2793
  PQuntrace(this->pgconn);
2756
2794
  rb_funcall(this->trace_stream, rb_intern("close"), 0);
2757
- this->trace_stream = Qnil;
2795
+ RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
2758
2796
  return Qnil;
2759
2797
  }
2760
2798
 
@@ -2813,13 +2851,14 @@ pgconn_set_notice_receiver(VALUE self)
2813
2851
  VALUE proc, old_proc;
2814
2852
  t_pg_connection *this = pg_get_connection_safe( self );
2815
2853
 
2854
+ rb_check_frozen(self);
2816
2855
  /* If default_notice_receiver is unset, assume that the current
2817
2856
  * notice receiver is the default, and save it to a global variable.
2818
2857
  * This should not be a problem because the default receiver is
2819
2858
  * always the same, so won't vary among connections.
2820
2859
  */
2821
- if(default_notice_receiver == NULL)
2822
- default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2860
+ if(this->default_notice_receiver == NULL)
2861
+ this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
2823
2862
 
2824
2863
  old_proc = this->notice_receiver;
2825
2864
  if( rb_block_given_p() ) {
@@ -2828,10 +2867,10 @@ pgconn_set_notice_receiver(VALUE self)
2828
2867
  } else {
2829
2868
  /* if no block is given, set back to default */
2830
2869
  proc = Qnil;
2831
- PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
2870
+ PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
2832
2871
  }
2833
2872
 
2834
- this->notice_receiver = proc;
2873
+ RB_OBJ_WRITE(self, &this->notice_receiver, proc);
2835
2874
  return old_proc;
2836
2875
  }
2837
2876
 
@@ -2846,10 +2885,10 @@ notice_processor_proxy(void *arg, const char *message)
2846
2885
  VALUE self = (VALUE)arg;
2847
2886
  t_pg_connection *this = pg_get_connection( self );
2848
2887
 
2849
- if (this->notice_receiver != Qnil) {
2888
+ if (this->notice_processor != Qnil) {
2850
2889
  VALUE message_str = rb_str_new2(message);
2851
2890
  PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
2852
- rb_funcall(this->notice_receiver, rb_intern("call"), 1, message_str);
2891
+ rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
2853
2892
  }
2854
2893
  return;
2855
2894
  }
@@ -2873,25 +2912,26 @@ pgconn_set_notice_processor(VALUE self)
2873
2912
  VALUE proc, old_proc;
2874
2913
  t_pg_connection *this = pg_get_connection_safe( self );
2875
2914
 
2915
+ rb_check_frozen(self);
2876
2916
  /* If default_notice_processor is unset, assume that the current
2877
2917
  * notice processor is the default, and save it to a global variable.
2878
2918
  * This should not be a problem because the default processor is
2879
2919
  * always the same, so won't vary among connections.
2880
2920
  */
2881
- if(default_notice_processor == NULL)
2882
- default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2921
+ if(this->default_notice_processor == NULL)
2922
+ this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
2883
2923
 
2884
- old_proc = this->notice_receiver;
2924
+ old_proc = this->notice_processor;
2885
2925
  if( rb_block_given_p() ) {
2886
2926
  proc = rb_block_proc();
2887
2927
  PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
2888
2928
  } else {
2889
2929
  /* if no block is given, set back to default */
2890
2930
  proc = Qnil;
2891
- PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
2931
+ PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
2892
2932
  }
2893
2933
 
2894
- this->notice_receiver = proc;
2934
+ RB_OBJ_WRITE(self, &this->notice_processor, proc);
2895
2935
  return old_proc;
2896
2936
  }
2897
2937
 
@@ -2923,6 +2963,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
2923
2963
  {
2924
2964
  PGconn *conn = pg_get_pgconn( self );
2925
2965
 
2966
+ rb_check_frozen(self);
2926
2967
  Check_Type(str, T_STRING);
2927
2968
 
2928
2969
  if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
@@ -3091,11 +3132,13 @@ pgconn_async_get_last_result(VALUE self)
3091
3132
  VALUE rb_pgresult = Qnil;
3092
3133
  PGresult *cur, *prev;
3093
3134
 
3094
- cur = prev = NULL;
3135
+ cur = prev = NULL;
3095
3136
  for(;;) {
3096
3137
  int status;
3097
3138
 
3098
- /* wait for input (without blocking) before reading each result */
3139
+ /* Wait for input before reading each result.
3140
+ * That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
3141
+ */
3099
3142
  wait_socket_readable(self, NULL, get_result_readable);
3100
3143
 
3101
3144
  cur = gvl_PQgetResult(conn);
@@ -3123,8 +3166,14 @@ pgconn_async_get_last_result(VALUE self)
3123
3166
  * conn.discard_results()
3124
3167
  *
3125
3168
  * 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.
3169
+ * This is internally used prior to Connection#exec and sibling methods.
3170
+ * It doesn't raise an exception on connection errors, but returns +false+ instead.
3171
+ *
3172
+ * Returns:
3173
+ * * +nil+ when the connection is already idle
3174
+ * * +true+ when some results have been discarded
3175
+ * * +false+ when a failure occurred and the connection was closed
3176
+ *
3128
3177
  */
3129
3178
  static VALUE
3130
3179
  pgconn_discard_results(VALUE self)
@@ -3132,8 +3181,12 @@ pgconn_discard_results(VALUE self)
3132
3181
  PGconn *conn = pg_get_pgconn(self);
3133
3182
  VALUE socket_io;
3134
3183
 
3135
- if( PQtransactionStatus(conn) == PQTRANS_IDLE ) {
3136
- return Qnil;
3184
+ switch( PQtransactionStatus(conn) ) {
3185
+ case PQTRANS_IDLE:
3186
+ case PQTRANS_INTRANS:
3187
+ case PQTRANS_INERROR:
3188
+ return Qnil;
3189
+ default:;
3137
3190
  }
3138
3191
 
3139
3192
  socket_io = pgconn_socket_io(self);
@@ -3146,10 +3199,21 @@ pgconn_discard_results(VALUE self)
3146
3199
  * To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
3147
3200
  */
3148
3201
  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;
3202
+ int events;
3203
+
3204
+ switch( PQflush(conn) ) {
3205
+ case 1:
3206
+ events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
3207
+ if (events & PG_RUBY_IO_READABLE){
3208
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3209
+ }
3210
+ break;
3211
+ case 0:
3212
+ pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
3213
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3214
+ break;
3215
+ default:
3216
+ goto error;
3153
3217
  }
3154
3218
  }
3155
3219
 
@@ -3159,7 +3223,9 @@ pgconn_discard_results(VALUE self)
3159
3223
  status = PQresultStatus(cur);
3160
3224
  PQclear(cur);
3161
3225
  if (status == PGRES_COPY_IN){
3162
- gvl_PQputCopyEnd(conn, "COPY terminated by new PQexec");
3226
+ while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
3227
+ pgconn_async_flush(self);
3228
+ }
3163
3229
  }
3164
3230
  if (status == PGRES_COPY_OUT){
3165
3231
  for(;;) {
@@ -3168,10 +3234,7 @@ pgconn_discard_results(VALUE self)
3168
3234
  if( st == 0 ) {
3169
3235
  /* would block -> wait for readable data */
3170
3236
  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
- }
3237
+ if ( PQconsumeInput(conn) == 0 ) goto error;
3175
3238
  } else if( st > 0 ) {
3176
3239
  /* some data retrieved -> discard it */
3177
3240
  PQfreemem(buffer);
@@ -3184,6 +3247,10 @@ pgconn_discard_results(VALUE self)
3184
3247
  }
3185
3248
 
3186
3249
  return Qtrue;
3250
+
3251
+ error:
3252
+ pgconn_close_socket_io(self);
3253
+ return Qfalse;
3187
3254
  }
3188
3255
 
3189
3256
  /*
@@ -3640,6 +3707,14 @@ pgconn_send_flush_request(VALUE self)
3640
3707
  * LARGE OBJECT SUPPORT
3641
3708
  **************************************************************************/
3642
3709
 
3710
+ #define BLOCKING_BEGIN(conn) do { \
3711
+ int old_nonblocking = PQisnonblocking(conn); \
3712
+ PQsetnonblocking(conn, 0);
3713
+
3714
+ #define BLOCKING_END(th) \
3715
+ PQsetnonblocking(conn, old_nonblocking); \
3716
+ } while(0);
3717
+
3643
3718
  /*
3644
3719
  * call-seq:
3645
3720
  * conn.lo_creat( [mode] ) -> Integer
@@ -3660,7 +3735,10 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
3660
3735
  else
3661
3736
  mode = NUM2INT(nmode);
3662
3737
 
3663
- lo_oid = lo_creat(conn, mode);
3738
+ BLOCKING_BEGIN(conn)
3739
+ lo_oid = lo_creat(conn, mode);
3740
+ BLOCKING_END(conn)
3741
+
3664
3742
  if (lo_oid == 0)
3665
3743
  pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
3666
3744
 
@@ -3705,7 +3783,10 @@ pgconn_loimport(VALUE self, VALUE filename)
3705
3783
 
3706
3784
  Check_Type(filename, T_STRING);
3707
3785
 
3708
- lo_oid = lo_import(conn, StringValueCStr(filename));
3786
+ BLOCKING_BEGIN(conn)
3787
+ lo_oid = lo_import(conn, StringValueCStr(filename));
3788
+ BLOCKING_END(conn)
3789
+
3709
3790
  if (lo_oid == 0) {
3710
3791
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3711
3792
  }
@@ -3723,11 +3804,16 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
3723
3804
  {
3724
3805
  PGconn *conn = pg_get_pgconn(self);
3725
3806
  Oid oid;
3807
+ int ret;
3726
3808
  Check_Type(filename, T_STRING);
3727
3809
 
3728
3810
  oid = NUM2UINT(lo_oid);
3729
3811
 
3730
- if (lo_export(conn, oid, StringValueCStr(filename)) < 0) {
3812
+ BLOCKING_BEGIN(conn)
3813
+ ret = lo_export(conn, oid, StringValueCStr(filename));
3814
+ BLOCKING_END(conn)
3815
+
3816
+ if (ret < 0) {
3731
3817
  pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
3732
3818
  }
3733
3819
  return Qnil;
@@ -3758,7 +3844,11 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
3758
3844
  else
3759
3845
  mode = NUM2INT(nmode);
3760
3846
 
3761
- if((fd = lo_open(conn, lo_oid, mode)) < 0) {
3847
+ BLOCKING_BEGIN(conn)
3848
+ fd = lo_open(conn, lo_oid, mode);
3849
+ BLOCKING_END(conn)
3850
+
3851
+ if(fd < 0) {
3762
3852
  pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
3763
3853
  }
3764
3854
  return INT2FIX(fd);
@@ -3783,8 +3873,12 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
3783
3873
  if( RSTRING_LEN(buffer) < 0) {
3784
3874
  pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
3785
3875
  }
3786
- if((n = lo_write(conn, fd, StringValuePtr(buffer),
3787
- RSTRING_LEN(buffer))) < 0) {
3876
+ BLOCKING_BEGIN(conn)
3877
+ n = lo_write(conn, fd, StringValuePtr(buffer),
3878
+ RSTRING_LEN(buffer));
3879
+ BLOCKING_END(conn)
3880
+
3881
+ if(n < 0) {
3788
3882
  pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
3789
3883
  }
3790
3884
 
@@ -3812,7 +3906,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
3812
3906
  pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
3813
3907
 
3814
3908
  buffer = ALLOC_N(char, len);
3815
- if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
3909
+
3910
+ BLOCKING_BEGIN(conn)
3911
+ ret = lo_read(conn, lo_desc, buffer, len);
3912
+ BLOCKING_END(conn)
3913
+
3914
+ if(ret < 0)
3816
3915
  pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
3817
3916
 
3818
3917
  if(ret == 0) {
@@ -3842,7 +3941,11 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
3842
3941
  int lo_desc = NUM2INT(in_lo_desc);
3843
3942
  int ret;
3844
3943
 
3845
- if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
3944
+ BLOCKING_BEGIN(conn)
3945
+ ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
3946
+ BLOCKING_END(conn)
3947
+
3948
+ if(ret < 0) {
3846
3949
  pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
3847
3950
  }
3848
3951
 
@@ -3862,7 +3965,11 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
3862
3965
  PGconn *conn = pg_get_pgconn(self);
3863
3966
  int lo_desc = NUM2INT(in_lo_desc);
3864
3967
 
3865
- if((position = lo_tell(conn, lo_desc)) < 0)
3968
+ BLOCKING_BEGIN(conn)
3969
+ position = lo_tell(conn, lo_desc);
3970
+ BLOCKING_END(conn)
3971
+
3972
+ if(position < 0)
3866
3973
  pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
3867
3974
 
3868
3975
  return INT2FIX(position);
@@ -3880,8 +3987,13 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
3880
3987
  PGconn *conn = pg_get_pgconn(self);
3881
3988
  int lo_desc = NUM2INT(in_lo_desc);
3882
3989
  size_t len = NUM2INT(in_len);
3990
+ int ret;
3883
3991
 
3884
- if(lo_truncate(conn,lo_desc,len) < 0)
3992
+ BLOCKING_BEGIN(conn)
3993
+ ret = lo_truncate(conn,lo_desc,len);
3994
+ BLOCKING_END(conn)
3995
+
3996
+ if(ret < 0)
3885
3997
  pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
3886
3998
 
3887
3999
  return Qnil;
@@ -3898,8 +4010,13 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
3898
4010
  {
3899
4011
  PGconn *conn = pg_get_pgconn(self);
3900
4012
  int lo_desc = NUM2INT(in_lo_desc);
4013
+ int ret;
3901
4014
 
3902
- if(lo_close(conn,lo_desc) < 0)
4015
+ BLOCKING_BEGIN(conn)
4016
+ ret = lo_close(conn,lo_desc);
4017
+ BLOCKING_END(conn)
4018
+
4019
+ if(ret < 0)
3903
4020
  pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
3904
4021
 
3905
4022
  return Qnil;
@@ -3916,8 +4033,13 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
3916
4033
  {
3917
4034
  PGconn *conn = pg_get_pgconn(self);
3918
4035
  Oid oid = NUM2UINT(in_oid);
4036
+ int ret;
3919
4037
 
3920
- if(lo_unlink(conn,oid) < 0)
4038
+ BLOCKING_BEGIN(conn)
4039
+ ret = lo_unlink(conn,oid);
4040
+ BLOCKING_END(conn)
4041
+
4042
+ if(ret < 0)
3921
4043
  pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
3922
4044
 
3923
4045
  return Qnil;
@@ -3975,6 +4097,7 @@ static VALUE pgconn_external_encoding(VALUE self);
3975
4097
  static VALUE
3976
4098
  pgconn_internal_encoding_set(VALUE self, VALUE enc)
3977
4099
  {
4100
+ rb_check_frozen(self);
3978
4101
  if (NIL_P(enc)) {
3979
4102
  pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
3980
4103
  return enc;
@@ -4029,6 +4152,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
4029
4152
  {
4030
4153
  VALUE query_format, query;
4031
4154
 
4155
+ rb_check_frozen(self);
4032
4156
  Check_Type(encname, T_STRING);
4033
4157
  query_format = rb_str_new_cstr("set client_encoding to '%s'");
4034
4158
  query = rb_funcall(query_format, rb_intern("%"), 1, encname);
@@ -4078,15 +4202,23 @@ static VALUE
4078
4202
  pgconn_set_default_encoding( VALUE self )
4079
4203
  {
4080
4204
  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 );
4205
+ rb_encoding *rb_enc;
4206
+
4207
+ rb_check_frozen(self);
4208
+ if (( rb_enc = rb_default_internal_encoding() )) {
4209
+ rb_encoding * conn_encoding = pg_conn_enc_get( conn );
4210
+
4211
+ /* Don't set the server encoding, if it's unnecessary.
4212
+ * This is important for connection proxies, who disallow configuration settings.
4213
+ */
4214
+ if ( conn_encoding != rb_enc ) {
4215
+ const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
4216
+ if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
4217
+ rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
4218
+ encname, PQerrorMessage(conn) );
4219
+ }
4220
+ pgconn_set_internal_encoding_index( self );
4221
+ return rb_enc_from_encoding( rb_enc );
4090
4222
  } else {
4091
4223
  pgconn_set_internal_encoding_index( self );
4092
4224
  return Qnil;
@@ -4110,10 +4242,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
4110
4242
  t_typemap *tm;
4111
4243
  UNUSED(tm);
4112
4244
 
4245
+ rb_check_frozen(self);
4113
4246
  /* Check type of method param */
4114
4247
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4115
4248
 
4116
- this->type_map_for_queries = typemap;
4249
+ RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
4117
4250
 
4118
4251
  return typemap;
4119
4252
  }
@@ -4150,8 +4283,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
4150
4283
  t_typemap *tm;
4151
4284
  UNUSED(tm);
4152
4285
 
4286
+ rb_check_frozen(self);
4153
4287
  TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
4154
- this->type_map_for_results = typemap;
4288
+ RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
4155
4289
 
4156
4290
  return typemap;
4157
4291
  }
@@ -4189,13 +4323,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
4189
4323
  {
4190
4324
  t_pg_connection *this = pg_get_connection( self );
4191
4325
 
4326
+ rb_check_frozen(self);
4192
4327
  if( encoder != Qnil ){
4193
4328
  t_pg_coder *co;
4194
4329
  UNUSED(co);
4195
4330
  /* Check argument type */
4196
4331
  TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
4197
4332
  }
4198
- this->encoder_for_put_copy_data = encoder;
4333
+ RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
4199
4334
 
4200
4335
  return encoder;
4201
4336
  }
@@ -4237,13 +4372,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
4237
4372
  {
4238
4373
  t_pg_connection *this = pg_get_connection( self );
4239
4374
 
4375
+ rb_check_frozen(self);
4240
4376
  if( decoder != Qnil ){
4241
4377
  t_pg_coder *co;
4242
4378
  UNUSED(co);
4243
4379
  /* Check argument type */
4244
4380
  TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
4245
4381
  }
4246
- this->decoder_for_get_copy_data = decoder;
4382
+ RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
4247
4383
 
4248
4384
  return decoder;
4249
4385
  }
@@ -4289,6 +4425,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
4289
4425
  {
4290
4426
  t_pg_connection *this = pg_get_connection( self );
4291
4427
 
4428
+ rb_check_frozen(self);
4292
4429
  this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
4293
4430
  if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
4294
4431
  else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
@@ -4362,6 +4499,7 @@ init_pg_connection(void)
4362
4499
  rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
4363
4500
  rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
4364
4501
  rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
4502
+ rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
4365
4503
  rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
4366
4504
  rb_define_alias(rb_cPGconn, "close", "finish");
4367
4505