Skip to content

Commit 7074dae

Browse files
authored
Merge pull request #1058 from dr-itz/rails6-dev
[postgres] fix setting date when timezone offset is negative
2 parents cc6a5e7 + 1653ac7 commit 7074dae

File tree

3 files changed

+89
-14
lines changed

3 files changed

+89
-14
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ matrix:
6969
- addons:
7070
postgresql: "10"
7171
env: DB=postgresql PREPARED_STATEMENTS=true INSERT_RETURNING=true
72+
- addons:
73+
postgresql: "10"
74+
env: DB=postgresql PREPARED_STATEMENTS=true JRUBY_OPTS=-J-Duser.timezone=America/Detroit
7275
- addons:
7376
postgresql: "9.4"
7477
env: DB=postgresql PREPARED_STATEMENTS=true

src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,18 @@
3636
import java.lang.StringBuilder;
3737
import java.lang.reflect.InvocationTargetException;
3838
import java.math.BigDecimal;
39-
import java.sql.Connection;
40-
import java.sql.DatabaseMetaData;
41-
import java.sql.PreparedStatement;
42-
import java.sql.ResultSet;
43-
import java.sql.ResultSetMetaData;
44-
import java.sql.SQLException;
45-
import java.sql.Timestamp;
46-
import java.sql.Types;
47-
import java.util.ArrayList;
48-
import java.util.Collections;
49-
import java.util.HashMap;
50-
import java.util.Map;
51-
import java.util.UUID;
39+
import java.sql.*;
40+
import java.sql.Date;
41+
import java.util.*;
5242
import java.util.regex.Pattern;
5343
import java.util.regex.Matcher;
5444

45+
import org.joda.time.DateTime;
5546
import org.jruby.*;
5647
import org.jruby.anno.JRubyMethod;
5748
import org.jruby.exceptions.RaiseException;
5849
import org.jruby.ext.bigdecimal.RubyBigDecimal;
50+
import org.jruby.ext.date.RubyDate;
5951
import org.jruby.javasupport.JavaUtil;
6052
import org.jruby.runtime.ObjectAllocator;
6153
import org.jruby.runtime.ThreadContext;
@@ -115,6 +107,7 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
115107

116108
// Used to wipe trailing 0's from points (3.0, 5.6) -> (3, 5.6)
117109
private static final Pattern pointCleanerPattern = Pattern.compile("\\.0\\b");
110+
private static final TimeZone TZ_DEFAULT = TimeZone.getDefault();
118111

119112
private RubyClass resultClass;
120113
private RubyHash typeMap = null;
@@ -386,7 +379,20 @@ protected void setDateParameter(final ThreadContext context,
386379
}
387380
}
388381

389-
super.setDateParameter(context, connection, statement, index, value, attribute, type);
382+
if ( ! "Date".equals(value.getMetaClass().getName()) && value.respondsTo("to_date") ) {
383+
value = value.callMethod(context, "to_date");
384+
}
385+
386+
if (value instanceof RubyDate) {
387+
RubyDate rubyDate = (RubyDate) value;
388+
DateTime dt = rubyDate.getDateTime();
389+
// pgjdbc needs adjustment for default JVM timezone
390+
statement.setDate(index, new Date(dt.getMillis() - TZ_DEFAULT.getOffset(dt.getMillis())));
391+
return;
392+
}
393+
394+
// NOTE: assuming Date#to_s does right ...
395+
statement.setDate(index, Date.valueOf(value.toString()));
390396
}
391397

392398
@Override

test/db/postgresql/date_test.rb

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
require 'test_helper'
2+
require 'db/postgres'
3+
4+
class DateTest < Test::Unit::TestCase
5+
6+
class CreatePosts < ActiveRecord::Migration[5.0]
7+
def self.up
8+
create_table :posts, force: true do |t|
9+
t.date :published_on
10+
end
11+
end
12+
def self.down
13+
drop_table :posts
14+
end
15+
end
16+
17+
def setup
18+
CreatePosts.up
19+
end
20+
21+
def teardown
22+
CreatePosts.down
23+
end
24+
25+
class Post < ActiveRecord::Base
26+
end
27+
28+
def test_prepared_statement_for_date_column_sends_correct_date_to_postgres
29+
Post.create!
30+
date = Date.new(2020, 2, 12)
31+
Post.first.update_columns published_on: date
32+
33+
assert_equal date, Post.first.published_on
34+
ensure
35+
Post.connection.execute 'TRUNCATE posts;'
36+
end
37+
38+
def test_unprepared_statement_for_date_column_sends_correct_date_to_postgres
39+
Post.create!
40+
date = Date.new(2020, 2, 12)
41+
42+
ActiveRecord::Base.connection.unprepared_statement do
43+
Post.first.update_columns published_on: date
44+
end
45+
46+
assert_equal date, Post.first.published_on
47+
ensure
48+
Post.connection.execute 'TRUNCATE posts;'
49+
end
50+
51+
def test_raw_arel_for_date_column_sends_correct_date_to_postgres
52+
Post.create!
53+
date = Date.new(2020, 2, 12)
54+
55+
update_arel = Arel::UpdateManager.new
56+
update_arel.table Post.arel_table
57+
update_arel.set [
58+
[Post.arel_table[:published_on], date]
59+
]
60+
Post.connection.update update_arel
61+
62+
assert_equal date, Post.first.published_on
63+
ensure
64+
Post.connection.execute 'TRUNCATE posts;'
65+
end
66+
end

0 commit comments

Comments
 (0)