pg 1.5.9-x64-mingw32 → 1.6.0.rc1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/ext/pg_copy_coder.c CHANGED
@@ -51,7 +51,7 @@ static const rb_data_type_t pg_copycoder_type = {
51
51
  pg_copycoder_mark,
52
52
  RUBY_TYPED_DEFAULT_FREE,
53
53
  pg_copycoder_memsize,
54
- pg_compact_callback(pg_copycoder_compact),
54
+ pg_copycoder_compact,
55
55
  },
56
56
  &pg_coder_type,
57
57
  0,
@@ -831,7 +831,6 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
831
831
 
832
832
  for( fieldno = 0; fieldno < nfields; fieldno++){
833
833
  long input_len;
834
- VALUE field_value;
835
834
 
836
835
  /* read field size */
837
836
  if (line_end_ptr - cur_ptr < 4 ) goto length_error;
@@ -843,6 +842,7 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl
843
842
  /* NULL indicator */
844
843
  rb_ary_push(array, Qnil);
845
844
  } else {
845
+ VALUE field_value;
846
846
  if (line_end_ptr - cur_ptr < input_len ) goto length_error;
847
847
 
848
848
  /* copy input data to field_str */
@@ -43,7 +43,7 @@ static const rb_data_type_t pg_recordcoder_type = {
43
43
  pg_recordcoder_mark,
44
44
  RUBY_TYPED_DEFAULT_FREE,
45
45
  pg_recordcoder_memsize,
46
- pg_compact_callback(pg_recordcoder_compact),
46
+ pg_recordcoder_compact,
47
47
  },
48
48
  &pg_coder_type,
49
49
  0,
data/ext/pg_result.c CHANGED
@@ -147,9 +147,7 @@ pgresult_clear( void *_this )
147
147
  t_pg_result *this = (t_pg_result *)_this;
148
148
  if( this->pgresult && !this->autoclear ){
149
149
  PQclear(this->pgresult);
150
- #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
151
150
  rb_gc_adjust_memory_usage(-this->result_size);
152
- #endif
153
151
  }
154
152
  this->result_size = 0;
155
153
  this->nfields = -1;
@@ -180,7 +178,7 @@ static const rb_data_type_t pgresult_type = {
180
178
  pgresult_gc_mark,
181
179
  pgresult_gc_free,
182
180
  pgresult_memsize,
183
- pg_compact_callback(pgresult_gc_compact),
181
+ pgresult_gc_compact,
184
182
  },
185
183
  0, 0,
186
184
  RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
@@ -253,9 +251,7 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
253
251
  */
254
252
  this->result_size = pgresult_approx_size(result);
255
253
 
256
- #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
257
254
  rb_gc_adjust_memory_usage(this->result_size);
258
- #endif
259
255
 
260
256
  return self;
261
257
  }
@@ -323,6 +319,9 @@ pg_result_check( VALUE self )
323
319
  case PGRES_COMMAND_OK:
324
320
  #ifdef HAVE_PQENTERPIPELINEMODE
325
321
  case PGRES_PIPELINE_SYNC:
322
+ #endif
323
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
324
+ case PGRES_TUPLES_CHUNK:
326
325
  #endif
327
326
  return self;
328
327
  case PGRES_BAD_RESPONSE:
@@ -549,6 +548,7 @@ static void pgresult_init_fnames(VALUE self)
549
548
  * * +PGRES_FATAL_ERROR+
550
549
  * * +PGRES_COPY_BOTH+
551
550
  * * +PGRES_SINGLE_TUPLE+
551
+ * * +PGRES_TUPLES_CHUNK+
552
552
  * * +PGRES_PIPELINE_SYNC+
553
553
  * * +PGRES_PIPELINE_ABORTED+
554
554
  *
@@ -613,14 +613,12 @@ pgresult_error_message(VALUE self)
613
613
  return ret;
614
614
  }
615
615
 
616
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
617
616
  /*
618
617
  * call-seq:
619
618
  * res.verbose_error_message( verbosity, show_context ) -> String
620
619
  *
621
620
  * Returns a reformatted version of the error message associated with a PGresult object.
622
621
  *
623
- * Available since PostgreSQL-9.6
624
622
  */
625
623
  static VALUE
626
624
  pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
@@ -639,7 +637,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
639
637
 
640
638
  return ret;
641
639
  }
642
- #endif
643
640
 
644
641
  /*
645
642
  * call-seq:
@@ -1528,6 +1525,9 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1528
1525
  return self;
1529
1526
  rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1530
1527
  case PGRES_SINGLE_TUPLE:
1528
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
1529
+ case PGRES_TUPLES_CHUNK:
1530
+ #endif
1531
1531
  break;
1532
1532
  default:
1533
1533
  pg_result_check( self );
@@ -1572,7 +1572,7 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
1572
1572
  * wrapping each row into a dedicated result object, it delivers data in nearly
1573
1573
  * the same speed as with ordinary results.
1574
1574
  *
1575
- * The base result must be in status PGRES_SINGLE_TUPLE.
1575
+ * The base result must be in status PGRES_SINGLE_TUPLE or PGRES_TUPLES_CHUNK.
1576
1576
  * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1577
1577
  * A PG::Error is raised for any errors from the server.
1578
1578
  *
@@ -1707,10 +1707,8 @@ init_pg_result(void)
1707
1707
  rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
1708
1708
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1709
1709
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1710
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1711
1710
  rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1712
1711
  rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1713
- #endif
1714
1712
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1715
1713
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1716
1714
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -231,7 +231,7 @@ pg_text_enc_integer(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
231
231
  *
232
232
  */
233
233
  static int
234
- pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
234
+ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate1, int enc_idx)
235
235
  {
236
236
  if(out){
237
237
  double dvalue = NUM2DBL(value);
@@ -239,7 +239,6 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
239
239
  int neg = 0;
240
240
  int exp2i, exp10i, i;
241
241
  unsigned long long ll, remainder, oldval;
242
- VALUE intermediate;
243
242
 
244
243
  /* Cast to the same strings as value.to_s . */
245
244
  if( isinf(dvalue) ){
@@ -283,6 +282,7 @@ pg_text_enc_float(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
283
282
 
284
283
  if( exp10i <= -5 || exp10i >= 15 ) {
285
284
  /* Write the float in exponent format (1.23e45) */
285
+ VALUE intermediate;
286
286
 
287
287
  /* write fraction digits from right to left */
288
288
  for( i = MAX_DOUBLE_DIGITS; i > 1; i--){
data/ext/pg_tuple.c CHANGED
@@ -125,7 +125,7 @@ static const rb_data_type_t pg_tuple_type = {
125
125
  pg_tuple_gc_mark,
126
126
  pg_tuple_gc_free,
127
127
  pg_tuple_memsize,
128
- pg_compact_callback(pg_tuple_gc_compact),
128
+ pg_tuple_gc_compact,
129
129
  },
130
130
  0, 0,
131
131
  RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
@@ -135,7 +135,7 @@ static const rb_data_type_t pg_tuple_type = {
135
135
  * Document-method: allocate
136
136
  *
137
137
  * call-seq:
138
- * PG::VeryTuple.allocate -> obj
138
+ * PG::Tuple.allocate -> obj
139
139
  */
140
140
  static VALUE
141
141
  pg_tuple_s_allocate( VALUE klass )
data/ext/pg_type_map.c CHANGED
@@ -33,7 +33,7 @@ const rb_data_type_t pg_typemap_type = {
33
33
  pg_typemap_mark,
34
34
  RUBY_TYPED_DEFAULT_FREE,
35
35
  pg_typemap_memsize,
36
- pg_compact_callback(pg_typemap_compact),
36
+ pg_typemap_compact,
37
37
  },
38
38
  0,
39
39
  0,
@@ -14,7 +14,7 @@ static const rb_data_type_t pg_tmas_type = {
14
14
  pg_typemap_mark,
15
15
  RUBY_TYPED_DEFAULT_FREE,
16
16
  pg_typemap_memsize,
17
- pg_compact_callback(pg_typemap_compact),
17
+ pg_typemap_compact,
18
18
  },
19
19
  &pg_typemap_type,
20
20
  0,
@@ -153,7 +153,7 @@ static const rb_data_type_t pg_tmbk_type = {
153
153
  pg_tmbk_mark,
154
154
  RUBY_TYPED_DEFAULT_FREE,
155
155
  pg_tmbk_memsize,
156
- pg_compact_callback(pg_tmbk_compact),
156
+ pg_tmbk_compact,
157
157
  },
158
158
  &pg_typemap_type,
159
159
  0,
@@ -228,7 +228,7 @@ static const rb_data_type_t pg_tmbc_type = {
228
228
  pg_tmbc_mark,
229
229
  pg_tmbc_free,
230
230
  pg_tmbc_memsize,
231
- pg_compact_callback(pg_tmbc_compact),
231
+ pg_tmbc_compact,
232
232
  },
233
233
  &pg_typemap_type,
234
234
  0,
@@ -130,7 +130,7 @@ static const rb_data_type_t pg_tmbmt_type = {
130
130
  pg_tmbmt_mark,
131
131
  RUBY_TYPED_DEFAULT_FREE,
132
132
  pg_tmbmt_memsize,
133
- pg_compact_callback(pg_tmbmt_compact),
133
+ pg_tmbmt_compact,
134
134
  },
135
135
  &pg_typemap_type,
136
136
  0,
@@ -190,7 +190,7 @@ static const rb_data_type_t pg_tmbo_type = {
190
190
  pg_tmbo_mark,
191
191
  RUBY_TYPED_DEFAULT_FREE,
192
192
  pg_tmbo_memsize,
193
- pg_compact_callback(pg_tmbo_compact),
193
+ pg_tmbo_compact,
194
194
  },
195
195
  &pg_typemap_type,
196
196
  0,
@@ -40,7 +40,7 @@ static const rb_data_type_t pg_tmir_type = {
40
40
  pg_typemap_mark,
41
41
  RUBY_TYPED_DEFAULT_FREE,
42
42
  pg_tmir_memsize,
43
- pg_compact_callback(pg_tmir_compact),
43
+ pg_tmir_compact,
44
44
  },
45
45
  &pg_typemap_type,
46
46
  0,
data/lib/2.7/pg_ext.so CHANGED
Binary file
data/lib/3.0/pg_ext.so CHANGED
Binary file
@@ -127,8 +127,8 @@ class PG::BasicTypeRegistry
127
127
  @maps = [
128
128
  [0, :encoder, PG::TextEncoder::Array],
129
129
  [0, :decoder, PG::TextDecoder::Array],
130
- [1, :encoder, nil],
131
- [1, :decoder, nil],
130
+ [1, :encoder, PG::BinaryEncoder::Array],
131
+ [1, :decoder, PG::BinaryDecoder::Array],
132
132
  ].inject([]) do |h, (format, direction, arraycoder)|
133
133
  coders = registry.coders_for(format, direction) || {}
134
134
  h[format] ||= {}
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'pg' unless defined?( PG )
5
+
6
+ if defined?(PG::CancelConnection)
7
+ class PG::CancelConnection
8
+ include PG::Connection::Pollable
9
+
10
+ # The timeout used by #cancel and async_cancel to establish the cancel connection.
11
+ attr_accessor :async_connect_timeout
12
+
13
+ # call-seq:
14
+ # conn.cancel
15
+ #
16
+ # Requests that the server abandons processing of the current command in a blocking manner.
17
+ #
18
+ # If the cancel request wasn't successfully dispatched an error message is raised.
19
+ #
20
+ # Successful dispatch of the cancellation is no guarantee that the request will have any effect, however.
21
+ # If the cancellation is effective, the command being canceled will terminate early and raises an error.
22
+ # If the cancellation fails (say, because the server was already done processing the command), then there will be no visible result at all.
23
+ #
24
+ def cancel
25
+ start
26
+ polling_loop(:poll, async_connect_timeout)
27
+ end
28
+ alias async_cancel cancel
29
+ end
30
+ end
data/lib/pg/connection.rb CHANGED
@@ -356,21 +356,18 @@ class PG::Connection
356
356
  end
357
357
  end
358
358
 
359
- # Method 'ssl_attribute' was introduced in PostgreSQL 9.5.
360
- if self.instance_methods.find{|m| m.to_sym == :ssl_attribute }
361
- # call-seq:
362
- # conn.ssl_attributes -> Hash<String,String>
363
- #
364
- # Returns SSL-related information about the connection as key/value pairs
365
- #
366
- # The available attributes varies depending on the SSL library being used,
367
- # and the type of connection.
368
- #
369
- # See also #ssl_attribute
370
- def ssl_attributes
371
- ssl_attribute_names.each.with_object({}) do |n,h|
372
- h[n] = ssl_attribute(n)
373
- end
359
+ # call-seq:
360
+ # conn.ssl_attributes -> Hash<String,String>
361
+ #
362
+ # Returns SSL-related information about the connection as key/value pairs
363
+ #
364
+ # The available attributes varies depending on the SSL library being used,
365
+ # and the type of connection.
366
+ #
367
+ # See also #ssl_attribute
368
+ def ssl_attributes
369
+ ssl_attribute_names.each.with_object({}) do |n,h|
370
+ h[n] = ssl_attribute(n)
374
371
  end
375
372
  end
376
373
 
@@ -539,6 +536,25 @@ class PG::Connection
539
536
  end
540
537
  alias async_put_copy_end put_copy_end
541
538
 
539
+ if method_defined? :send_pipeline_sync
540
+ # call-seq:
541
+ # conn.pipeline_sync
542
+ #
543
+ # Marks a synchronization point in a pipeline by sending a sync message and flushing the send buffer.
544
+ # This serves as the delimiter of an implicit transaction and an error recovery point.
545
+ #
546
+ # See enter_pipeline_mode
547
+ #
548
+ # Raises PG::Error if the connection is not in pipeline mode or sending a sync message failed.
549
+ #
550
+ # Available since PostgreSQL-14
551
+ def pipeline_sync(*args)
552
+ send_pipeline_sync(*args)
553
+ flush
554
+ end
555
+ alias async_pipeline_sync pipeline_sync
556
+ end
557
+
542
558
  if method_defined? :sync_encrypt_password
543
559
  # call-seq:
544
560
  # conn.encrypt_password( password, username, algorithm=nil ) -> String
@@ -586,128 +602,144 @@ class PG::Connection
586
602
  end
587
603
  alias async_reset reset
588
604
 
589
- # call-seq:
590
- # conn.cancel() -> String
591
- #
592
- # Requests cancellation of the command currently being
593
- # processed.
594
- #
595
- # Returns +nil+ on success, or a string containing the
596
- # error message if a failure occurs.
597
- def cancel
598
- be_pid = backend_pid
599
- be_key = backend_key
600
- cancel_request = [0x10, 1234, 5678, be_pid, be_key].pack("NnnNN")
601
-
602
- if Fiber.respond_to?(:scheduler) && Fiber.scheduler && RUBY_PLATFORM =~ /mingw|mswin/
603
- # Ruby's nonblocking IO is not really supported on Windows.
604
- # We work around by using threads and explicit calls to wait_readable/wait_writable.
605
- cl = Thread.new(socket_io.remote_address) { |ra| ra.connect }.value
606
- begin
607
- cl.write_nonblock(cancel_request)
608
- rescue IO::WaitReadable, Errno::EINTR
609
- cl.wait_writable
610
- retry
611
- end
612
- begin
613
- cl.read_nonblock(1)
614
- rescue IO::WaitReadable, Errno::EINTR
615
- cl.wait_readable
616
- retry
617
- rescue EOFError
618
- end
619
- elsif RUBY_ENGINE == 'truffleruby'
620
- begin
621
- cl = socket_io.remote_address.connect
622
- rescue NotImplementedError
623
- # Workaround for truffleruby < 21.3.0
624
- cl2 = Socket.for_fd(socket_io.fileno)
625
- cl2.autoclose = false
626
- adr = cl2.remote_address
627
- if adr.ip?
628
- cl = TCPSocket.new(adr.ip_address, adr.ip_port)
629
- cl.autoclose = false
630
- else
631
- cl = UNIXSocket.new(adr.unix_path)
632
- cl.autoclose = false
605
+ if defined?(PG::CancelConnection)
606
+ # PostgreSQL-17+
607
+
608
+ def sync_cancel
609
+ cancon = PG::CancelConnection.new(self)
610
+ cancon.sync_cancel
611
+ rescue PG::Error => err
612
+ err.to_s
613
+ end
614
+
615
+ # call-seq:
616
+ # conn.cancel() -> String
617
+ #
618
+ # Requests cancellation of the command currently being
619
+ # processed.
620
+ #
621
+ # Returns +nil+ on success, or a string containing the
622
+ # error message if a failure occurs.
623
+ #
624
+ # On PostgreSQL-17+ client libaray the class PG::CancelConnection is used.
625
+ # On older client library a pure ruby implementation is used.
626
+ def cancel
627
+ cancon = PG::CancelConnection.new(self)
628
+ cancon.async_connect_timeout = conninfo_hash[:connect_timeout]
629
+ cancon.async_cancel
630
+ rescue PG::Error => err
631
+ err.to_s
632
+ end
633
+
634
+ else
635
+
636
+ # PostgreSQL < 17
637
+
638
+ def cancel
639
+ be_pid = backend_pid
640
+ be_key = backend_key
641
+ cancel_request = [0x10, 1234, 5678, be_pid, be_key].pack("NnnNN")
642
+
643
+ if Fiber.respond_to?(:scheduler) && Fiber.scheduler && RUBY_PLATFORM =~ /mingw|mswin/
644
+ # Ruby's nonblocking IO is not really supported on Windows.
645
+ # We work around by using threads and explicit calls to wait_readable/wait_writable.
646
+ cl = Thread.new(socket_io.remote_address) { |ra| ra.connect }.value
647
+ begin
648
+ cl.write_nonblock(cancel_request)
649
+ rescue IO::WaitReadable, Errno::EINTR
650
+ cl.wait_writable
651
+ retry
633
652
  end
653
+ begin
654
+ cl.read_nonblock(1)
655
+ rescue IO::WaitReadable, Errno::EINTR
656
+ cl.wait_readable
657
+ retry
658
+ rescue EOFError
659
+ end
660
+ else
661
+ cl = socket_io.remote_address.connect
662
+ # Send CANCEL_REQUEST_CODE and parameters
663
+ cl.write(cancel_request)
664
+ # Wait for the postmaster to close the connection, which indicates that it's processed the request.
665
+ cl.read(1)
634
666
  end
635
- cl.write(cancel_request)
636
- cl.read(1)
637
- else
638
- cl = socket_io.remote_address.connect
639
- # Send CANCEL_REQUEST_CODE and parameters
640
- cl.write(cancel_request)
641
- # Wait for the postmaster to close the connection, which indicates that it's processed the request.
642
- cl.read(1)
643
- end
644
667
 
645
- cl.close
646
- nil
647
- rescue SystemCallError => err
648
- err.to_s
668
+ cl.close
669
+ nil
670
+ rescue SystemCallError => err
671
+ err.to_s
672
+ end
649
673
  end
650
674
  alias async_cancel cancel
651
675
 
652
- private def async_connect_or_reset(poll_meth)
676
+ module Pollable
653
677
  # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
678
+ private def polling_loop(poll_meth, connect_timeout)
679
+ if (timeo = connect_timeout.to_i) && timeo > 0
680
+ host_count = conninfo_hash[:host].to_s.count(",") + 1
681
+ stop_time = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
682
+ end
654
683
 
655
- if (timeo = conninfo_hash[:connect_timeout].to_i) && timeo > 0
656
- host_count = conninfo_hash[:host].to_s.count(",") + 1
657
- stop_time = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
658
- end
659
-
660
- poll_status = PG::PGRES_POLLING_WRITING
661
- until poll_status == PG::PGRES_POLLING_OK ||
662
- poll_status == PG::PGRES_POLLING_FAILED
663
-
664
- # Set single timeout to parameter "connect_timeout" but
665
- # don't exceed total connection time of number-of-hosts * connect_timeout.
666
- timeout = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
667
- event = if !timeout || timeout >= 0
668
- # If the socket needs to read, wait 'til it becomes readable to poll again
669
- case poll_status
670
- when PG::PGRES_POLLING_READING
671
- if defined?(IO::READABLE) # ruby-3.0+
672
- socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
673
- else
674
- IO.select([socket_io], nil, [socket_io], timeout)
684
+ poll_status = PG::PGRES_POLLING_WRITING
685
+ until poll_status == PG::PGRES_POLLING_OK ||
686
+ poll_status == PG::PGRES_POLLING_FAILED
687
+
688
+ # Set single timeout to parameter "connect_timeout" but
689
+ # don't exceed total connection time of number-of-hosts * connect_timeout.
690
+ timeout = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
691
+ event = if !timeout || timeout >= 0
692
+ # If the socket needs to read, wait 'til it becomes readable to poll again
693
+ case poll_status
694
+ when PG::PGRES_POLLING_READING
695
+ if defined?(IO::READABLE) # ruby-3.0+
696
+ socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
697
+ else
698
+ IO.select([socket_io], nil, [socket_io], timeout)
699
+ end
700
+
701
+ # ...and the same for when the socket needs to write
702
+ when PG::PGRES_POLLING_WRITING
703
+ if defined?(IO::WRITABLE) # ruby-3.0+
704
+ # Use wait instead of wait_readable, since connection errors are delivered as
705
+ # exceptional/priority events on Windows.
706
+ socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
707
+ else
708
+ # io#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
709
+ IO.select(nil, [socket_io], [socket_io], timeout)
710
+ end
675
711
  end
676
-
677
- # ...and the same for when the socket needs to write
678
- when PG::PGRES_POLLING_WRITING
679
- if defined?(IO::WRITABLE) # ruby-3.0+
680
- # Use wait instead of wait_readable, since connection errors are delivered as
681
- # exceptional/priority events on Windows.
682
- socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
712
+ end
713
+ # connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
714
+ # connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
715
+ unless event
716
+ if self.class.send(:host_is_named_pipe?, host)
717
+ connhost = "on socket \"#{host}\""
718
+ elsif respond_to?(:hostaddr)
719
+ connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
683
720
  else
684
- # io#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
685
- IO.select(nil, [socket_io], [socket_io], timeout)
721
+ connhost = "at \"#{host}\", port #{port}"
686
722
  end
723
+ raise PG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", connection: self)
687
724
  end
688
- end
689
- # connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
690
- # connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
691
- unless event
692
- if self.class.send(:host_is_named_pipe?, host)
693
- connhost = "on socket \"#{host}\""
694
- elsif respond_to?(:hostaddr)
695
- connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
696
- else
697
- connhost = "at \"#{host}\", port #{port}"
698
- end
699
- raise PG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", connection: self)
725
+
726
+ # Check to see if it's finished or failed yet
727
+ poll_status = send( poll_meth )
700
728
  end
701
729
 
702
- # Check to see if it's finished or failed yet
703
- poll_status = send( poll_meth )
730
+ unless status == PG::CONNECTION_OK
731
+ msg = error_message
732
+ finish
733
+ raise PG::ConnectionBad.new(msg, connection: self)
734
+ end
704
735
  end
736
+ end
705
737
 
706
- unless status == PG::CONNECTION_OK
707
- msg = error_message
708
- finish
709
- raise PG::ConnectionBad.new(msg, connection: self)
710
- end
738
+ include Pollable
739
+
740
+ private def async_connect_or_reset(poll_meth)
741
+ # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
742
+ polling_loop(poll_meth, conninfo_hash[:connect_timeout])
711
743
 
712
744
  # Set connection to nonblocking to handle all blocking states in ruby.
713
745
  # That way a fiber scheduler is able to handle IO requests.
@@ -825,6 +857,14 @@ class PG::Connection
825
857
  iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
826
858
  iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
827
859
 
860
+ if PG::BUNDLED_LIBPQ_WITH_UNIXSOCKET && iopts[:host].to_s.empty?
861
+ # Many distors patch the hardcoded default UnixSocket path in libpq to /var/run/postgresql instead of /tmp .
862
+ # We simply try them all.
863
+ iopts[:host] = "/var/run/postgresql" + # Ubuntu, Debian, Fedora, Opensuse
864
+ ",/run/postgresql" + # Alpine, Archlinux, Gentoo
865
+ ",/tmp" # Stock PostgreSQL
866
+ end
867
+
828
868
  iopts_for_reset = iopts
829
869
  if iopts[:hostaddr]
830
870
  # hostaddr is provided -> no need to resolve hostnames
@@ -897,14 +937,29 @@ class PG::Connection
897
937
  private_constant :REDIRECT_CLASS_METHODS
898
938
 
899
939
  # These methods are affected by PQsetnonblocking
900
- REDIRECT_SEND_METHODS = PG.make_shareable({
940
+ REDIRECT_SEND_METHODS = {
901
941
  :isnonblocking => [:async_isnonblocking, :sync_isnonblocking],
902
942
  :nonblocking? => [:async_isnonblocking, :sync_isnonblocking],
903
943
  :put_copy_data => [:async_put_copy_data, :sync_put_copy_data],
904
944
  :put_copy_end => [:async_put_copy_end, :sync_put_copy_end],
905
945
  :flush => [:async_flush, :sync_flush],
906
- })
946
+ }
907
947
  private_constant :REDIRECT_SEND_METHODS
948
+ if PG::Connection.instance_methods.include? :sync_pipeline_sync
949
+ if PG::Connection.instance_methods.include? :send_pipeline_sync
950
+ # PostgreSQL-17+
951
+ REDIRECT_SEND_METHODS.merge!({
952
+ :pipeline_sync => [:async_pipeline_sync, :sync_pipeline_sync],
953
+ })
954
+ else
955
+ # PostgreSQL-14+
956
+ REDIRECT_SEND_METHODS.merge!({
957
+ :pipeline_sync => [:sync_pipeline_sync, :sync_pipeline_sync],
958
+ })
959
+ end
960
+ end
961
+ PG.make_shareable(REDIRECT_SEND_METHODS)
962
+
908
963
  REDIRECT_METHODS = {
909
964
  :exec => [:async_exec, :sync_exec],
910
965
  :query => [:async_exec, :sync_exec],
@@ -921,12 +976,13 @@ class PG::Connection
921
976
  :set_client_encoding => [:async_set_client_encoding, :sync_set_client_encoding],
922
977
  :client_encoding= => [:async_set_client_encoding, :sync_set_client_encoding],
923
978
  :cancel => [:async_cancel, :sync_cancel],
979
+ :encrypt_password => [:async_encrypt_password, :sync_encrypt_password],
924
980
  }
925
981
  private_constant :REDIRECT_METHODS
926
-
927
- if PG::Connection.instance_methods.include? :async_encrypt_password
982
+ if PG::Connection.instance_methods.include? :async_close_prepared
928
983
  REDIRECT_METHODS.merge!({
929
- :encrypt_password => [:async_encrypt_password, :sync_encrypt_password],
984
+ :close_prepared => [:async_close_prepared, :sync_close_prepared],
985
+ :close_portal => [:async_close_portal, :sync_close_portal],
930
986
  })
931
987
  end
932
988
  PG.make_shareable(REDIRECT_METHODS)