diff --git a/ext/extconf.rb b/ext/extconf.rb index 4e293b080..b36a4c3a8 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -316,6 +316,7 @@ module PG src + " int con(){ return PGRES_PIPELINE_SYNC; }" end have_func 'PQsetChunkedRowsMode', 'libpq-fe.h' # since PostgreSQL-17 +have_func 'PQfullProtocolVersion', 'libpq-fe.h' # since PostgreSQL-18 have_func 'timegm' have_func 'rb_io_wait' # since ruby-3.0 have_func 'rb_io_descriptor' # since ruby-3.1 diff --git a/ext/pg_connection.c b/ext/pg_connection.c index 696f26f6f..6d4300be1 100644 --- a/ext/pg_connection.c +++ b/ext/pg_connection.c @@ -865,6 +865,31 @@ pgconn_protocol_version(VALUE self) return INT2NUM(protocol_version); } +#ifdef HAVE_PQFULLPROTOCOLVERSION +/* + * call-seq: + * conn.full_protocol_version -> Integer + * + * Interrogates the frontend/backend protocol being used, including minor version. + * + * Applications might wish to use this function to determine whether certain features are supported. + * The result is the major version multiplied by 10000 added to the minor version, e.g. 30002 for version 3.2. + * The protocol version will not change after connection startup is complete, but it could theoretically change during a connection reset. + * The 3.0 protocol is supported by PostgreSQL server versions 7.4 and above. + * + * PG::ConnectionBad is raised if the connection is bad. + */ +static VALUE +pgconn_full_protocol_version(VALUE self) +{ + int protocol_version = PQfullProtocolVersion(pg_get_pgconn(self)); + if (protocol_version == 0) { + pg_raise_conn_error( rb_eConnectionBad, self, "PQfullProtocolVersion() can't get protocol version"); + } + return INT2NUM(protocol_version); +} +#endif + /* * call-seq: * conn.server_version -> Integer @@ -4733,6 +4758,9 @@ init_pg_connection(void) rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0); rb_define_method(rb_cPGconn, "parameter_status", pgconn_parameter_status, 1); rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0); +#ifdef HAVE_PQFULLPROTOCOLVERSION + rb_define_method(rb_cPGconn, "full_protocol_version", pgconn_full_protocol_version, 0); +#endif rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0); rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0); rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0); diff --git a/spec/helpers.rb b/spec/helpers.rb index 5935e2034..6ebb0604f 100644 --- a/spec/helpers.rb +++ b/spec/helpers.rb @@ -682,6 +682,7 @@ def set_etc_hosts(hostaddr, hostname) config.filter_run_excluding( :postgresql_12 ) if PG.library_version < 120000 config.filter_run_excluding( :postgresql_14 ) if PG.library_version < 140000 config.filter_run_excluding( :postgresql_17 ) if PG.library_version < 170000 + config.filter_run_excluding( :postgresql_18 ) if PG.library_version < 180000 config.filter_run_excluding( :unix_socket ) if RUBY_PLATFORM=~/mingw|mswin/i config.filter_run_excluding( :scheduler ) if RUBY_VERSION < "3.0" || (RUBY_PLATFORM =~ /mingw|mswin/ && RUBY_VERSION < "3.1") || !Fiber.respond_to?(:scheduler) config.filter_run_excluding( :scheduler_address_resolve ) if RUBY_VERSION < "3.1" diff --git a/spec/pg/connection_spec.rb b/spec/pg/connection_spec.rb index 9ac2a2475..7763493a2 100644 --- a/spec/pg/connection_spec.rb +++ b/spec/pg/connection_spec.rb @@ -976,6 +976,18 @@ end end + context :protocol_version, :postgresql_18 do + it "should retrieve the wrie protocol version" do + expect( @conn.full_protocol_version ).to eq 30000 + end + + it "should raise an error on a bad connection" do + conn = PG::Connection.connect_start( @conninfo ) + conn.finish + expect{ conn.full_protocol_version }.to raise_error(PG::ConnectionBad) + end + end + it "allows a query to be cancelled" do start = Time.now @conn.set_notice_processor do |notice|