Skip to content

Commit

Permalink
Add async_set_client_encoding which is compatible to scheduler
Browse files Browse the repository at this point in the history
  • Loading branch information
larskanis committed Sep 10, 2021
1 parent 60c1858 commit ca1bc72
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 12 deletions.
43 changes: 31 additions & 12 deletions ext/pg_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -2906,9 +2906,11 @@ pgconn_get_client_encoding(VALUE self)

/*
* call-seq:
* conn.set_client_encoding( encoding )
* conn.sync_set_client_encoding( encoding )
*
* Sets the client encoding to the _encoding_ String.
* This function has the same behavior as #async_set_client_encoding, but is implemented using the synchronous command processing API of libpq.
* See #async_exec for the differences between the two API variants.
* It's not recommended to use explicit sync or async variants but #set_client_encoding instead, unless you have a good reason to do so.
*/
static VALUE
pgconn_set_client_encoding(VALUE self, VALUE str)
Expand Down Expand Up @@ -3853,16 +3855,33 @@ pgconn_external_encoding(VALUE self)
return rb_enc_from_encoding( enc );
}

/*
* call-seq:
* conn.set_client_encoding( encoding )
*
* Sets the client encoding to the _encoding_ String.
*/
static VALUE
pgconn_async_set_client_encoding(VALUE self, VALUE encname)
{
VALUE query_format, query;

Check_Type(encname, T_STRING);
query_format = rb_str_new_cstr("set client_encoding to '%s'");
query = rb_funcall(query_format, rb_intern("%"), 1, encname);

pgconn_async_exec(1, &query, self);
pgconn_set_internal_encoding_index( self );

return Qnil;
}

static VALUE
pgconn_set_client_encoding_async1( VALUE args )
{
VALUE self = ((VALUE*)args)[0];
VALUE encname = ((VALUE*)args)[1];
VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);

pgconn_async_exec(1, &query, self);
pgconn_async_set_client_encoding(self, encname);
return 0;
}

Expand All @@ -3877,9 +3896,9 @@ pgconn_set_client_encoding_async2( VALUE arg, VALUE ex )


static VALUE
pgconn_set_client_encoding_async( VALUE self, const char *encname )
pgconn_set_client_encoding_async( VALUE self, VALUE encname )
{
VALUE args[] = { self, rb_str_new_cstr(encname) };
VALUE args[] = { self, encname };
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
}

Expand All @@ -3901,10 +3920,9 @@ pgconn_set_default_encoding( VALUE self )

if (( enc = rb_default_internal_encoding() )) {
encname = pg_get_rb_encoding_as_pg_encoding( enc );
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
encname, PQerrorMessage(conn) );
pgconn_set_internal_encoding_index( self );
return rb_enc_from_encoding( enc );
} else {
pgconn_set_internal_encoding_index( self );
Expand Down Expand Up @@ -4282,8 +4300,9 @@ init_pg_connection()

/****** PG::Connection INSTANCE METHODS: Other ******/
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
rb_define_method(rb_cPGconn, "sync_set_client_encoding", pgconn_set_client_encoding, 1);
rb_define_method(rb_cPGconn, "async_set_client_encoding", pgconn_async_set_client_encoding, 1);
rb_define_alias(rb_cPGconn, "async_client_encoding=", "async_set_client_encoding");
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
rb_define_private_method(rb_cPGconn, "wait_for_flush", pgconn_wait_for_flush, 0);
rb_define_private_method(rb_cPGconn, "flush_data=", pgconn_flush_data_set, 1);
Expand Down
2 changes: 2 additions & 0 deletions lib/pg/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ def async_connect(*args, **kwargs)
:get_last_result => [:async_get_last_result, :sync_get_last_result],
:get_copy_data => [:async_get_copy_data, :sync_get_copy_data],
:reset => [:async_reset, :sync_reset],
:set_client_encoding => [:async_set_client_encoding, :sync_set_client_encoding],
:client_encoding= => [:async_set_client_encoding, :sync_set_client_encoding],
}

def async_send_api=(enable)
Expand Down
22 changes: 22 additions & 0 deletions spec/pg/scheduler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ def run_with_scheduler(timeout=10)
end
end

it "connects to a server with setting default encoding" do
Encoding.default_internal = Encoding::ISO8859_3
begin
run_with_scheduler do |conn|
res = conn.exec_params("SELECT 8", [])
expect(res.getvalue(0,0).encoding).to eq(Encoding::ISO8859_3)
expect( conn.get_client_encoding ).to eq( "LATIN3" )
end
ensure
Encoding.default_internal = nil
end
end

it "can set_client_encoding" do
run_with_scheduler do |conn|
expect( conn.set_client_encoding('iso8859-4') ).to eq( nil )
expect( conn.get_client_encoding ).to eq( "LATIN4" )
conn.client_encoding = 'iso8859-2'
expect( conn.get_client_encoding ).to eq( "LATIN2" )
end
end

it "waits when sending query data" do
run_with_scheduler do |conn|
data = "x" * 1000 * 1000 * 10
Expand Down

0 comments on commit ca1bc72

Please sign in to comment.