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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/{History.md → CHANGELOG.md} +76 -0
- data/Gemfile +7 -4
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +4 -4
- data/README.md +60 -20
- data/Rakefile +92 -14
- data/ext/errorcodes.def +4 -5
- data/ext/errorcodes.txt +2 -5
- data/ext/extconf.rb +188 -15
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +33 -0
- data/ext/pg.c +16 -5
- data/ext/pg.h +9 -9
- data/ext/pg_binary_decoder.c +151 -1
- data/ext/pg_binary_encoder.c +212 -9
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +54 -5
- data/ext/pg_connection.c +368 -158
- data/ext/pg_copy_coder.c +2 -2
- data/ext/pg_record_coder.c +1 -1
- data/ext/pg_result.c +15 -17
- data/ext/pg_text_decoder.c +1 -1
- data/ext/pg_text_encoder.c +22 -9
- data/ext/pg_tuple.c +7 -7
- data/ext/pg_type_map.c +4 -2
- data/ext/pg_type_map_all_strings.c +1 -1
- data/ext/pg_type_map_by_class.c +1 -1
- data/ext/pg_type_map_by_column.c +2 -1
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -1
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_for_queries.rb +7 -3
- data/lib/pg/basic_type_registry.rb +2 -2
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +4 -2
- data/lib/pg/connection.rb +259 -138
- data/lib/pg/version.rb +2 -1
- data/lib/pg.rb +156 -130
- data/misc/glibc/Dockerfile +20 -0
- data/misc/glibc/docker-compose.yml +9 -0
- data/misc/glibc/glibc_spec.rb +5 -0
- data/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +8 -4
- data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.6/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data.tar.gz.sig +0 -0
- metadata +36 -36
- metadata.gz.sig +0 -0
- data/.appveyor.yml +0 -42
- data/.gems +0 -6
- data/.gemtest +0 -0
- data/.github/workflows/binary-gems.yml +0 -117
- data/.github/workflows/source-gem.yml +0 -152
- data/.gitignore +0 -22
- data/.hgsigs +0 -34
- data/.hgtags +0 -41
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -49
- data/Manifest.txt +0 -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"
|
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
|
-
|
170
|
-
|
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
|
-
#
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
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
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
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
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
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
|
-
|
653
|
-
|
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
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
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
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
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
|
-
#
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
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
|
-
|
687
|
-
|
739
|
+
finish
|
740
|
+
raise PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self)
|
688
741
|
end
|
689
742
|
end
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
-
|
705
|
-
|
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
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
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
|
-
#
|
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
|
-
#
|
770
|
-
#
|
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 =
|
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
|
-
:
|
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