Skip to content
Open
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
7 changes: 5 additions & 2 deletions ext/pg_binary_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

VALUE rb_mPG_BinaryDecoder;
static VALUE s_Date;
static VALUE s_Date_GREGORIAN; /* Date::GREGORIAN */
static ID s_id_new;


Expand Down Expand Up @@ -403,7 +404,7 @@ pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field
default:
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);

return rb_funcall(s_Date, s_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
return rb_funcall(s_Date, s_id_new, 4, INT2NUM(year), INT2NUM(month), INT2NUM(day), s_Date_GREGORIAN);
}
}

Expand All @@ -412,8 +413,10 @@ static VALUE
init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
{
rb_require("date");
rb_gc_register_address(&s_Date);
rb_gc_register_address(&s_Date_GREGORIAN);
s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
rb_gc_register_mark_object(s_Date);
s_Date_GREGORIAN = rb_const_get(s_Date, rb_intern("GREGORIAN"));
s_id_new = rb_intern("new");

/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
Expand Down
7 changes: 7 additions & 0 deletions ext/pg_binary_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#endif

VALUE rb_mPG_BinaryEncoder;
static ID s_id_gregorianP;
static ID s_id_gregorian;
static ID s_id_year;
static ID s_id_month;
static ID s_id_day;
Expand Down Expand Up @@ -272,6 +274,9 @@ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, i
write_nbo32(PG_INT32_MIN, out);
return 4;
} {
/* Only create a new gregorian Date object if necessary */
if( rb_funcall(value, s_id_gregorianP, 0) != Qtrue )
value = rb_funcall(value, s_id_gregorian, 0);
VALUE year = rb_funcall(value, s_id_year, 0);
VALUE month = rb_funcall(value, s_id_month, 0);
VALUE day = rb_funcall(value, s_id_day, 0);
Expand Down Expand Up @@ -554,6 +559,8 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
void
init_pg_binary_encoder(void)
{
s_id_gregorianP = rb_intern("gregorian?");
s_id_gregorian = rb_intern("gregorian");
s_id_year = rb_intern("year");
s_id_month = rb_intern("month");
s_id_day = rb_intern("day");
Expand Down
2 changes: 2 additions & 0 deletions lib/pg/basic_type_map_for_queries.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def get_array_type(value)
Integer => [0, 'int8'],
Float => [0, 'float8'],
Time => [0, 'timestamptz'],
Date => [0, 'date'],
# We use text format and no type OID for IPAddr, because setting the OID can lead
# to unnecessary inet/cidr conversions on the server side.
IPAddr => [0, 'inet'],
Expand All @@ -200,6 +201,7 @@ def get_array_type(value)
String => [0, '_text'],
Float => [0, '_float8'],
Time => [0, '_timestamptz'],
Date => [0, '_date'],
IPAddr => [0, '_inet'],
}.merge(has_bigdecimal ? {BigDecimal => [0, '_numeric']} : {}))
private_constant :DEFAULT_ARRAY_TYPE_MAP
Expand Down
2 changes: 1 addition & 1 deletion lib/pg/text_decoder/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module TextDecoder
class Date < SimpleDecoder
def decode(string, tuple=nil, field=nil)
if string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/
::Date.new $1.to_i, $2.to_i, $3.to_i
::Date.new $1.to_i, $2.to_i, $3.to_i, ::Date::GREGORIAN
else
string
end
Expand Down
8 changes: 7 additions & 1 deletion lib/pg/text_encoder/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ module TextEncoder
# This is a encoder class for conversion of Ruby Date values to PostgreSQL date type.
class Date < SimpleEncoder
def encode(value)
value.respond_to?(:strftime) ? value.strftime("%Y-%m-%d") : value
if value.respond_to?(:gregorian?)
# Only create a new gregorian Date object if necessary
value = value.gregorian unless value.gregorian?
value.strftime("%Y-%m-%d")
else
value
end
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions spec/pg/basic_type_map_based_on_result_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@

[1, 0].each do |format|
it "can type cast #copy_data input with encoder to format #{format}" do
@conn.exec( "CREATE TEMP TABLE copytable (b bytea, i INT, ts1 timestamp, ts2 timestamp, f4 float4, f8 float8, d1 date, d2 date)" )
@conn.exec( "CREATE TEMP TABLE copytable (b bytea, i INT, ts1 timestamp, ts2 timestamp, f4 float4, f8 float8, d1 date, d2 date, d3 date)" )

# Retrieve table OIDs per empty result set.
res = @conn.exec_params( "SELECT * FROM copytable LIMIT 0", [], format )
Expand All @@ -136,13 +136,13 @@
row_encoder = nsp::CopyRow.new type_map: tm

@conn.copy_data( "COPY copytable FROM STDIN WITH (FORMAT #{ format==1 ? "binary" : "text" })", row_encoder ) do |res|
@conn.put_copy_data ["\xff\x00\n\r'", 123, Time.utc(2023, 3, 17, 3, 4, 5.6789123), Time.new(1990, 12, 17, 18, 44, 45, "+03:30").utc, 12.345, -12.345e167, Date.new(2055, 12, 31), Date.new(1234, 8, 31)]
@conn.put_copy_data [" xyz ", -444, "Infinity", "-infinity", -Float::INFINITY, Float::NAN, "infinity", "-infinity"]
@conn.put_copy_data ["\xff\x00\n\r'", 123, Time.utc(2023, 3, 17, 3, 4, 5.6789123), Time.new(1990, 12, 17, 18, 44, 45, "+03:30").utc, 12.345, -12.345e167, Date.new(2055, 12, 31), Date.new(1234, 8, 15), Date.new(1234, 8, 15, ::Date::GREGORIAN)]
@conn.put_copy_data [" xyz ", -444, "Infinity", "-infinity", -Float::INFINITY, Float::NAN, "infinity", "-infinity", nil]
end
res = @conn.exec( "SELECT * FROM copytable" )
expect( res.values ).to eq( [
["\\xff000a0d27", "123", "2023-03-17 03:04:05.678912", "1990-12-17 15:14:45", "12.345", "-1.2345e+168", "2055-12-31", "1234-08-31"],
["\\x202078797a2020", "-444", "infinity", "-infinity", "-Infinity", "NaN", "infinity", "-infinity"]
["\\xff000a0d27", "123", "2023-03-17 03:04:05.678912", "1990-12-17 15:14:45", "12.345", "-1.2345e+168", "2055-12-31", "1234-08-22", "1234-08-15"],
["\\x202078797a2020", "-444", "infinity", "-infinity", "-Infinity", "NaN", "infinity", "-infinity", nil]
] )
end
end
Expand Down
7 changes: 5 additions & 2 deletions spec/pg/basic_type_map_for_results_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,15 @@
it "should do format #{format} date type conversions" do
res = @conn.exec_params( "SELECT CAST('2113-12-31' AS DATE),
CAST('1913-12-31' AS DATE),
CAST('1581-12-15' AS DATE),
CAST('infinity' AS DATE),
CAST('-infinity' AS DATE)", [], format )
expect( res.getvalue(0,0) ).to eq( Date.new(2113, 12, 31) )
expect( res.getvalue(0,1) ).to eq( Date.new(1913, 12, 31) )
expect( res.getvalue(0,2) ).to eq( 'infinity' )
expect( res.getvalue(0,3) ).to eq( '-infinity' )
expect( res.getvalue(0,2) ).to eq( Date.new(1581, 12, 15, Date::GREGORIAN) )
expect( res.getvalue(0,2) ).to eq( Date.new(1581, 12, 5, Date::JULIAN) )
expect( res.getvalue(0,3) ).to eq( 'infinity' )
expect( res.getvalue(0,4) ).to eq( '-infinity' )
end
end

Expand Down
Loading