pg 1.3.5-x86-mingw32 → 1.4.2-x86-mingw32
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.rdoc +40 -0
- data/Rakefile.cross +2 -2
- data/ext/extconf.rb +0 -31
- data/ext/pg_connection.c +205 -177
- data/ext/pg_result.c +2 -2
- data/lib/2.5/pg_ext.so +0 -0
- data/lib/2.6/pg_ext.so +0 -0
- data/lib/2.7/pg_ext.so +0 -0
- data/lib/3.0/pg_ext.so +0 -0
- data/lib/3.1/pg_ext.so +0 -0
- data/lib/pg/connection.rb +174 -118
- data/lib/pg/exceptions.rb +7 -1
- data/lib/pg/version.rb +1 -1
- data/lib/pg.rb +4 -4
- data/lib/x86-mingw32/libpq.dll +0 -0
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
    
        data/ext/pg_result.c
    CHANGED
    
    | @@ -1476,10 +1476,10 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int, void*), void* d | |
| 1476 1476 |  | 
| 1477 1477 | 
             
            		pgresult = gvl_PQgetResult(pgconn);
         | 
| 1478 1478 | 
             
            		if( pgresult == NULL )
         | 
| 1479 | 
            -
            			rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another  | 
| 1479 | 
            +
            			rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
         | 
| 1480 1480 |  | 
| 1481 1481 | 
             
            		if( nfields != PQnfields(pgresult) )
         | 
| 1482 | 
            -
            			rb_raise( rb_eInvalidChangeOfResultFields, "number of fields  | 
| 1482 | 
            +
            			rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, PQnfields(pgresult));
         | 
| 1483 1483 |  | 
| 1484 1484 | 
             
            		this->pgresult = pgresult;
         | 
| 1485 1485 | 
             
            	}
         | 
    
        data/lib/2.5/pg_ext.so
    CHANGED
    
    | Binary file | 
    
        data/lib/2.6/pg_ext.so
    CHANGED
    
    | Binary file | 
    
        data/lib/2.7/pg_ext.so
    CHANGED
    
    | Binary file | 
    
        data/lib/3.0/pg_ext.so
    CHANGED
    
    | Binary file | 
    
        data/lib/3.1/pg_ext.so
    CHANGED
    
    | Binary file | 
    
        data/lib/pg/connection.rb
    CHANGED
    
    | @@ -46,37 +46,6 @@ class PG::Connection | |
| 46 46 | 
             
            		hash.map { |k,v| "#{k}=#{quote_connstr(v)}" }.join( ' ' )
         | 
| 47 47 | 
             
            	end
         | 
| 48 48 |  | 
| 49 | 
            -
            	# Decode a connection string to Hash options
         | 
| 50 | 
            -
            	#
         | 
| 51 | 
            -
            	# Value are properly unquoted and unescaped.
         | 
| 52 | 
            -
            	def self.connect_string_to_hash( str )
         | 
| 53 | 
            -
            		options = {}
         | 
| 54 | 
            -
            		key = nil
         | 
| 55 | 
            -
            		value = String.new
         | 
| 56 | 
            -
            		str.scan(/\G\s*(?>([^\s\\\']+)\s*=\s*|([^\s\\\']+)|'((?:[^\'\\]|\\.)*)'|(\\.?)|(\S))(\s|\z)?/m) do
         | 
| 57 | 
            -
            					|k, word, sq, esc, garbage, sep|
         | 
| 58 | 
            -
            			raise ArgumentError, "unterminated quoted string in connection info string: #{str.inspect}" if garbage
         | 
| 59 | 
            -
            			if k
         | 
| 60 | 
            -
            				key = k
         | 
| 61 | 
            -
            			else
         | 
| 62 | 
            -
            				value << (word || (sq || esc).gsub(/\\(.)/, '\\1'))
         | 
| 63 | 
            -
            			end
         | 
| 64 | 
            -
            			if sep
         | 
| 65 | 
            -
            				raise ArgumentError, "missing = after #{value.inspect}" unless key
         | 
| 66 | 
            -
            				options[key.to_sym] = value
         | 
| 67 | 
            -
            				key = nil
         | 
| 68 | 
            -
            				value = String.new
         | 
| 69 | 
            -
            			end
         | 
| 70 | 
            -
            		end
         | 
| 71 | 
            -
            		options
         | 
| 72 | 
            -
            	end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
            	# URI defined in RFC3986
         | 
| 75 | 
            -
            	# This regexp is modified to allow host to specify multiple comma separated components captured as <hostports> and to disallow comma in hostnames.
         | 
| 76 | 
            -
            	# Taken from: https://github.com/ruby/ruby/blob/be04006c7d2f9aeb7e9d8d09d945b3a9c7850202/lib/uri/rfc3986_parser.rb#L6
         | 
| 77 | 
            -
            	HOST_AND_PORT = /(?<hostport>(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[-\.!$&-+0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)/
         | 
| 78 | 
            -
            	POSTGRESQL_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<hostports>#{HOST_AND_PORT}(?:,\g<hostport>)*))(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
         | 
| 79 | 
            -
             | 
| 80 49 | 
             
            	# Parse the connection +args+ into a connection-parameter string.
         | 
| 81 50 | 
             
            	# See PG::Connection.new for valid arguments.
         | 
| 82 51 | 
             
            	#
         | 
| @@ -87,91 +56,43 @@ class PG::Connection | |
| 87 56 | 
             
            	# * URI object
         | 
| 88 57 | 
             
            	# * positional arguments
         | 
| 89 58 | 
             
            	#
         | 
| 90 | 
            -
            	# The method adds the option " | 
| 91 | 
            -
            	#  | 
| 92 | 
            -
            	 | 
| 93 | 
            -
            	def self::parse_connect_args( *args )
         | 
| 59 | 
            +
            	# The method adds the option "fallback_application_name" if it isn't already set.
         | 
| 60 | 
            +
            	# It returns a connection string with "key=value" pairs.
         | 
| 61 | 
            +
            	def self.parse_connect_args( *args )
         | 
| 94 62 | 
             
            		hash_arg = args.last.is_a?( Hash ) ? args.pop.transform_keys(&:to_sym) : {}
         | 
| 95 | 
            -
            		option_string = ""
         | 
| 96 63 | 
             
            		iopts = {}
         | 
| 97 64 |  | 
| 98 65 | 
             
            		if args.length == 1
         | 
| 99 66 | 
             
            			case args.first
         | 
| 100 | 
            -
            			when URI,  | 
| 101 | 
            -
            				 | 
| 102 | 
            -
            				 | 
| 103 | 
            -
            				if  | 
| 104 | 
            -
            					iopts = URI.decode_www_form(uri_match['query']).to_h.transform_keys(&:to_sym)
         | 
| 105 | 
            -
            				end
         | 
| 106 | 
            -
            				# extract "host1,host2" from "host1:5432,host2:5432"
         | 
| 107 | 
            -
            				iopts[:host] = uri_match['hostports'].split(',', -1).map do |hostport|
         | 
| 108 | 
            -
            					hostmatch = /\A#{HOST_AND_PORT}\z/.match(hostport)
         | 
| 109 | 
            -
            					hostmatch['IPv6address'] || hostmatch['IPv4address'] || hostmatch['reg-name']&.gsub(/%(\h\h)/){ $1.hex.chr }
         | 
| 110 | 
            -
            				end.join(',')
         | 
| 111 | 
            -
            				oopts = {}
         | 
| 112 | 
            -
            			when /=/
         | 
| 113 | 
            -
            				# Option string style
         | 
| 114 | 
            -
            				option_string = args.first.to_s
         | 
| 115 | 
            -
            				iopts = connect_string_to_hash(option_string)
         | 
| 116 | 
            -
            				oopts = {}
         | 
| 67 | 
            +
            			when URI, /=/, /:\/\//
         | 
| 68 | 
            +
            				# Option or URL string style
         | 
| 69 | 
            +
            				conn_string = args.first.to_s
         | 
| 70 | 
            +
            				iopts = PG::Connection.conninfo_parse(conn_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
         | 
| 117 71 | 
             
            			else
         | 
| 118 72 | 
             
            				# Positional parameters (only host given)
         | 
| 119 73 | 
             
            				iopts[CONNECT_ARGUMENT_ORDER.first.to_sym] = args.first
         | 
| 120 | 
            -
            				oopts = iopts.dup
         | 
| 121 74 | 
             
            			end
         | 
| 122 75 | 
             
            		else
         | 
| 123 | 
            -
            			# Positional parameters
         | 
| 76 | 
            +
            			# Positional parameters with host and more
         | 
| 124 77 | 
             
            			max = CONNECT_ARGUMENT_ORDER.length
         | 
| 125 78 | 
             
            			raise ArgumentError,
         | 
| 126 | 
            -
             | 
| 79 | 
            +
            					"Extra positional parameter %d: %p" % [ max + 1, args[max] ] if args.length > max
         | 
| 127 80 |  | 
| 128 81 | 
             
            			CONNECT_ARGUMENT_ORDER.zip( args ) do |(k,v)|
         | 
| 129 82 | 
             
            				iopts[ k.to_sym ] = v if v
         | 
| 130 83 | 
             
            			end
         | 
| 131 84 | 
             
            			iopts.delete(:tty) # ignore obsolete tty parameter
         | 
| 132 | 
            -
            			oopts = iopts.dup
         | 
| 133 85 | 
             
            		end
         | 
| 134 86 |  | 
| 135 87 | 
             
            		iopts.merge!( hash_arg )
         | 
| 136 | 
            -
            		oopts.merge!( hash_arg )
         | 
| 137 | 
            -
             | 
| 138 | 
            -
            		# Resolve DNS in Ruby to avoid blocking state while connecting, when it ...
         | 
| 139 | 
            -
            		if (host=iopts[:host]) && !iopts[:hostaddr]
         | 
| 140 | 
            -
            			hostaddrs = host.split(",", -1).map do |mhost|
         | 
| 141 | 
            -
            				if !mhost.empty? && !mhost.start_with?("/") &&  # isn't UnixSocket
         | 
| 142 | 
            -
            						# isn't a path on Windows
         | 
| 143 | 
            -
            						(RUBY_PLATFORM !~ /mingw|mswin/ || mhost !~ /\A\w:[\/\\]/)
         | 
| 144 | 
            -
             | 
| 145 | 
            -
            					if Fiber.respond_to?(:scheduler) &&
         | 
| 146 | 
            -
            							Fiber.scheduler &&
         | 
| 147 | 
            -
            							RUBY_VERSION < '3.1.'
         | 
| 148 | 
            -
             | 
| 149 | 
            -
            						# Use a second thread to avoid blocking of the scheduler.
         | 
| 150 | 
            -
            						# `IPSocket.getaddress` isn't fiber aware before ruby-3.1.
         | 
| 151 | 
            -
            						Thread.new{ IPSocket.getaddress(mhost) rescue '' }.value
         | 
| 152 | 
            -
            					else
         | 
| 153 | 
            -
            						IPSocket.getaddress(mhost) rescue ''
         | 
| 154 | 
            -
            					end
         | 
| 155 | 
            -
            				end
         | 
| 156 | 
            -
            			end
         | 
| 157 | 
            -
            			oopts[:hostaddr] = hostaddrs.join(",") if hostaddrs.any?
         | 
| 158 | 
            -
            		end
         | 
| 159 88 |  | 
| 160 89 | 
             
            		if !iopts[:fallback_application_name]
         | 
| 161 | 
            -
            			 | 
| 90 | 
            +
            			iopts[:fallback_application_name] = $0.sub( /^(.{30}).{4,}(.{30})$/ ){ $1+"..."+$2 }
         | 
| 162 91 | 
             
            		end
         | 
| 163 92 |  | 
| 164 | 
            -
            		 | 
| 165 | 
            -
            			uri += uri_match['query'] ? "&" : "?"
         | 
| 166 | 
            -
            			uri += URI.encode_www_form( oopts )
         | 
| 167 | 
            -
            			return uri
         | 
| 168 | 
            -
            		else
         | 
| 169 | 
            -
            			option_string += ' ' unless option_string.empty? && oopts.empty?
         | 
| 170 | 
            -
            			return option_string + connect_hash_to_string(oopts)
         | 
| 171 | 
            -
            		end
         | 
| 93 | 
            +
            		return connect_hash_to_string(iopts)
         | 
| 172 94 | 
             
            	end
         | 
| 173 95 |  | 
| 174 | 
            -
             | 
| 175 96 | 
             
            	#  call-seq:
         | 
| 176 97 | 
             
            	#     conn.copy_data( sql [, coder] ) {|sql_result| ... } -> PG::Result
         | 
| 177 98 | 
             
            	#
         | 
| @@ -241,7 +162,7 @@ class PG::Connection | |
| 241 162 | 
             
            	#   ["more", "data", "to", "copy"]
         | 
| 242 163 |  | 
| 243 164 | 
             
            	def copy_data( sql, coder=nil )
         | 
| 244 | 
            -
            		raise PG::NotInBlockingMode | 
| 165 | 
            +
            		raise PG::NotInBlockingMode.new("copy_data can not be used in nonblocking mode", connection: self) if nonblocking?
         | 
| 245 166 | 
             
            		res = exec( sql )
         | 
| 246 167 |  | 
| 247 168 | 
             
            		case res.result_status
         | 
| @@ -273,11 +194,15 @@ class PG::Connection | |
| 273 194 | 
             
            				yield res
         | 
| 274 195 | 
             
            			rescue Exception => err
         | 
| 275 196 | 
             
            				cancel
         | 
| 276 | 
            -
            				 | 
| 197 | 
            +
            				begin
         | 
| 198 | 
            +
            					while get_copy_data
         | 
| 199 | 
            +
            					end
         | 
| 200 | 
            +
            				rescue PG::Error
         | 
| 201 | 
            +
            					# Ignore error in cleanup to avoid losing original exception
         | 
| 277 202 | 
             
            				end
         | 
| 278 203 | 
             
            				while get_result
         | 
| 279 204 | 
             
            				end
         | 
| 280 | 
            -
            				raise
         | 
| 205 | 
            +
            				raise err
         | 
| 281 206 | 
             
            			else
         | 
| 282 207 | 
             
            				res = get_last_result
         | 
| 283 208 | 
             
            				if !res || res.result_status != PGRES_COMMAND_OK
         | 
| @@ -285,7 +210,7 @@ class PG::Connection | |
| 285 210 | 
             
            					end
         | 
| 286 211 | 
             
            					while get_result
         | 
| 287 212 | 
             
            					end
         | 
| 288 | 
            -
            					raise PG::NotAllCopyDataRetrieved | 
| 213 | 
            +
            					raise PG::NotAllCopyDataRetrieved.new("Not all COPY data retrieved", connection: self)
         | 
| 289 214 | 
             
            				end
         | 
| 290 215 | 
             
            				res
         | 
| 291 216 | 
             
            			ensure
         | 
| @@ -310,16 +235,17 @@ class PG::Connection | |
| 310 235 | 
             
            	# and a +COMMIT+ at the end of the block, or
         | 
| 311 236 | 
             
            	# +ROLLBACK+ if any exception occurs.
         | 
| 312 237 | 
             
            	def transaction
         | 
| 238 | 
            +
            		rollback = false
         | 
| 313 239 | 
             
            		exec "BEGIN"
         | 
| 314 | 
            -
            		 | 
| 240 | 
            +
            		yield(self)
         | 
| 315 241 | 
             
            	rescue Exception
         | 
| 242 | 
            +
            		rollback = true
         | 
| 316 243 | 
             
            		cancel if transaction_status == PG::PQTRANS_ACTIVE
         | 
| 317 244 | 
             
            		block
         | 
| 318 245 | 
             
            		exec "ROLLBACK"
         | 
| 319 246 | 
             
            		raise
         | 
| 320 | 
            -
            	 | 
| 321 | 
            -
            		exec "COMMIT"
         | 
| 322 | 
            -
            		res
         | 
| 247 | 
            +
            	ensure
         | 
| 248 | 
            +
            		exec "COMMIT" unless rollback
         | 
| 323 249 | 
             
            	end
         | 
| 324 250 |  | 
| 325 251 | 
             
            	### Returns an array of Hashes with connection defaults. See ::conndefaults
         | 
| @@ -482,10 +408,10 @@ class PG::Connection | |
| 482 408 | 
             
            	# See also #copy_data.
         | 
| 483 409 | 
             
            	#
         | 
| 484 410 | 
             
            	def put_copy_data(buffer, encoder=nil)
         | 
| 485 | 
            -
            		until sync_put_copy_data(buffer, encoder)
         | 
| 486 | 
            -
            			flush
         | 
| 411 | 
            +
            		until res=sync_put_copy_data(buffer, encoder)
         | 
| 412 | 
            +
            			res = flush
         | 
| 487 413 | 
             
            		end
         | 
| 488 | 
            -
            		 | 
| 414 | 
            +
            		res
         | 
| 489 415 | 
             
            	end
         | 
| 490 416 | 
             
            	alias async_put_copy_data put_copy_data
         | 
| 491 417 |  | 
| @@ -545,6 +471,7 @@ class PG::Connection | |
| 545 471 | 
             
            	def reset
         | 
| 546 472 | 
             
            		reset_start
         | 
| 547 473 | 
             
            		async_connect_or_reset(:reset_poll)
         | 
| 474 | 
            +
            		self
         | 
| 548 475 | 
             
            	end
         | 
| 549 476 | 
             
            	alias async_reset reset
         | 
| 550 477 |  | 
| @@ -613,28 +540,62 @@ class PG::Connection | |
| 613 540 |  | 
| 614 541 | 
             
            	private def async_connect_or_reset(poll_meth)
         | 
| 615 542 | 
             
            		# Track the progress of the connection, waiting for the socket to become readable/writable before polling it
         | 
| 543 | 
            +
             | 
| 544 | 
            +
            		if (timeo = conninfo_hash[:connect_timeout].to_i) && timeo > 0
         | 
| 545 | 
            +
            			# Lowest timeout is 2 seconds - like in libpq
         | 
| 546 | 
            +
            			timeo = [timeo, 2].max
         | 
| 547 | 
            +
            			stop_time = timeo + Process.clock_gettime(Process::CLOCK_MONOTONIC)
         | 
| 548 | 
            +
            		end
         | 
| 549 | 
            +
             | 
| 616 550 | 
             
            		poll_status = PG::PGRES_POLLING_WRITING
         | 
| 617 551 | 
             
            		until poll_status == PG::PGRES_POLLING_OK ||
         | 
| 618 552 | 
             
            				poll_status == PG::PGRES_POLLING_FAILED
         | 
| 619 553 |  | 
| 620 | 
            -
            			 | 
| 621 | 
            -
            			 | 
| 622 | 
            -
             | 
| 623 | 
            -
            				 | 
| 554 | 
            +
            			timeout = stop_time&.-(Process.clock_gettime(Process::CLOCK_MONOTONIC))
         | 
| 555 | 
            +
            			event = if !timeout || timeout >= 0
         | 
| 556 | 
            +
            				# If the socket needs to read, wait 'til it becomes readable to poll again
         | 
| 557 | 
            +
            				case poll_status
         | 
| 558 | 
            +
            				when PG::PGRES_POLLING_READING
         | 
| 559 | 
            +
            					if defined?(IO::READABLE) # ruby-3.0+
         | 
| 560 | 
            +
            						socket_io.wait(IO::READABLE | IO::PRIORITY, timeout)
         | 
| 561 | 
            +
            					else
         | 
| 562 | 
            +
            						IO.select([socket_io], nil, [socket_io], timeout)
         | 
| 563 | 
            +
            					end
         | 
| 624 564 |  | 
| 625 | 
            -
             | 
| 626 | 
            -
             | 
| 627 | 
            -
             | 
| 565 | 
            +
            				# ...and the same for when the socket needs to write
         | 
| 566 | 
            +
            				when PG::PGRES_POLLING_WRITING
         | 
| 567 | 
            +
            					if defined?(IO::WRITABLE) # ruby-3.0+
         | 
| 568 | 
            +
            						# Use wait instead of wait_readable, since connection errors are delivered as
         | 
| 569 | 
            +
            						# exceptional/priority events on Windows.
         | 
| 570 | 
            +
            						socket_io.wait(IO::WRITABLE | IO::PRIORITY, timeout)
         | 
| 571 | 
            +
            					else
         | 
| 572 | 
            +
            						# io#wait on ruby-2.x doesn't wait for priority, so fallback to IO.select
         | 
| 573 | 
            +
            						IO.select(nil, [socket_io], [socket_io], timeout)
         | 
| 574 | 
            +
            					end
         | 
| 575 | 
            +
            				end
         | 
| 576 | 
            +
            			end
         | 
| 577 | 
            +
            			# connection to server at "localhost" (127.0.0.1), port 5433 failed: timeout expired (PG::ConnectionBad)
         | 
| 578 | 
            +
            			# connection to server on socket "/var/run/postgresql/.s.PGSQL.5433" failed: No such file or directory
         | 
| 579 | 
            +
            			unless event
         | 
| 580 | 
            +
            				if self.class.send(:host_is_named_pipe?, host)
         | 
| 581 | 
            +
            					connhost = "on socket \"#{host}\""
         | 
| 582 | 
            +
            				elsif respond_to?(:hostaddr)
         | 
| 583 | 
            +
            					connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
         | 
| 584 | 
            +
            				else
         | 
| 585 | 
            +
            					connhost = "at \"#{host}\", port #{port}"
         | 
| 586 | 
            +
            				end
         | 
| 587 | 
            +
            				raise PG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", connection: self)
         | 
| 628 588 | 
             
            			end
         | 
| 629 589 |  | 
| 630 590 | 
             
            			# Check to see if it's finished or failed yet
         | 
| 631 591 | 
             
            			poll_status = send( poll_meth )
         | 
| 592 | 
            +
            			@last_status = status unless [PG::CONNECTION_BAD, PG::CONNECTION_OK].include?(status)
         | 
| 632 593 | 
             
            		end
         | 
| 633 594 |  | 
| 634 595 | 
             
            		unless status == PG::CONNECTION_OK
         | 
| 635 596 | 
             
            			msg = error_message
         | 
| 636 597 | 
             
            			finish
         | 
| 637 | 
            -
            			raise PG::ConnectionBad,  | 
| 598 | 
            +
            			raise PG::ConnectionBad.new(msg, connection: self)
         | 
| 638 599 | 
             
            		end
         | 
| 639 600 |  | 
| 640 601 | 
             
            		# Set connection to nonblocking to handle all blocking states in ruby.
         | 
| @@ -642,8 +603,6 @@ class PG::Connection | |
| 642 603 | 
             
            		sync_setnonblocking(true)
         | 
| 643 604 | 
             
            		self.flush_data = true
         | 
| 644 605 | 
             
            		set_default_encoding
         | 
| 645 | 
            -
             | 
| 646 | 
            -
            		self
         | 
| 647 606 | 
             
            	end
         | 
| 648 607 |  | 
| 649 608 | 
             
            	class << self
         | 
| @@ -698,13 +657,17 @@ class PG::Connection | |
| 698 657 | 
             
            		# connection will have its +client_encoding+ set accordingly.
         | 
| 699 658 | 
             
            		#
         | 
| 700 659 | 
             
            		# Raises a PG::Error if the connection fails.
         | 
| 701 | 
            -
            		def new(*args | 
| 702 | 
            -
            			conn =  | 
| 703 | 
            -
             | 
| 704 | 
            -
             | 
| 705 | 
            -
             | 
| 706 | 
            -
             | 
| 707 | 
            -
             | 
| 660 | 
            +
            		def new(*args)
         | 
| 661 | 
            +
            			conn = connect_to_hosts(*args)
         | 
| 662 | 
            +
             | 
| 663 | 
            +
            			if block_given?
         | 
| 664 | 
            +
            				begin
         | 
| 665 | 
            +
            					return yield conn
         | 
| 666 | 
            +
            				ensure
         | 
| 667 | 
            +
            					conn.finish
         | 
| 668 | 
            +
            				end
         | 
| 669 | 
            +
            			end
         | 
| 670 | 
            +
            			conn
         | 
| 708 671 | 
             
            		end
         | 
| 709 672 | 
             
            		alias async_connect new
         | 
| 710 673 | 
             
            		alias connect new
         | 
| @@ -712,6 +675,99 @@ class PG::Connection | |
| 712 675 | 
             
            		alias setdb new
         | 
| 713 676 | 
             
            		alias setdblogin new
         | 
| 714 677 |  | 
| 678 | 
            +
            		private def connect_to_hosts(*args)
         | 
| 679 | 
            +
            			option_string = parse_connect_args(*args)
         | 
| 680 | 
            +
            			iopts = PG::Connection.conninfo_parse(option_string).each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }
         | 
| 681 | 
            +
            			iopts = PG::Connection.conndefaults.each_with_object({}){|h, o| o[h[:keyword].to_sym] = h[:val] if h[:val] }.merge(iopts)
         | 
| 682 | 
            +
             | 
| 683 | 
            +
            			errors = []
         | 
| 684 | 
            +
            			if iopts[:hostaddr]
         | 
| 685 | 
            +
            				# hostaddr is provided -> no need to resolve hostnames
         | 
| 686 | 
            +
            				ihostaddrs = iopts[:hostaddr].split(",", -1)
         | 
| 687 | 
            +
             | 
| 688 | 
            +
            				ihosts = iopts[:host].split(",", -1) if iopts[:host]
         | 
| 689 | 
            +
            				raise PG::ConnectionBad, "could not match #{ihosts.size} host names to #{ihostaddrs.size} hostaddr values" if ihosts && ihosts.size != ihostaddrs.size
         | 
| 690 | 
            +
             | 
| 691 | 
            +
            				iports = iopts[:port].split(",", -1)
         | 
| 692 | 
            +
            				iports = iports * ihostaddrs.size if iports.size == 1
         | 
| 693 | 
            +
            				raise PG::ConnectionBad, "could not match #{iports.size} port numbers to #{ihostaddrs.size} hosts" if iports.size != ihostaddrs.size
         | 
| 694 | 
            +
             | 
| 695 | 
            +
            				# Try to connect to each hostaddr with separate timeout
         | 
| 696 | 
            +
            				ihostaddrs.each_with_index do |ihostaddr, idx|
         | 
| 697 | 
            +
            					oopts = iopts.merge(hostaddr: ihostaddr, port: iports[idx])
         | 
| 698 | 
            +
            					oopts[:host] = ihosts[idx] if ihosts
         | 
| 699 | 
            +
            					c = connect_internal(oopts, errors)
         | 
| 700 | 
            +
            					return c if c
         | 
| 701 | 
            +
            				end
         | 
| 702 | 
            +
            			elsif iopts[:host] && !iopts[:host].empty?
         | 
| 703 | 
            +
            				# Resolve DNS in Ruby to avoid blocking state while connecting, when it ...
         | 
| 704 | 
            +
            				ihosts = iopts[:host].split(",", -1)
         | 
| 705 | 
            +
             | 
| 706 | 
            +
            				iports = iopts[:port].split(",", -1)
         | 
| 707 | 
            +
            				iports = iports * ihosts.size if iports.size == 1
         | 
| 708 | 
            +
            				raise PG::ConnectionBad, "could not match #{iports.size} port numbers to #{ihosts.size} hosts" if iports.size != ihosts.size
         | 
| 709 | 
            +
             | 
| 710 | 
            +
            				ihosts.each_with_index do |mhost, idx|
         | 
| 711 | 
            +
            					unless host_is_named_pipe?(mhost)
         | 
| 712 | 
            +
            						addrs = if Fiber.respond_to?(:scheduler) &&
         | 
| 713 | 
            +
            									Fiber.scheduler &&
         | 
| 714 | 
            +
            									RUBY_VERSION < '3.1.'
         | 
| 715 | 
            +
             | 
| 716 | 
            +
            							# Use a second thread to avoid blocking of the scheduler.
         | 
| 717 | 
            +
            							# `TCPSocket.gethostbyname` isn't fiber aware before ruby-3.1.
         | 
| 718 | 
            +
            							Thread.new{ Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue [''] }.value
         | 
| 719 | 
            +
            						else
         | 
| 720 | 
            +
            							Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue ['']
         | 
| 721 | 
            +
            						end
         | 
| 722 | 
            +
             | 
| 723 | 
            +
            						# Try to connect to each host with separate timeout
         | 
| 724 | 
            +
            						addrs.each do |addr|
         | 
| 725 | 
            +
            							oopts = iopts.merge(hostaddr: addr, host: mhost, port: iports[idx])
         | 
| 726 | 
            +
            							c = connect_internal(oopts, errors)
         | 
| 727 | 
            +
            							return c if c
         | 
| 728 | 
            +
            						end
         | 
| 729 | 
            +
            					else
         | 
| 730 | 
            +
            						# No hostname to resolve (UnixSocket)
         | 
| 731 | 
            +
            						oopts = iopts.merge(host: mhost, port: iports[idx])
         | 
| 732 | 
            +
            						c = connect_internal(oopts, errors)
         | 
| 733 | 
            +
            						return c if c
         | 
| 734 | 
            +
            					end
         | 
| 735 | 
            +
            				end
         | 
| 736 | 
            +
            			else
         | 
| 737 | 
            +
            				# No host given
         | 
| 738 | 
            +
            				return connect_internal(iopts)
         | 
| 739 | 
            +
            			end
         | 
| 740 | 
            +
            			raise PG::ConnectionBad, errors.join("\n")
         | 
| 741 | 
            +
            		end
         | 
| 742 | 
            +
             | 
| 743 | 
            +
            		private def connect_internal(opts, errors=nil)
         | 
| 744 | 
            +
            			begin
         | 
| 745 | 
            +
            				conn = self.connect_start(opts) or
         | 
| 746 | 
            +
            											raise(PG::Error, "Unable to create a new connection")
         | 
| 747 | 
            +
             | 
| 748 | 
            +
            				raise PG::ConnectionBad.new(conn.error_message, connection: self) if conn.status == PG::CONNECTION_BAD
         | 
| 749 | 
            +
             | 
| 750 | 
            +
            				conn.send(:async_connect_or_reset, :connect_poll)
         | 
| 751 | 
            +
            			rescue PG::ConnectionBad => err
         | 
| 752 | 
            +
            				if errors && !(conn && [PG::CONNECTION_AWAITING_RESPONSE].include?(conn.instance_variable_get(:@last_status)))
         | 
| 753 | 
            +
            					# Seems to be no authentication error -> try next host
         | 
| 754 | 
            +
            					errors << err
         | 
| 755 | 
            +
            					return nil
         | 
| 756 | 
            +
            				else
         | 
| 757 | 
            +
            					# Probably an authentication error
         | 
| 758 | 
            +
            					raise
         | 
| 759 | 
            +
            				end
         | 
| 760 | 
            +
            			end
         | 
| 761 | 
            +
            			conn
         | 
| 762 | 
            +
            		end
         | 
| 763 | 
            +
             | 
| 764 | 
            +
            		private def host_is_named_pipe?(host_string)
         | 
| 765 | 
            +
            			host_string.empty? || host_string.start_with?("/") ||  # it's UnixSocket?
         | 
| 766 | 
            +
            							host_string.start_with?("@") ||  # it's UnixSocket in the abstract namespace?
         | 
| 767 | 
            +
            							# it's a path on Windows?
         | 
| 768 | 
            +
            							(RUBY_PLATFORM =~ /mingw|mswin/ && host_string =~ /\A([\/\\]|\w:[\/\\])/)
         | 
| 769 | 
            +
            		end
         | 
| 770 | 
            +
             | 
| 715 771 | 
             
            		# call-seq:
         | 
| 716 772 | 
             
            		#    PG::Connection.ping(connection_hash)       -> Integer
         | 
| 717 773 | 
             
            		#    PG::Connection.ping(connection_string)     -> Integer
         | 
    
        data/lib/pg/exceptions.rb
    CHANGED
    
    | @@ -6,7 +6,13 @@ require 'pg' unless defined?( PG ) | |
| 6 6 |  | 
| 7 7 | 
             
            module PG
         | 
| 8 8 |  | 
| 9 | 
            -
            	class Error < StandardError | 
| 9 | 
            +
            	class Error < StandardError
         | 
| 10 | 
            +
            		def initialize(msg=nil, connection: nil, result: nil)
         | 
| 11 | 
            +
            			@connection = connection
         | 
| 12 | 
            +
            			@result = result
         | 
| 13 | 
            +
            			super(msg)
         | 
| 14 | 
            +
            		end
         | 
| 15 | 
            +
            	end
         | 
| 10 16 |  | 
| 11 17 | 
             
            end # module PG
         | 
| 12 18 |  | 
    
        data/lib/pg/version.rb
    CHANGED
    
    
    
        data/lib/pg.rb
    CHANGED
    
    | @@ -59,14 +59,14 @@ module PG | |
| 59 59 | 
             
            	# Get the PG library version.
         | 
| 60 60 | 
             
            	#
         | 
| 61 61 | 
             
            	# +include_buildnum+ is no longer used and any value passed will be ignored.
         | 
| 62 | 
            -
            	def self | 
| 63 | 
            -
            		 | 
| 62 | 
            +
            	def self.version_string( include_buildnum=nil )
         | 
| 63 | 
            +
            		"%s %s" % [ self.name, VERSION ]
         | 
| 64 64 | 
             
            	end
         | 
| 65 65 |  | 
| 66 66 |  | 
| 67 67 | 
             
            	### Convenience alias for PG::Connection.new.
         | 
| 68 | 
            -
            	def self | 
| 69 | 
            -
            		 | 
| 68 | 
            +
            	def self.connect( *args, &block )
         | 
| 69 | 
            +
            		Connection.new( *args, &block )
         | 
| 70 70 | 
             
            	end
         | 
| 71 71 |  | 
| 72 72 |  | 
    
        data/lib/x86-mingw32/libpq.dll
    CHANGED
    
    | Binary file | 
    
        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. | 
| 4 | 
            +
              version: 1.4.2
         | 
| 5 5 | 
             
            platform: x86-mingw32
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Michael Granger
         | 
| @@ -36,7 +36,7 @@ cert_chain: | |
| 36 36 | 
             
              oL1mUdzB8KrZL4/WbG5YNX6UTtJbIOu9qEFbBAy4/jtIkJX+dlNoFwd4GXQW1YNO
         | 
| 37 37 | 
             
              nA==
         | 
| 38 38 | 
             
              -----END CERTIFICATE-----
         | 
| 39 | 
            -
            date: 2022- | 
| 39 | 
            +
            date: 2022-07-27 00:00:00.000000000 Z
         | 
| 40 40 | 
             
            dependencies: []
         | 
| 41 41 | 
             
            description: Pg is the Ruby interface to the PostgreSQL RDBMS. It works with PostgreSQL
         | 
| 42 42 | 
             
              9.3 and later.
         | 
    
        metadata.gz.sig
    CHANGED
    
    | Binary file |