From d122cda75008a24899f62aae61d52091318686ef Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Wed, 22 Mar 2023 21:09:37 +0100 Subject: [PATCH] Add PG::BinaryEncoder::Float4 and Float8 --- ext/pg_binary_encoder.c | 50 +++++++++++++++++++ lib/pg/basic_type_registry.rb | 4 +- .../pg/basic_type_map_based_on_result_spec.rb | 8 +-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/ext/pg_binary_encoder.c b/ext/pg_binary_encoder.c index ddf67b55e..2b6d9c318 100644 --- a/ext/pg_binary_encoder.c +++ b/ext/pg_binary_encoder.c @@ -93,6 +93,52 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i return 8; } +/* + * Document-class: PG::BinaryEncoder::Float4 < PG::SimpleEncoder + * + * This is the binary encoder class for the PostgreSQL +float4+ type. + * + */ +static VALUE +pg_bin_enc_float4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx) +{ + union { + float f; + int32_t i; + } swap4; + + if(out){ + swap4.f = NUM2DBL(*intermediate); + write_nbo32(swap4.i, out); + }else{ + *intermediate = value; + } + return 4; +} + +/* + * Document-class: PG::BinaryEncoder::Float8 < PG::SimpleEncoder + * + * This is the binary encoder class for the PostgreSQL +float8+ type. + * + */ +static VALUE +pg_bin_enc_float8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx) +{ + union { + double f; + int64_t i; + } swap8; + + if(out){ + swap8.f = NUM2DBL(*intermediate); + write_nbo64(swap8.i, out); + }else{ + *intermediate = value; + } + return 8; +} + /* * Document-class: PG::BinaryEncoder::Timestamp < PG::SimpleEncoder * @@ -207,6 +253,10 @@ init_pg_binary_encoder(void) pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder ); /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */ pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder ); + /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float4", rb_cPG_SimpleEncoder ); */ + pg_define_coder( "Float4", pg_bin_enc_float4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder ); + /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float8", rb_cPG_SimpleEncoder ); */ + pg_define_coder( "Float8", pg_bin_enc_float8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder ); /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */ pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder ); /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */ diff --git a/lib/pg/basic_type_registry.rb b/lib/pg/basic_type_registry.rb index 874aa3dca..cfab0d1dd 100644 --- a/lib/pg/basic_type_registry.rb +++ b/lib/pg/basic_type_registry.rb @@ -276,8 +276,8 @@ def register_default_types register_type 1, 'bytea', PG::BinaryEncoder::Bytea, PG::BinaryDecoder::Bytea register_type 1, 'bool', PG::BinaryEncoder::Boolean, PG::BinaryDecoder::Boolean - register_type 1, 'float4', nil, PG::BinaryDecoder::Float - register_type 1, 'float8', nil, PG::BinaryDecoder::Float + register_type 1, 'float4', PG::BinaryEncoder::Float4, PG::BinaryDecoder::Float + register_type 1, 'float8', PG::BinaryEncoder::Float8, PG::BinaryDecoder::Float register_type 1, 'timestamp', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtc register_type 1, 'timestamptz', PG::BinaryEncoder::TimestampUtc, PG::BinaryDecoder::TimestampUtcToLocal diff --git a/spec/pg/basic_type_map_based_on_result_spec.rb b/spec/pg/basic_type_map_based_on_result_spec.rb index 30f3f3a5f..7d208de9b 100644 --- a/spec/pg/basic_type_map_based_on_result_spec.rb +++ b/spec/pg/basic_type_map_based_on_result_spec.rb @@ -91,7 +91,7 @@ end it "can type cast #copy_data binary input with encoder" do - @conn.exec( "CREATE TEMP TABLE copytable (b bytea, i INT, ts timestamp)" ) + @conn.exec( "CREATE TEMP TABLE copytable (b bytea, i INT, ts timestamp, f4 float4, f8 float8)" ) # Retrieve table OIDs per empty result set. res = @conn.exec_params( "SELECT * FROM copytable LIMIT 0", [], 1 ) @@ -99,11 +99,11 @@ row_encoder = PG::BinaryEncoder::CopyRow.new type_map: tm @conn.copy_data( "COPY copytable FROM STDIN WITH (FORMAT binary)", row_encoder ) do |res| - @conn.put_copy_data ["\xff\x00\n\r'", 123, Time.utc(2023, 3, 17, 3, 4, 5.6789123)] - @conn.put_copy_data [" xyz ", -444, Time.new(1990, 12, 17, 18, 44, 45, "+03:30")] + @conn.put_copy_data ["\xff\x00\n\r'", 123, Time.utc(2023, 3, 17, 3, 4, 5.6789123), 12.345, -12.345e67] + @conn.put_copy_data [" xyz ", -444, Time.new(1990, 12, 17, 18, 44, 45, "+03:30"), -Float::INFINITY, Float::NAN] end res = @conn.exec( "SELECT * FROM copytable" ) - expect( res.values ).to eq( [["\\xff000a0d27", "123", "2023-03-17 03:04:05.678912"], ["\\x202078797a2020", "-444", "1990-12-17 15:14:45"]] ) + expect( res.values ).to eq( [["\\xff000a0d27", "123", "2023-03-17 03:04:05.678912", "12.345", "-1.2345e+68"], ["\\x202078797a2020", "-444", "1990-12-17 15:14:45", "-Infinity", "NaN"]] ) end end end