pg 1.5.9 → 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 (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/{History.md → CHANGELOG.md} +65 -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 +91 -13
  9. data/ext/extconf.rb +188 -15
  10. data/ext/gvl_wrappers.c +13 -2
  11. data/ext/gvl_wrappers.h +33 -0
  12. data/ext/pg.c +16 -5
  13. data/ext/pg.h +9 -9
  14. data/ext/pg_binary_decoder.c +151 -1
  15. data/ext/pg_binary_encoder.c +212 -9
  16. data/ext/pg_cancel_connection.c +360 -0
  17. data/ext/pg_coder.c +54 -5
  18. data/ext/pg_connection.c +368 -158
  19. data/ext/pg_copy_coder.c +2 -2
  20. data/ext/pg_record_coder.c +1 -1
  21. data/ext/pg_result.c +15 -17
  22. data/ext/pg_text_decoder.c +1 -1
  23. data/ext/pg_text_encoder.c +22 -9
  24. data/ext/pg_tuple.c +7 -7
  25. data/ext/pg_type_map.c +4 -2
  26. data/ext/pg_type_map_all_strings.c +1 -1
  27. data/ext/pg_type_map_by_class.c +1 -1
  28. data/ext/pg_type_map_by_column.c +2 -1
  29. data/ext/pg_type_map_by_mri_type.c +1 -1
  30. data/ext/pg_type_map_by_oid.c +3 -1
  31. data/ext/pg_type_map_in_ruby.c +1 -1
  32. data/ext/pg_util.c +2 -2
  33. data/ext/pg_util.h +2 -2
  34. data/lib/pg/basic_type_map_for_queries.rb +7 -3
  35. data/lib/pg/basic_type_registry.rb +2 -2
  36. data/lib/pg/cancel_connection.rb +53 -0
  37. data/lib/pg/coder.rb +4 -2
  38. data/lib/pg/connection.rb +254 -131
  39. data/lib/pg/version.rb +2 -1
  40. data/lib/pg.rb +156 -130
  41. data/misc/glibc/Dockerfile +20 -0
  42. data/misc/glibc/docker-compose.yml +9 -0
  43. data/misc/glibc/glibc_spec.rb +5 -0
  44. data/misc/yugabyte/Dockerfile +9 -0
  45. data/misc/yugabyte/docker-compose.yml +28 -0
  46. data/misc/yugabyte/pg-test.rb +45 -0
  47. data/pg.gemspec +5 -3
  48. data/ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch +30 -0
  49. data/ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch +12 -0
  50. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +21 -0
  51. data/ports/patches/postgresql/17.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  52. data/ports/patches/postgresql/17.6/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  53. data/rakelib/pg_gem_helper.rb +64 -0
  54. data.tar.gz.sig +0 -0
  55. metadata +36 -21
  56. metadata.gz.sig +0 -0
  57. data/Manifest.txt +0 -72
  58. data/Rakefile.cross +0 -303
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,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
654
636
 
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)
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
666
+
667
+ cl.close
668
+ nil
669
+ rescue SystemCallError => err
670
+ err.to_s
658
671
  end
672
+ end
673
+ alias async_cancel cancel
659
674
 
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)
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
675
725
  end
726
+ end
676
727
 
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)
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
683
738
  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)
739
+ finish
740
+ raise PG::ConnectionBad.new(connection_errors.join("\n").b, connection: self)
686
741
  end
687
742
  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)
743
+
744
+ # Check to see if it's finished or failed yet
745
+ poll_status = send( poll_meth )
700
746
  end
701
747
 
702
- # Check to see if it's finished or failed yet
703
- 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
704
753
  end
705
754
 
706
- unless status == PG::CONNECTION_OK
707
- msg = error_message
708
- finish
709
- 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
710
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)
711
796
 
712
797
  # Set connection to nonblocking to handle all blocking states in ruby.
713
798
  # That way a fiber scheduler is able to handle IO requests.
@@ -723,7 +808,7 @@ class PG::Connection
723
808
  # PG::Connection.new(connection_string) -> conn
724
809
  # PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
725
810
  #
726
- # Create a connection to the specified server.
811
+ # === Create a connection to the specified server.
727
812
  #
728
813
  # +connection_hash+ must be a ruby Hash with connection parameters.
729
814
  # See the {list of valid parameters}[https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS] in the PostgreSQL documentation.
@@ -747,7 +832,13 @@ class PG::Connection
747
832
  # [+password+]
748
833
  # login password
749
834
  #
750
- # 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:
751
842
  #
752
843
  # # Connect using all defaults
753
844
  # PG::Connection.new
@@ -764,10 +855,18 @@ class PG::Connection
764
855
  # # As an URI
765
856
  # PG::Connection.new( "postgresql://user:pass@pgsql.example.com:5432/testdb?sslmode=require" )
766
857
  #
767
- # If the Ruby default internal encoding is set (i.e., <code>Encoding.default_internal != nil</code>), the
768
- # 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.
769
869
  #
770
- # Raises a PG::Error if the connection fails.
771
870
  def new(*args)
772
871
  conn = connect_to_hosts(*args)
773
872
 
@@ -825,6 +924,14 @@ class PG::Connection
825
924
  iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
826
925
  iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
827
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
+
828
935
  iopts_for_reset = iopts
829
936
  if iopts[:hostaddr]
830
937
  # hostaddr is provided -> no need to resolve hostnames
@@ -897,14 +1004,29 @@ class PG::Connection
897
1004
  private_constant :REDIRECT_CLASS_METHODS
898
1005
 
899
1006
  # These methods are affected by PQsetnonblocking
900
- REDIRECT_SEND_METHODS = PG.make_shareable({
1007
+ REDIRECT_SEND_METHODS = {
901
1008
  :isnonblocking => [:async_isnonblocking, :sync_isnonblocking],
902
1009
  :nonblocking? => [:async_isnonblocking, :sync_isnonblocking],
903
1010
  :put_copy_data => [:async_put_copy_data, :sync_put_copy_data],
904
1011
  :put_copy_end => [:async_put_copy_end, :sync_put_copy_end],
905
1012
  :flush => [:async_flush, :sync_flush],
906
- })
1013
+ }
907
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
+
908
1030
  REDIRECT_METHODS = {
909
1031
  :exec => [:async_exec, :sync_exec],
910
1032
  :query => [:async_exec, :sync_exec],
@@ -921,12 +1043,13 @@ class PG::Connection
921
1043
  :set_client_encoding => [:async_set_client_encoding, :sync_set_client_encoding],
922
1044
  :client_encoding= => [:async_set_client_encoding, :sync_set_client_encoding],
923
1045
  :cancel => [:async_cancel, :sync_cancel],
1046
+ :encrypt_password => [:async_encrypt_password, :sync_encrypt_password],
924
1047
  }
925
1048
  private_constant :REDIRECT_METHODS
926
-
927
- if PG::Connection.instance_methods.include? :async_encrypt_password
1049
+ if PG::Connection.instance_methods.include? :async_close_prepared
928
1050
  REDIRECT_METHODS.merge!({
929
- :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],
930
1053
  })
931
1054
  end
932
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.9'
4
+ VERSION = '1.6.2'
4
5
  end