pg 1.6.3-aarch64-linux → 1.7.0-aarch64-linux

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 (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +52 -6
  4. data/Gemfile +1 -0
  5. data/README.ja.md +81 -30
  6. data/README.md +14 -7
  7. data/Rakefile +8 -7
  8. data/certs/larskanis-2026.pem +24 -0
  9. data/ext/extconf.rb +18 -28
  10. data/ext/gvl_wrappers.c +2 -2
  11. data/ext/gvl_wrappers.h +40 -160
  12. data/ext/pg.c +8 -12
  13. data/ext/pg.h +8 -11
  14. data/ext/pg_binary_decoder.c +6 -2
  15. data/ext/pg_binary_encoder.c +7 -0
  16. data/ext/pg_cancel_connection.c +6 -6
  17. data/ext/pg_coder.c +4 -4
  18. data/ext/pg_connection.c +196 -159
  19. data/ext/pg_copy_coder.c +34 -21
  20. data/ext/pg_record_coder.c +10 -6
  21. data/ext/pg_result.c +42 -26
  22. data/ext/pg_text_decoder.c +6 -6
  23. data/ext/pg_text_encoder.c +7 -2
  24. data/ext/pg_tuple.c +1 -1
  25. data/ext/pg_type_map.c +41 -1
  26. data/ext/pg_type_map_all_strings.c +2 -2
  27. data/ext/pg_type_map_by_class.c +1 -1
  28. data/ext/pg_type_map_by_column.c +2 -2
  29. data/ext/pg_type_map_by_oid.c +1 -1
  30. data/ext/pg_type_map_in_ruby.c +1 -1
  31. data/lib/3.1/pg_ext.so +0 -0
  32. data/lib/3.2/pg_ext.so +0 -0
  33. data/lib/3.3/pg_ext.so +0 -0
  34. data/lib/3.4/pg_ext.so +0 -0
  35. data/lib/4.0/pg_ext.so +0 -0
  36. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  37. data/lib/pg/basic_type_map_for_queries.rb +9 -2
  38. data/lib/pg/basic_type_map_for_results.rb +5 -0
  39. data/lib/pg/connection.rb +166 -76
  40. data/lib/pg/text_decoder/date.rb +1 -1
  41. data/lib/pg/text_decoder/json.rb +1 -1
  42. data/lib/pg/text_encoder/date.rb +7 -1
  43. data/lib/pg/text_encoder/json.rb +1 -1
  44. data/lib/pg/version.rb +1 -1
  45. data/misc/yugabyte/docker-compose.yml +1 -1
  46. data/pg.gemspec +1 -1
  47. data/ports/aarch64-linux/lib/libpq-ruby-pg.so.1 +0 -0
  48. data/sample/async_mixed.rb +1 -1
  49. data.tar.gz.sig +0 -0
  50. metadata +17 -19
  51. metadata.gz.sig +0 -0
  52. data/lib/3.0/pg_ext.so +0 -0
  53. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +0 -21
  54. data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +0 -52
  55. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0001-Allow-static-linking-krb5-library.patch +0 -0
  56. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0002-unknown-command-line-option-on-clang.patch +0 -0
  57. /data/ports/patches/postgresql/{18.1 → 18.6}/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +0 -0
@@ -64,4 +64,9 @@ class PG::BasicTypeMapBasedOnResult < PG::TypeMapByOid
64
64
  add_coder(coder)
65
65
  end
66
66
  end
67
+
68
+ # Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate result OIDs to encoders.
69
+ def coder_maps_bundle
70
+ @coder_maps
71
+ end
67
72
  end
@@ -57,6 +57,11 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
57
57
  init_encoders
58
58
  end
59
59
 
60
+ # Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate encoders to OIDs.
61
+ def coder_maps_bundle
62
+ @coder_maps
63
+ end
64
+
60
65
  class UndefinedDefault
61
66
  def self.call(oid_name, format)
62
67
  raise UndefinedEncoder, "no encoder defined for type #{oid_name.inspect} format #{format}"
@@ -177,13 +182,14 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
177
182
  end
178
183
 
179
184
  DEFAULT_TYPE_MAP = PG.make_shareable({
180
- TrueClass => [1, 'bool', 'bool'],
181
- FalseClass => [1, 'bool', 'bool'],
185
+ TrueClass => [0, 'bool', 'bool'],
186
+ FalseClass => [0, 'bool', 'bool'],
182
187
  # We use text format and no type OID for numbers, because setting the OID can lead
183
188
  # to unnecessary type conversions on server side.
184
189
  Integer => [0, 'int8'],
185
190
  Float => [0, 'float8'],
186
191
  Time => [0, 'timestamptz'],
192
+ Date => [0, 'date'],
187
193
  # We use text format and no type OID for IPAddr, because setting the OID can lead
188
194
  # to unnecessary inet/cidr conversions on the server side.
189
195
  IPAddr => [0, 'inet'],
@@ -200,6 +206,7 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass
200
206
  String => [0, '_text'],
201
207
  Float => [0, '_float8'],
202
208
  Time => [0, '_timestamptz'],
209
+ Date => [0, '_date'],
203
210
  IPAddr => [0, '_inet'],
204
211
  }.merge(has_bigdecimal ? {BigDecimal => [0, '_numeric']} : {}))
205
212
  private_constant :DEFAULT_ARRAY_TYPE_MAP
@@ -101,4 +101,9 @@ class PG::BasicTypeMapForResults < PG::TypeMapByOid
101
101
  typenames = @coder_maps.typenames_by_oid
102
102
  self.default_type_map = WarningTypeMap.new(typenames)
103
103
  end
104
+
105
+ # Returns the PG::BasicTypeRegistry::CoderMapsBundle used to translate result OIDs to decoders.
106
+ def coder_maps_bundle
107
+ @coder_maps
108
+ end
104
109
  end
data/lib/pg/connection.rb CHANGED
@@ -2,7 +2,6 @@
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) # for ruby < 3.0
6
5
  require 'socket'
7
6
 
8
7
  # The PostgreSQL connection class. The interface for this class is based on
@@ -13,7 +12,7 @@ require 'socket'
13
12
  # For example, to send query to the database on the localhost:
14
13
  #
15
14
  # require 'pg'
16
- # conn = PG::Connection.open(:dbname => 'test')
15
+ # conn = PG::Connection.open(dbname: 'test')
17
16
  # res = conn.exec_params('SELECT $1 AS a, $2 AS b, $3 AS c', [1, 2, nil])
18
17
  # # Equivalent to:
19
18
  # # res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
@@ -306,22 +305,19 @@ class PG::Connection
306
305
  # and a +COMMIT+ at the end of the block, or
307
306
  # +ROLLBACK+ if any exception occurs.
308
307
  def transaction
309
- rollback = false
310
308
  exec "BEGIN"
311
309
  yield(self)
312
- rescue PG::RollbackTransaction
313
- rollback = true
314
- cancel if transaction_status == PG::PQTRANS_ACTIVE
315
- block
316
- exec "ROLLBACK"
317
- rescue Exception
318
- rollback = true
319
- cancel if transaction_status == PG::PQTRANS_ACTIVE
320
- block
321
- exec "ROLLBACK"
310
+ rescue PG::RollbackTransaction => error
311
+ rescue Exception => error
322
312
  raise
323
313
  ensure
324
- exec "COMMIT" unless rollback
314
+ if error || Thread.current.status == "aborting"
315
+ cancel if transaction_status == PG::PQTRANS_ACTIVE
316
+ block
317
+ exec("ROLLBACK")
318
+ else
319
+ exec("COMMIT")
320
+ end
325
321
  end
326
322
 
327
323
  ### Returns an array of Hashes with connection defaults. See ::conndefaults
@@ -555,33 +551,30 @@ class PG::Connection
555
551
  alias async_pipeline_sync pipeline_sync
556
552
  end
557
553
 
558
- if method_defined? :sync_encrypt_password
559
- # call-seq:
560
- # conn.encrypt_password( password, username, algorithm=nil ) -> String
561
- #
562
- # This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
563
- # It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
564
- # Instead, use this function to convert the password to encrypted form before it is sent.
565
- #
566
- # The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
567
- # +algorithm+ specifies the encryption algorithm to use to encrypt the password.
568
- # Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
569
- # Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
570
- # If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
571
- # That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
572
- # If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
573
- #
574
- # Return value is the encrypted password.
575
- # The caller can assume the string doesn't contain any special characters that would require escaping.
576
- #
577
- # Available since PostgreSQL-10.
578
- # See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
579
- def encrypt_password( password, username, algorithm=nil )
580
- algorithm ||= exec("SHOW password_encryption").getvalue(0,0)
581
- sync_encrypt_password(password, username, algorithm)
582
- end
583
- alias async_encrypt_password encrypt_password
554
+ # call-seq:
555
+ # conn.encrypt_password( password, username, algorithm=nil ) -> String
556
+ #
557
+ # This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
558
+ # It is good practice not to send the original cleartext password in such a command, because it might be exposed in command logs, activity displays, and so on.
559
+ # Instead, use this function to convert the password to encrypted form before it is sent.
560
+ #
561
+ # The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
562
+ # +algorithm+ specifies the encryption algorithm to use to encrypt the password.
563
+ # Currently supported algorithms are +md5+ and +scram-sha-256+ (+on+ and +off+ are also accepted as aliases for +md5+, for compatibility with older server versions).
564
+ # Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
565
+ # If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
566
+ # That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
567
+ # If you wish to use the default algorithm for the server but want to avoid blocking, query +password_encryption+ yourself before calling #encrypt_password, and pass that value as the algorithm.
568
+ #
569
+ # Return value is the encrypted password.
570
+ # The caller can assume the string doesn't contain any special characters that would require escaping.
571
+ #
572
+ # See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
573
+ def encrypt_password( password, username, algorithm=nil )
574
+ algorithm ||= exec("SHOW password_encryption").getvalue(0,0)
575
+ sync_encrypt_password(password, username, algorithm)
584
576
  end
577
+ alias async_encrypt_password encrypt_password
585
578
 
586
579
  # call-seq:
587
580
  # conn.reset()
@@ -592,7 +585,9 @@ class PG::Connection
592
585
  # Use connection options from PG::Connection.new to reconnect with the same options but with renewed DNS resolution.
593
586
  # Use conninfo_hash as a fallback when connect_start was used to create the connection object.
594
587
  iopts = @iopts_for_reset || conninfo_hash.compact
595
- if iopts[:host] && !iopts[:host].empty? && PG.library_version >= 100000
588
+ if iopts[:host] && !iopts[:host].empty? &&
589
+ iopts[:port] && !iopts[:port].empty? &&
590
+ PG.library_version >= 100000
596
591
  iopts = self.class.send(:resolve_hosts, iopts)
597
592
  end
598
593
  conninfo = self.class.parse_connect_args( iopts );
@@ -621,7 +616,7 @@ class PG::Connection
621
616
  # Returns +nil+ on success, or a string containing the
622
617
  # error message if a failure occurs.
623
618
  #
624
- # On PostgreSQL-17+ client libaray the class PG::CancelConnection is used.
619
+ # On PostgreSQL-17+ client library the class PG::CancelConnection is used.
625
620
  # On older client library a pure ruby implementation is used.
626
621
  def cancel
627
622
  cancon = PG::CancelConnection.new(self)
@@ -672,6 +667,101 @@ class PG::Connection
672
667
  end
673
668
  alias async_cancel cancel
674
669
 
670
+ PLACEHOLDER_RE = /
671
+ '(?:''|[^'])*' | # string literal
672
+ "(?:""|[^"])*" | # quoted identifier
673
+ --[^\n]* | # line comment
674
+ \/\*.*?\*\/ | # block comment
675
+ \$\$.*?\$\$ | # dollar-quoted string. E.g. $$ $1 $$
676
+ \$(?<__dq_tag>[A-Za-z_][A-Za-z_0-9]*)\$.*?\$\k<__dq_tag>\$ | # named dollar-quoted string. E.g. $foo$ $1 $foo$
677
+ (?<placeholder>\$(?:[1-9]\d*)) # placeholder we are interested in
678
+ /mx
679
+ private_constant :PLACEHOLDER_RE
680
+ SAFE_TYPE_NAME_PART_RE = /\A[A-Za-z_][A-Za-z0-9_$]*\z/
681
+ private_constant :SAFE_TYPE_NAME_PART_RE
682
+
683
+ private def quote_type_name(name)
684
+ name = name.to_s.dup
685
+ array_suffix = name.slice!(/(?:\[\])+\z/) || ""
686
+ name = name.split(".", -1).map do |part|
687
+ SAFE_TYPE_NAME_PART_RE.match?(part) ? part : quote_ident(part)
688
+ end.join(".")
689
+ name + array_suffix
690
+ end
691
+
692
+ # Compiles your prepared SQL statement and the given positional arguments into plain SQL string.
693
+ #
694
+ # The resulting SQL string can be used with +conn.exec+ like the prepared SQL statement and parameters with +conn.exec_params+.
695
+ # +conn.exec_params+ is usually preferred because it's faster and safer.
696
+ # +embed_params+ is intended for debugging messages with positional parameters.
697
+ # It avoids manual insertion for later inspection in +psql+ or so.
698
+ #
699
+ # When using PG::Connection#exec_params, it's possible to set the numeric database type OID of a parameter by either a hash with +:type+ key, or by PG::Coder#oid .
700
+ # +embed_params+ casts the parameter the same way, but needs the name of the type instead its OID.
701
+ # That name must be provided by either a +:typename+ key in addition to the +:type+ OID or by PG::Coder#name in addition to PG::Coder#oid.
702
+ #
703
+ # Only text parameter format can be embedded into SQL text.
704
+ # Binary data ( <tt>:format => 1</tt> or PG::Coder#format == 1 ) raises an ArgumentError.
705
+ # However the common pattern of sending BYTEA (OID 17) data as format 1, which avoids escapting large blobs, is recognized and probably escaped into the SQL result string.
706
+ #
707
+ # Example:
708
+ # conn.embed_params('SELECT $1 AS a, $2 AS b, $3 AS c', [1, 2, {value: "\0", type: 17, format: 1}])
709
+ # => "SELECT '1' AS a, '2' AS b, '\\x00'::bytea AS c"
710
+ def embed_params(sql, params, type_map: type_map_for_queries)
711
+ return sql if params.empty?
712
+
713
+ oid_to_typecast = proc do |oid, tname, errtext|
714
+ if oid && oid > 0
715
+ if tname.to_s.empty?
716
+ raise(ArgumentError, "Database type name of OID #{oid.inspect} missing#{errtext}")
717
+ else
718
+ "::#{quote_type_name(tname)}"
719
+ end
720
+ end
721
+ end
722
+
723
+ encoders = type_map.query_param_encoders(params)
724
+ params = encoders.map.with_index do |enc, i|
725
+ value = params[i]
726
+ case value
727
+ when NilClass
728
+ 'NULL'
729
+ when PG::BasicTypeMapForQueries::BinaryData
730
+ "'#{ escape_bytea(value) }'"
731
+ else
732
+ if enc
733
+ raise ArgumentError, "binary encoded parameter from #{enc.inspect} cannot be inserted into SQL text" if enc.format != 0
734
+ "'#{escape(enc.encode(value))}'#{oid_to_typecast[enc.oid, enc.name, " - please set name of encoder #{enc.inspect}"]}"
735
+ elsif Hash === value
736
+ typename = value[:format] == 1 && value[:type] == 17 ?
737
+ "::bytea" : oid_to_typecast[value[:type], value[:typename], " - please set parameter key :typename"]
738
+
739
+ case value[:value]
740
+ when NilClass
741
+ "NULL#{typename}"
742
+ else
743
+ if value[:format] == 1
744
+ raise ArgumentError, "binary encoded parameter with OID #{value[:type].inspect} cannot be inserted into SQL text" if value[:type] && value[:type] != 17
745
+ "'#{escape_bytea(value[:value].to_s)}'#{typename}"
746
+ else
747
+ "'#{escape(value[:value].to_s)}'#{typename}"
748
+ end
749
+ end
750
+ else
751
+ "'#{escape(value.to_s)}'"
752
+ end
753
+ end
754
+ end
755
+
756
+ sql.gsub(PLACEHOLDER_RE).each do |matched|
757
+ placeholder = Regexp.last_match[:placeholder]
758
+ # Do not replace non-positional args string and pass it as is
759
+ next matched unless placeholder
760
+
761
+ params[placeholder[1..].to_i - 1]
762
+ end
763
+ end
764
+
675
765
  module Pollable
676
766
  # Track the progress of the connection, waiting for the socket to become readable/writable before polling it.
677
767
  #
@@ -679,7 +769,7 @@ class PG::Connection
679
769
  # - All hosts are passed to PG::Connection.connect_start
680
770
  # - As soon as the host is tried to connect the related host is removed from the hosts list
681
771
  # - 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.
772
+ # - When the polling status changes to `PG::PGRES_POLLING_FAILED` connecting is aborted and a PG::ConnectionBad is raised with details to all connection attempts.
683
773
  # - When a timeout occurs, connecting is restarted with the remaining hosts.
684
774
  #
685
775
  # The downside is that this connects only once to hosts which are listed twice when they timeout.
@@ -706,22 +796,13 @@ class PG::Connection
706
796
  # If the socket needs to read, wait 'til it becomes readable to poll again
707
797
  case poll_status
708
798
  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
799
+ socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
714
800
 
715
801
  # ...and the same for when the socket needs to write
716
802
  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
803
+ # Use wait instead of wait_readable, since connection errors are delivered as
804
+ # exceptional/priority events on Windows.
805
+ socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
725
806
  end
726
807
  end
727
808
 
@@ -887,7 +968,6 @@ class PG::Connection
887
968
 
888
969
  # Resolve DNS in Ruby to avoid blocking state while connecting.
889
970
  # Multiple comma-separated values are generated, if the hostname resolves to both IPv4 and IPv6 addresses.
890
- # This requires PostgreSQL-10+, so no DNS resolving is done on earlier versions.
891
971
  private def resolve_hosts(iopts)
892
972
  ihosts = iopts[:host].split(",", -1)
893
973
  iports = iopts[:port].split(",", -1)
@@ -897,16 +977,7 @@ class PG::Connection
897
977
 
898
978
  dests = ihosts.each_with_index.flat_map do |mhost, idx|
899
979
  unless host_is_named_pipe?(mhost)
900
- if Fiber.respond_to?(:scheduler) &&
901
- Fiber.scheduler &&
902
- RUBY_VERSION < '3.1.'
903
-
904
- # Use a second thread to avoid blocking of the scheduler.
905
- # `TCPSocket.gethostbyname` isn't fiber aware before ruby-3.1.
906
- hostaddrs = Thread.new{ Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue [''] }.value
907
- else
908
- hostaddrs = Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue ['']
909
- end
980
+ hostaddrs = Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue ['']
910
981
  else
911
982
  # No hostname to resolve (UnixSocket)
912
983
  hostaddrs = [nil]
@@ -919,13 +990,24 @@ class PG::Connection
919
990
  port: dests.map{|d| d[2] }.join(","))
920
991
  end
921
992
 
993
+ RESOLUTION_KEYS = [:host, :hostaddr, :port].freeze
994
+ private_constant :RESOLUTION_KEYS
995
+
922
996
  private def connect_to_hosts(*args)
923
997
  option_string = parse_connect_args(*args)
924
- iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
925
- iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
998
+ iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}) { |h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
926
999
 
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 .
1000
+ has_explicit_host = (!iopts[:host].to_s.empty? || !iopts[:hostaddr].to_s.empty?) && !iopts[:port].to_s.empty?
1001
+ has_explicit_service = !iopts[:service].to_s.empty?
1002
+
1003
+ iopts_with_defaults = PG::Connection.conndefaults.each_with_object({}) do |h, o|
1004
+ k = h[:keyword].to_sym
1005
+ # Only use the host/hostname/port keys from defaults and leave user/dbname/sslmode/... for libpq, so that they are processed in the right order.
1006
+ o[k] = h[:val] if h[:val] && RESOLUTION_KEYS.include?(k)
1007
+ end.merge(iopts)
1008
+
1009
+ if PG::BUNDLED_LIBPQ_WITH_UNIXSOCKET && iopts_with_defaults[:host].to_s.empty? && iopts_with_defaults[:hostaddr].to_s.empty?
1010
+ # Many distros patch the hardcoded default UnixSocket path in libpq to /var/run/postgresql instead of /tmp .
929
1011
  # We simply try them all.
930
1012
  iopts[:host] = "/var/run/postgresql" + # Ubuntu, Debian, Fedora, Opensuse
931
1013
  ",/run/postgresql" + # Alpine, Archlinux, Gentoo
@@ -933,15 +1015,22 @@ class PG::Connection
933
1015
  end
934
1016
 
935
1017
  iopts_for_reset = iopts
936
- if iopts[:hostaddr]
1018
+ if iopts_with_defaults[:hostaddr]
937
1019
  # hostaddr is provided -> no need to resolve hostnames
938
-
939
- elsif iopts[:host] && !iopts[:host].empty? && PG.library_version >= 100000
940
- iopts = resolve_hosts(iopts)
1020
+ elsif has_explicit_service && !has_explicit_host
1021
+ # The pg_service.conf might provide host/user/port/etc.
1022
+ # Ruby-pg cannot interpret pg_service without reading INI file and the additional LDAP stuff.
1023
+ # So, pass params through and let libpq resolve the service, possibly blocking the Thread.scheduler.
1024
+ # This ensures the processing order of libpq which is:
1025
+ # connection string => service file => environment variable => compiled default
1026
+ elsif iopts_with_defaults[:host] && !iopts_with_defaults[:host].empty?
1027
+ # Do host resolution in Ruby to avoid blocking Thread.scheduler while DNS queries in libpq.
1028
+ iopts_for_reset = iopts_with_defaults
1029
+ iopts = resolve_hosts(iopts_with_defaults)
941
1030
  else
942
1031
  # No host given
943
1032
  end
944
- conn = self.connect_start(iopts) or
1033
+ conn = connect_start(iopts) or
945
1034
  raise(PG::Error, "Unable to create a new connection")
946
1035
 
947
1036
  raise PG::ConnectionBad, conn.error_message if conn.status == PG::CONNECTION_BAD
@@ -1047,6 +1136,7 @@ class PG::Connection
1047
1136
  }
1048
1137
  private_constant :REDIRECT_METHODS
1049
1138
  if PG::Connection.instance_methods.include? :async_close_prepared
1139
+ # PostgreSQL-17+
1050
1140
  REDIRECT_METHODS.merge!({
1051
1141
  :close_prepared => [:async_close_prepared, :sync_close_prepared],
1052
1142
  :close_portal => [:async_close_portal, :sync_close_portal],
@@ -11,7 +11,7 @@ module PG
11
11
  class Date < SimpleDecoder
12
12
  def decode(string, tuple=nil, field=nil)
13
13
  if string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/
14
- ::Date.new $1.to_i, $2.to_i, $3.to_i
14
+ ::Date.new $1.to_i, $2.to_i, $3.to_i, ::Date::GREGORIAN
15
15
  else
16
16
  string
17
17
  end
@@ -10,7 +10,7 @@ module PG
10
10
  # As soon as this class is used, it requires the ruby standard library 'json'.
11
11
  class JSON < SimpleDecoder
12
12
  def decode(string, tuple=nil, field=nil)
13
- ::JSON.parse(string, quirks_mode: true)
13
+ ::JSON.parse(string)
14
14
  end
15
15
  end
16
16
  end
@@ -6,7 +6,13 @@ module PG
6
6
  # This is a encoder class for conversion of Ruby Date values to PostgreSQL date type.
7
7
  class Date < SimpleEncoder
8
8
  def encode(value)
9
- value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d") : value
9
+ if value.respond_to?(:gregorian?)
10
+ # Only create a new gregorian Date object if necessary
11
+ value = value.gregorian unless value.gregorian?
12
+ value.strftime("%Y-%m-%d")
13
+ else
14
+ value
15
+ end
10
16
  end
11
17
  end
12
18
  end
@@ -10,7 +10,7 @@ module PG
10
10
  # As soon as this class is used, it requires the ruby standard library 'json'.
11
11
  class JSON < SimpleEncoder
12
12
  def encode(value)
13
- ::JSON.generate(value, quirks_mode: true)
13
+ ::JSON.generate(value)
14
14
  end
15
15
  end
16
16
  end
data/lib/pg/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module PG
3
3
  # Library version
4
- VERSION = '1.6.3'
4
+ VERSION = '1.7.0'
5
5
  end
@@ -14,7 +14,7 @@ services:
14
14
  start_period: 10s
15
15
 
16
16
  pg:
17
- image: ruby:3.0
17
+ image: ruby:4.0
18
18
  working_dir: /app
19
19
  volumes:
20
20
  - .:/app
data/pg.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.description = "Pg is the Ruby interface to the PostgreSQL RDBMS. It works with PostgreSQL 10 and later."
14
14
  spec.homepage = "https://github.com/ged/ruby-pg"
15
15
  spec.license = "BSD-2-Clause"
16
- spec.required_ruby_version = ">= 2.7"
16
+ spec.required_ruby_version = ">= 3.1"
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = "https://github.com/ged/ruby-pg"
@@ -5,7 +5,7 @@ require 'pg'
5
5
  $stdout.sync = true
6
6
 
7
7
  # This is a example of how to mix and match synchronous and async APIs. In this case,
8
- # the connection to the server is made syncrhonously, and then queries are
8
+ # the connection to the server is made synchronously, and then queries are
9
9
  # asynchronous.
10
10
 
11
11
  TIMEOUT = 5.0 # seconds to wait for an async operation to complete
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.7.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Michael Granger
@@ -11,8 +11,8 @@ cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIEBDCCAmygAwIBAgIBBDANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
14
- L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yNTEyMjkyMDMyMzFaFw0yNjEy
15
- MjkyMDMyMzFaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
14
+ L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yNjAyMTQyMTU3MTlaFw0yNzAy
15
+ MTQyMTU3MTlaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
16
16
  PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
17
17
  mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
18
18
  eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
@@ -23,15 +23,15 @@ cert_chain:
23
23
  chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
24
24
  9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjOTA3MAkG
25
25
  A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQ4h1tIyvdUWtMI739xMzTR
26
- 7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAUVIier9xybHmXNsj801xD+Q7Jz7wpRsf
27
- fMHpV2sAzvYcAa7pn+mbu9nf7RUhe5hiaUv88Usk9nRUYYrjBOO5RuD+wYNowpcE
28
- kxUiTAP/fgUBdW6hYUJy57CH3xUD6tj1Cg9hxdKy7jItZXbfhX+qPq2BwGaXz7gn
29
- nhrALITRmpuPnlsccM94dgSArCInSo2SEc12h2oB6FAnFG1Lre3dmQamI5q1EKp0
30
- Yafb2+cPbFcVYUdE50wf+cdeGDOsCGlAmo2OGqXWxTP2hIfyhsFoamD6UGufLoPG
31
- Dh6tAEZIuEvLjq93qoNceUQn+xxiiIszjY5mkTu9rVY+/gh5PJzu9IHvyIqBpb2o
32
- fdWDISWK+KSLCrqkFtKoliLDTZau73GcYCVOkjca+3cxqABKZ+M8r42Sq8JPxPiv
33
- KyLQBzqPeLN9qRDD1bEFHIcgwdY/zQTs4mWRBSmBWa7w+k8nP8aSV1dN/fvhYwY3
34
- HCQwtPaMYOznIOcc8shL4zLJpcl8uCqE
26
+ 7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAWuY62AlTOhipB443sEkhK0G09vjB3v0j
27
+ 9A2HlHXMOcgilbfbMR7ejT+/ynwdqMkrYCQCvoQH06NgIzFi2u6cKKmb2rWXMAF1
28
+ g0NLTs1h/KFsfwuX7IOQ9LxkMl9jlYWdFptFi9oQhlfgmFAFLiZJzNA0+QZMgW6A
29
+ e3usJh0/pT8E0hLWnJdomEF7pNsFyfKjbp5KWRd585z3dePi0iPcpzdByCnJsO36
30
+ Hyl/JsJZyHwpR6LlgfpXmYFwxeFZvpJg2S9O7Yo+qlgiaIUbnkVxOqfEXhCRZm8d
31
+ vfBZ6NSBwcdh7tXk01Yeqap0OtIE7Ey6C/so7uc3vZE6lPZ8xumMYyZ1lJTk5WwS
32
+ qgNbJXZWC/Q9RqPbOZXj4Q2Rq0iFfGNPlkKVeDabXfAASAVtrUb1gByb2b53Kq6N
33
+ OZ/RmpA4/XcoJIE2pnoUq8j6WCeNJ9m11JS2NmgUvYtdMFgMJWoH/hiF71l8dH3v
34
+ 76Q140MRgXCuR7RMxztucM6XZQbk1VSO
35
35
  -----END CERTIFICATE-----
36
36
  date: 1980-01-02 00:00:00.000000000 Z
37
37
  dependencies: []
@@ -117,6 +117,7 @@ files:
117
117
  - certs/larskanis-2022.pem
118
118
  - certs/larskanis-2023.pem
119
119
  - certs/larskanis-2024.pem
120
+ - certs/larskanis-2026.pem
120
121
  - ext/errorcodes.def
121
122
  - ext/errorcodes.rb
122
123
  - ext/errorcodes.txt
@@ -149,7 +150,6 @@ files:
149
150
  - ext/vc/pg.sln
150
151
  - ext/vc/pg_18/pg.vcproj
151
152
  - ext/vc/pg_19/pg_19.vcproj
152
- - lib/3.0/pg_ext.so
153
153
  - lib/3.1/pg_ext.so
154
154
  - lib/3.2/pg_ext.so
155
155
  - lib/3.3/pg_ext.so
@@ -200,11 +200,9 @@ files:
200
200
  - misc/yugabyte/pg-test.rb
201
201
  - pg.gemspec
202
202
  - ports/aarch64-linux/lib/libpq-ruby-pg.so.1
203
- - ports/patches/krb5/1.22.1/0001-Allow-static-linking-krb5-library.patch
204
- - ports/patches/krb5/1.22.1/0002-unknown-command-line-option-on-clang.patch
205
- - ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch
206
- - ports/patches/postgresql/18.1/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch
207
- - ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch
203
+ - ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch
204
+ - ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch
205
+ - ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch
208
206
  - rakelib/pg_gem_helper.rb
209
207
  - rakelib/task_extension.rb
210
208
  - sample/array_insert.rb
@@ -245,7 +243,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
245
243
  requirements:
246
244
  - - ">="
247
245
  - !ruby/object:Gem::Version
248
- version: '3.0'
246
+ version: '3.1'
249
247
  - - "<"
250
248
  - !ruby/object:Gem::Version
251
249
  version: 4.1.dev
metadata.gz.sig CHANGED
Binary file
data/lib/3.0/pg_ext.so DELETED
Binary file
@@ -1,21 +0,0 @@
1
- --- a/Configurations/10-main.conf
2
- +++ b/Configurations/10-main.conf
3
- @@ -1603,6 +1603,18 @@
4
- multilib => "64",
5
- },
6
-
7
- + "mingwarm64" => {
8
- + inherit_from => [ "mingw-common" ],
9
- + cflags => "",
10
- + sys_id => "MINGWARM64",
11
- + bn_ops => add("SIXTY_FOUR_BIT"),
12
- + asm_arch => 'aarch64',
13
- + uplink_arch => 'armv8',
14
- + perlasm_scheme => "win64",
15
- + shared_rcflag => "",
16
- + multilib => "-arm64",
17
- + },
18
- +
19
- #### UEFI
20
- "UEFI" => {
21
- inherit_from => [ "BASE_unix" ],