pg 1.5.8 → 1.6.2

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/{History.md → CHANGELOG.md} +76 -0
  4. data/Gemfile +7 -4
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +4 -4
  7. data/README.md +60 -20
  8. data/Rakefile +92 -14
  9. data/ext/errorcodes.def +4 -5
  10. data/ext/errorcodes.txt +2 -5
  11. data/ext/extconf.rb +188 -15
  12. data/ext/gvl_wrappers.c +13 -2
  13. data/ext/gvl_wrappers.h +33 -0
  14. data/ext/pg.c +16 -5
  15. data/ext/pg.h +9 -9
  16. data/ext/pg_binary_decoder.c +151 -1
  17. data/ext/pg_binary_encoder.c +212 -9
  18. data/ext/pg_cancel_connection.c +360 -0
  19. data/ext/pg_coder.c +54 -5
  20. data/ext/pg_connection.c +368 -158
  21. data/ext/pg_copy_coder.c +2 -2
  22. data/ext/pg_record_coder.c +1 -1
  23. data/ext/pg_result.c +15 -17
  24. data/ext/pg_text_decoder.c +1 -1
  25. data/ext/pg_text_encoder.c +22 -9
  26. data/ext/pg_tuple.c +7 -7
  27. data/ext/pg_type_map.c +4 -2
  28. data/ext/pg_type_map_all_strings.c +1 -1
  29. data/ext/pg_type_map_by_class.c +1 -1
  30. data/ext/pg_type_map_by_column.c +2 -1
  31. data/ext/pg_type_map_by_mri_type.c +1 -1
  32. data/ext/pg_type_map_by_oid.c +3 -1
  33. data/ext/pg_type_map_in_ruby.c +1 -1
  34. data/ext/pg_util.c +2 -2
  35. data/ext/pg_util.h +2 -2
  36. data/lib/pg/basic_type_map_for_queries.rb +7 -3
  37. data/lib/pg/basic_type_registry.rb +2 -2
  38. data/lib/pg/cancel_connection.rb +53 -0
  39. data/lib/pg/coder.rb +4 -2
  40. data/lib/pg/connection.rb +259 -138
  41. data/lib/pg/version.rb +2 -1
  42. data/lib/pg.rb +156 -130
  43. data/misc/glibc/Dockerfile +20 -0
  44. data/misc/glibc/docker-compose.yml +9 -0
  45. data/misc/glibc/glibc_spec.rb +5 -0
  46. data/misc/yugabyte/Dockerfile +9 -0
  47. data/misc/yugabyte/docker-compose.yml +28 -0
  48. data/misc/yugabyte/pg-test.rb +45 -0
  49. data/pg.gemspec +8 -4
  50. data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
  51. data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
  52. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
  53. data/ports/patches/postgresql/17.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  54. data/ports/patches/postgresql/17.6/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  55. data/rakelib/pg_gem_helper.rb +64 -0
  56. data.tar.gz.sig +0 -0
  57. metadata +36 -36
  58. metadata.gz.sig +0 -0
  59. data/.appveyor.yml +0 -42
  60. data/.gems +0 -6
  61. data/.gemtest +0 -0
  62. data/.github/workflows/binary-gems.yml +0 -117
  63. data/.github/workflows/source-gem.yml +0 -152
  64. data/.gitignore +0 -22
  65. data/.hgsigs +0 -34
  66. data/.hgtags +0 -41
  67. data/.irbrc +0 -23
  68. data/.pryrc +0 -23
  69. data/.tm_properties +0 -21
  70. data/.travis.yml +0 -49
  71. data/Manifest.txt +0 -72
  72. data/Rakefile.cross +0 -298
data/lib/pg/connection.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'pg' unless defined?( PG )
5
- require 'io/wait' unless ::IO.public_instance_methods(false).include?(:wait_readable)
5
+ require 'io/wait' unless ::IO.public_instance_methods(false).include?(:wait_readable) # for ruby < 3.0
6
6
  require 'socket'
7
7
 
8
8
  # The PostgreSQL connection class. The interface for this class is based on
@@ -117,7 +117,7 @@ class PG::Connection
117
117
  return str
118
118
  end
119
119
 
120
- BinarySignature = "PGCOPY\n\377\r\n\0".b
120
+ BinarySignature = "PGCOPY\n\377\r\n\0"
121
121
  private_constant :BinarySignature
122
122
 
123
123
  # call-seq:
@@ -166,9 +166,9 @@ class PG::Connection
166
166
  # conn.put_copy_data ['more', 'data', 'to', 'copy']
167
167
  # end
168
168
  #
169
- # All 4 CopyRow classes can take a type map to specify how the columns are mapped to and from the database format.
170
- # For details see the particular CopyRow class description.
171
- #
169
+ # All 4 CopyRow classes can take a type map to specify how the columns are mapped to and from the database format.
170
+ # For details see the particular CopyRow class description.
171
+ #
172
172
  # PG::BinaryEncoder::CopyRow can be used to send data in binary format to the server.
173
173
  # In this case copy_data generates the header and trailer data automatically:
174
174
  # enco = PG::BinaryEncoder::CopyRow.new
@@ -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,130 +602,197 @@ 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
633
- end
634
- 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)
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
643
613
  end
644
614
 
645
- cl.close
646
- nil
647
- rescue SystemCallError => err
648
- err.to_s
649
- end
650
- alias async_cancel cancel
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_cancel
629
+ rescue PG::Error => err
630
+ err.to_s
631
+ end
651
632
 
652
- private def async_connect_or_reset(poll_meth)
653
- # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
633
+ else
634
+
635
+ # PostgreSQL < 17
636
+
637
+ def cancel
638
+ be_pid = backend_pid
639
+ be_key = backend_key
640
+ cancel_request = [0x10, 1234, 5678, be_pid, be_key].pack("NnnNN")
641
+
642
+ if Fiber.respond_to?(:scheduler) && Fiber.scheduler && RUBY_PLATFORM =~ /mingw|mswin/
643
+ # Ruby's nonblocking IO is not really supported on Windows.
644
+ # We work around by using threads and explicit calls to wait_readable/wait_writable.
645
+ cl = Thread.new(socket_io.remote_address) { |ra| ra.connect }.value
646
+ begin
647
+ cl.write_nonblock(cancel_request)
648
+ rescue IO::WaitReadable, Errno::EINTR
649
+ cl.wait_writable
650
+ retry
651
+ end
652
+ begin
653
+ cl.read_nonblock(1)
654
+ rescue IO::WaitReadable, Errno::EINTR
655
+ cl.wait_readable
656
+ retry
657
+ rescue EOFError
658
+ end
659
+ else
660
+ cl = socket_io.remote_address.connect
661
+ # Send CANCEL_REQUEST_CODE and parameters
662
+ cl.write(cancel_request)
663
+ # Wait for the postmaster to close the connection, which indicates that it's processed the request.
664
+ cl.read(1)
665
+ end
654
666
 
655
- if (timeo = conninfo_hash[:connect_timeout].to_i) && timeo > 0
656
- # Lowest timeout is 2 seconds - like in libpq
657
- timeo = [timeo, 2].max
658
- host_count = conninfo_hash[:host].to_s.count(",") + 1
659
- stop_time = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
667
+ cl.close
668
+ nil
669
+ rescue SystemCallError => err
670
+ err.to_s
660
671
  end
672
+ end
673
+ alias async_cancel cancel
661
674
 
662
- poll_status = PG::PGRES_POLLING_WRITING
663
- until poll_status == PG::PGRES_POLLING_OK ||
664
- poll_status == PG::PGRES_POLLING_FAILED
665
-
666
- # Set single timeout to parameter "connect_timeout" but
667
- # don't exceed total connection time of number-of-hosts * connect_timeout.
668
- timeout = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
669
- event = if !timeout || timeout >= 0
670
- # If the socket needs to read, wait 'til it becomes readable to poll again
671
- case poll_status
672
- when PG::PGRES_POLLING_READING
673
- if defined?(IO::READABLE) # ruby-3.0+
674
- socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
675
- else
676
- IO.select([socket_io], nil, [socket_io], timeout)
675
+ module Pollable
676
+ # Track the progress of the connection, waiting for the socket to become readable/writable before polling it.
677
+ #
678
+ # Connecting to multiple hosts is done like so:
679
+ # - All hosts are passed to PG::Connection.connect_start
680
+ # - As soon as the host is tried to connect the related host is removed from the hosts list
681
+ # - When the polling status changes to `PG::PGRES_POLLING_OK` the connection is returned and ready to use.
682
+ # - When the polling status changes to `PG::PGRES_POLLING_FAILED` connecting is aborted and a PG::ConnectionBad is raised with details to all connection attepts.
683
+ # - When a timeout occurs, connecting is restarted with the remaining hosts.
684
+ #
685
+ # The downside is that this connects only once to hosts which are listed twice when they timeout.
686
+ private def polling_loop(poll_meth)
687
+ connect_timeout = conninfo_hash[:connect_timeout]
688
+ if (timeo = connect_timeout.to_i) && timeo > 0
689
+ host_count = (conninfo_hash[:hostaddr].to_s.empty? ? conninfo_hash[:host] : conninfo_hash[:hostaddr]).to_s.count(",") + 1
690
+ stop_time = timeo * host_count + Process.clock_gettime(Process::CLOCK_MONOTONIC)
691
+ end
692
+ iopts = conninfo_hash.compact
693
+ connection_errors = []
694
+ poll_status = PG::PGRES_POLLING_WRITING
695
+
696
+ until poll_status == PG::PGRES_POLLING_OK ||
697
+ poll_status == PG::PGRES_POLLING_FAILED
698
+
699
+ # Set single timeout to parameter "connect_timeout" but
700
+ # don't exceed total connection time of number-of-hosts * connect_timeout.
701
+ timeout = [timeo, stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)].min if stop_time
702
+
703
+ hostcnt = remove_current_host(iopts)
704
+
705
+ event = if !timeout || timeout >= 0
706
+ # If the socket needs to read, wait 'til it becomes readable to poll again
707
+ case poll_status
708
+ when PG::PGRES_POLLING_READING
709
+ if defined?(IO::READABLE) # ruby-3.0+
710
+ socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
711
+ else
712
+ IO.select([socket_io], nil, [socket_io], timeout)
713
+ end
714
+
715
+ # ...and the same for when the socket needs to write
716
+ when PG::PGRES_POLLING_WRITING
717
+ if defined?(IO::WRITABLE) # ruby-3.0+
718
+ # Use wait instead of wait_readable, since connection errors are delivered as
719
+ # exceptional/priority events on Windows.
720
+ socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
721
+ else
722
+ # io#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
723
+ IO.select(nil, [socket_io], [socket_io], timeout)
724
+ end
677
725
  end
726
+ end
678
727
 
679
- # ...and the same for when the socket needs to write
680
- when PG::PGRES_POLLING_WRITING
681
- if defined?(IO::WRITABLE) # ruby-3.0+
682
- # Use wait instead of wait_readable, since connection errors are delivered as
683
- # exceptional/priority events on Windows.
684
- socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
728
+ # connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
729
+ # connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
730
+ unless event
731
+ connection_errors << (error_message + "timeout expired")
732
+ if hostcnt > 0
733
+ reset_start2(self.class.parse_connect_args(iopts))
734
+ # Restart polling with waiting for writable.
735
+ # Otherwise "not connected" error is raised on Windows.
736
+ poll_status = PG::PGRES_POLLING_WRITING
737
+ next
685
738
  else
686
- # io#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
687
- IO.select(nil, [socket_io], [socket_io], timeout)
739
+ finish
740
+ raise PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self)
688
741
  end
689
742
  end
690
- end
691
- # connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
692
- # connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
693
- unless event
694
- if self.class.send(:host_is_named_pipe?, host)
695
- connhost = "on socket \"#{host}\""
696
- elsif respond_to?(:hostaddr)
697
- connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
698
- else
699
- connhost = "at \"#{host}\", port #{port}"
700
- end
701
- raise PG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", connection: self)
743
+
744
+ # Check to see if it's finished or failed yet
745
+ poll_status = send( poll_meth )
702
746
  end
703
747
 
704
- # Check to see if it's finished or failed yet
705
- poll_status = send( poll_meth )
748
+ unless status == PG::CONNECTION_OK
749
+ msg = error_message
750
+ finish
751
+ raise PG::ConnectionBad.new(connection_errors.map{|e| e + "\n" }.join.b + msg, connection: self)
752
+ end
706
753
  end
707
754
 
708
- unless status == PG::CONNECTION_OK
709
- msg = error_message
710
- finish
711
- raise PG::ConnectionBad.new(msg, connection: self)
755
+ # Remove the host to which the connection is currently established from the option hash.
756
+ # Affected options are:
757
+ # - :host
758
+ # - :hostaddr
759
+ # - :port
760
+ #
761
+ # Return the number of remaining hosts.
762
+ private def remove_current_host(iopts)
763
+ ihosts = iopts[:host]&.split(",", -1)
764
+ ihostaddrs = iopts[:hostaddr]&.split(",", -1)
765
+ iports = iopts[:port]&.split(",", -1)
766
+ iports = iports * (ihosts || ihostaddrs || [1]).size if iports&.size == 1
767
+
768
+ idx = (ihosts || ihostaddrs || iports).index.with_index do |_, i|
769
+ (ihosts ? ihosts[i] == host : true) &&
770
+ (ihostaddrs && respond_to?(:hostaddr, true) ? ihostaddrs[i] == hostaddr : true) &&
771
+ (iports ? iports[i].to_i == port : true)
772
+ end
773
+
774
+ if idx
775
+ ihosts&.delete_at(idx)
776
+ ihostaddrs&.delete_at(idx)
777
+ iports&.delete_at(idx)
778
+
779
+ iopts.merge!(
780
+ host: ihosts.join(",")) if ihosts
781
+ iopts.merge!(
782
+ hostaddr: ihostaddrs.join(",")) if ihostaddrs
783
+ iopts.merge!(
784
+ port: iports.join(",")) if iports
785
+ end
786
+
787
+ (ihosts || ihostaddrs || iports).size
712
788
  end
789
+ end
790
+
791
+ include Pollable
792
+
793
+ private def async_connect_or_reset(poll_meth)
794
+ # Track the progress of the connection, waiting for the socket to become readable/writable before polling it
795
+ polling_loop(poll_meth)
713
796
 
714
797
  # Set connection to nonblocking to handle all blocking states in ruby.
715
798
  # That way a fiber scheduler is able to handle IO requests.
@@ -725,7 +808,7 @@ class PG::Connection
725
808
  # PG::Connection.new(connection_string) -> conn
726
809
  # PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
727
810
  #
728
- # Create a connection to the specified server.
811
+ # === Create a connection to the specified server.
729
812
  #
730
813
  # +connection_hash+ must be a ruby Hash with connection parameters.
731
814
  # See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
@@ -749,7 +832,13 @@ class PG::Connection
749
832
  # [+password+]
750
833
  # login password
751
834
  #
752
- # Examples:
835
+ #
836
+ # If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
837
+ # connection will have its +client_encoding+ set accordingly.
838
+ #
839
+ # Raises a PG::Error if the connection fails.
840
+ #
841
+ # === Examples:
753
842
  #
754
843
  # # Connect using all defaults
755
844
  # PG::Connection.new
@@ -766,10 +855,18 @@ class PG::Connection
766
855
  # # As an URI
767
856
  # PG::Connection.new( "postgresql://user:pass@pgsql.example.com:5432/testdb?sslmode=require" )
768
857
  #
769
- # If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
770
- # connection will have its +client_encoding+ set accordingly.
858
+ # === Specifying Multiple Hosts
859
+ #
860
+ # It is possible to specify multiple hosts to connect to, so that they are tried in the given order or optionally in random order.
861
+ # In the Keyword/Value format, the host, hostaddr, and port options accept comma-separated lists of values.
862
+ # The {details to libpq}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS] describe how it works, but there are two small differences how ruby-pg handles multiple hosts:
863
+ # - All hosts are resolved before the first connection is tried.
864
+ # This means that when +load_balance_hosts+ is set to +random+, then all resolved addresses are tried randomly in one level.
865
+ # When a host resolves to more than one address, it is therefore tried more often than a host that has only one address.
866
+ # - When a timeout occurs due to the value of +connect_timeout+, then the given +host+, +hostaddr+ and +port+ combination is not tried a second time, even if it's specified several times.
867
+ # It's still possible to do load balancing with +load_balance_hosts+ set to +random+ and to increase the number of connections a node gets, when the hostname is provided multiple times in the host string.
868
+ # This is because in non-timeout cases the host is tried multiple times.
771
869
  #
772
- # Raises a PG::Error if the connection fails.
773
870
  def new(*args)
774
871
  conn = connect_to_hosts(*args)
775
872
 
@@ -827,6 +924,14 @@ class PG::Connection
827
924
  iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
828
925
  iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
829
926
 
927
+ if PG::BUNDLED_LIBPQ_WITH_UNIXSOCKET && iopts[:host].to_s.empty? && iopts[:hostaddr].to_s.empty?
928
+ # Many distors patch the hardcoded default UnixSocket path in libpq to /var/run/postgresql instead of /tmp .
929
+ # We simply try them all.
930
+ iopts[:host] = "/var/run/postgresql" + # Ubuntu, Debian, Fedora, Opensuse
931
+ ",/run/postgresql" + # Alpine, Archlinux, Gentoo
932
+ ",/tmp" # Stock PostgreSQL
933
+ end
934
+
830
935
  iopts_for_reset = iopts
831
936
  if iopts[:hostaddr]
832
937
  # hostaddr is provided -> no need to resolve hostnames
@@ -899,14 +1004,29 @@ class PG::Connection
899
1004
  private_constant :REDIRECT_CLASS_METHODS
900
1005
 
901
1006
  # These methods are affected by PQsetnonblocking
902
- REDIRECT_SEND_METHODS = PG.make_shareable({
1007
+ REDIRECT_SEND_METHODS = {
903
1008
  :isnonblocking => [:async_isnonblocking, :sync_isnonblocking],
904
1009
  :nonblocking? => [:async_isnonblocking, :sync_isnonblocking],
905
1010
  :put_copy_data => [:async_put_copy_data, :sync_put_copy_data],
906
1011
  :put_copy_end => [:async_put_copy_end, :sync_put_copy_end],
907
1012
  :flush => [:async_flush, :sync_flush],
908
- })
1013
+ }
909
1014
  private_constant :REDIRECT_SEND_METHODS
1015
+ if PG::Connection.instance_methods.include? :sync_pipeline_sync
1016
+ if PG::Connection.instance_methods.include? :send_pipeline_sync
1017
+ # PostgreSQL-17+
1018
+ REDIRECT_SEND_METHODS.merge!({
1019
+ :pipeline_sync => [:async_pipeline_sync, :sync_pipeline_sync],
1020
+ })
1021
+ else
1022
+ # PostgreSQL-14+
1023
+ REDIRECT_SEND_METHODS.merge!({
1024
+ :pipeline_sync => [:sync_pipeline_sync, :sync_pipeline_sync],
1025
+ })
1026
+ end
1027
+ end
1028
+ PG.make_shareable(REDIRECT_SEND_METHODS)
1029
+
910
1030
  REDIRECT_METHODS = {
911
1031
  :exec => [:async_exec, :sync_exec],
912
1032
  :query => [:async_exec, :sync_exec],
@@ -923,12 +1043,13 @@ class PG::Connection
923
1043
  :set_client_encoding => [:async_set_client_encoding, :sync_set_client_encoding],
924
1044
  :client_encoding= => [:async_set_client_encoding, :sync_set_client_encoding],
925
1045
  :cancel => [:async_cancel, :sync_cancel],
1046
+ :encrypt_password => [:async_encrypt_password, :sync_encrypt_password],
926
1047
  }
927
1048
  private_constant :REDIRECT_METHODS
928
-
929
- if PG::Connection.instance_methods.include? :async_encrypt_password
1049
+ if PG::Connection.instance_methods.include? :async_close_prepared
930
1050
  REDIRECT_METHODS.merge!({
931
- :encrypt_password => [:async_encrypt_password, :sync_encrypt_password],
1051
+ :close_prepared => [:async_close_prepared, :sync_close_prepared],
1052
+ :close_portal => [:async_close_portal, :sync_close_portal],
932
1053
  })
933
1054
  end
934
1055
  PG.make_shareable(REDIRECT_METHODS)
data/lib/pg/version.rb CHANGED
@@ -1,4 +1,5 @@
1
+ # frozen_string_literal: true
1
2
  module PG
2
3
  # Library version
3
- VERSION = '1.5.8'
4
+ VERSION = '1.6.2'
4
5
  end