Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Added:

- Add PG::Connection#embed_params and keyword `:typename` for its parameter casting. [#726](https://github.com/ged/ruby-pg/pull/726)
This allows to generate SQL strings with embedded parameters for easier debugging.
- Add PG:Connection#full_protocol_version which is new in PostgreSQL-18 [#695](https://github.com/ged/ruby-pg/pull/695)
- Add PG::Connection#full_protocol_version which is new in PostgreSQL-18 [#695](https://github.com/ged/ruby-pg/pull/695)
- Add PG::Result#each_tuple [#675](https://github.com/ged/ruby-pg/pull/675)
- Add PG::TypeMap#query_param_encoders to retrieve encoders. [#726](https://github.com/ged/ruby-pg/pull/726)
- Deduplicate result field name strings for better performance. [#750](https://github.com/ged/ruby-pg/pull/750)
Expand Down
5 changes: 3 additions & 2 deletions ext/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,9 @@ module PG
end

have_func 'PQencryptPasswordConn', 'libpq-fe.h' or # since PostgreSQL-10
abort "Your PostgreSQL is too old. Either install an older version " +
"of this gem or upgrade your database to at least PostgreSQL-10."
abort "Your PostgreSQL client library (libpq) is too old. " +
"Either install an older version of this gem " +
"or upgrade your database to at least PostgreSQL-10."
# optional headers/functions
have_func 'PQresultMemorySize', 'libpq-fe.h' # since PostgreSQL-12
have_func 'timegm'
Expand Down
8 changes: 2 additions & 6 deletions ext/pg.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,14 +384,10 @@ Init_pg_ext(void)
rb_define_const(rb_mPGconstants, "CONNECTION_SSL_STARTUP", INT2FIX(CONNECTION_SSL_STARTUP));
/* Internal state - PG.connect() needed. */
rb_define_const(rb_mPGconstants, "CONNECTION_NEEDED", INT2FIX(CONNECTION_NEEDED));
#if PG_MAJORVERSION_NUM >= 10
/* Checking if session is read-write. Available since PostgreSQL-10. */
/* Checking if session is read-write. */
rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_WRITABLE", INT2FIX(CONNECTION_CHECK_WRITABLE));
#endif
#if PG_MAJORVERSION_NUM >= 10
/* Consuming any extra messages. Available since PostgreSQL-10. */
/* Consuming any extra messages. */
rb_define_const(rb_mPGconstants, "CONNECTION_CONSUME", INT2FIX(CONNECTION_CONSUME));
#endif
#if PG_MAJORVERSION_NUM >= 12
/* Negotiating GSSAPI. Available since PostgreSQL-12. */
rb_define_const(rb_mPGconstants, "CONNECTION_GSS_STARTUP", INT2FIX(CONNECTION_GSS_STARTUP));
Expand Down
2 changes: 2 additions & 0 deletions ext/pg_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,8 @@ pgconn_protocol_version(VALUE self)
* The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above.
*
* PG::ConnectionBad is raised if the connection is bad.
*
* Available since PostgreSQL-18.
*/
static VALUE
pgconn_full_protocol_version(VALUE self)
Expand Down
54 changes: 25 additions & 29 deletions lib/pg/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -551,33 +551,30 @@ def pipeline_sync(*args)
alias async_pipeline_sync pipeline_sync
end

if method_defined? :sync_encrypt_password
# call-seq:
# conn.encrypt_password( password, username, algorithm=nil ) -> String
#
# This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
# 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.
# Instead, use this function to convert the password to encrypted form before it is sent.
#
# The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
# +algorithm+ specifies the encryption algorithm to use to encrypt the password.
# 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).
# Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
# If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
# That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
# 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.
#
# Return value is the encrypted password.
# The caller can assume the string doesn't contain any special characters that would require escaping.
#
# Available since PostgreSQL-10.
# See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
def encrypt_password( password, username, algorithm=nil )
algorithm ||= exec("SHOW password_encryption").getvalue(0,0)
sync_encrypt_password(password, username, algorithm)
end
alias async_encrypt_password encrypt_password
# call-seq:
# conn.encrypt_password( password, username, algorithm=nil ) -> String
#
# This function is intended to be used by client applications that wish to send commands like <tt>ALTER USER joe PASSWORD 'pwd'</tt>.
# 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.
# Instead, use this function to convert the password to encrypted form before it is sent.
#
# The +password+ and +username+ arguments are the cleartext password, and the SQL name of the user it is for.
# +algorithm+ specifies the encryption algorithm to use to encrypt the password.
# 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).
# Note that support for +scram-sha-256+ was introduced in PostgreSQL version 10, and will not work correctly with older server versions.
# If algorithm is omitted or +nil+, this function will query the server for the current value of the +password_encryption+ setting.
# That can block, and will fail if the current transaction is aborted, or if the connection is busy executing another query.
# 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.
#
# Return value is the encrypted password.
# The caller can assume the string doesn't contain any special characters that would require escaping.
#
# See also corresponding {libpq function}[https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN].
def encrypt_password( password, username, algorithm=nil )
algorithm ||= exec("SHOW password_encryption").getvalue(0,0)
sync_encrypt_password(password, username, algorithm)
end
alias async_encrypt_password encrypt_password

# call-seq:
# conn.reset()
Expand Down Expand Up @@ -971,7 +968,6 @@ def new(*args)

# Resolve DNS in Ruby to avoid blocking state while connecting.
# Multiple comma-separated values are generated, if the hostname resolves to both IPv4 and IPv6 addresses.
# This requires PostgreSQL-10+, so no DNS resolving is done on earlier versions.
private def resolve_hosts(iopts)
ihosts = iopts[:host].split(",", -1)
iports = iopts[:port].split(",", -1)
Expand Down Expand Up @@ -1027,8 +1023,8 @@ def new(*args)
# So, pass params through and let libpq resolve the service, possibly blocking the Thread.scheduler.
# This ensures the processing order of libpq which is:
# connection string => service file => environment variable => compiled default
elsif iopts_with_defaults[:host] && !iopts_with_defaults[:host].empty? && PG.library_version >= 100000
# Do host resolution to avoid blocking Thread.scheduler while DNS queries.
elsif iopts_with_defaults[:host] && !iopts_with_defaults[:host].empty?
# Do host resolution in Ruby to avoid blocking Thread.scheduler while DNS queries in libpq.
iopts_for_reset = iopts_with_defaults
iopts = resolve_hosts(iopts_with_defaults)
else
Expand Down
10 changes: 2 additions & 8 deletions spec/pg/connection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2848,14 +2848,8 @@ def wait_check_socket(conn)
end

it "shouldn't type map params unless requested" do
if @conn.server_version < 100000
expect{
@conn.exec_params( "SELECT $1", [5] )
}.to raise_error(PG::IndeterminateDatatype){|err| expect(err).to have_attributes(connection: @conn) }
else
# PostgreSQL-10 maps to TEXT type (OID 25)
expect( @conn.exec_params( "SELECT $1", [5] ).ftype(0)).to eq(25)
end
# PostgreSQL maps to TEXT type (OID 25)
expect( @conn.exec_params( "SELECT $1", [5] ).ftype(0)).to eq(25)
end

it "should raise an error on invalid encoder to put_copy_data" do
Expand Down
Loading