Skip to content

Commit ff0a5b4

Browse files
committed
a "fast" attempt to bring 4.2 compatibility to PG but seems it's not the right way
Postgres will be the trickiest to handle multiple AR support with 4.2 ... as always
1 parent 9bc5b7a commit ff0a5b4

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

lib/arjdbc/jdbc/adapter.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,5 +930,8 @@ def _string_to_timestamp(value)
930930
end
931931

932932
end
933+
module Jdbc
934+
autoload :TypeCast, 'arjdbc/jdbc/type_cast'
935+
end
933936
end
934937
end

lib/arjdbc/jdbc/type_cast.rb

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
module ActiveRecord::ConnectionAdapters
2+
module Jdbc
3+
# Type casting methods taken from AR 4.1's Column class.
4+
# @private Simply to quickly "hack-in" 4.2 compatibility.
5+
module TypeCast
6+
7+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
8+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
9+
10+
#module Format
11+
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
12+
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
13+
#end
14+
15+
# Used to convert from BLOBs to Strings
16+
def binary_to_string(value)
17+
value
18+
end
19+
20+
def value_to_date(value)
21+
if value.is_a?(String)
22+
return nil if value.empty?
23+
fast_string_to_date(value) || fallback_string_to_date(value)
24+
elsif value.respond_to?(:to_date)
25+
value.to_date
26+
else
27+
value
28+
end
29+
end
30+
31+
def string_to_time(string)
32+
return string unless string.is_a?(String)
33+
return nil if string.empty?
34+
35+
fast_string_to_time(string) || fallback_string_to_time(string)
36+
end
37+
38+
def string_to_dummy_time(string)
39+
return string unless string.is_a?(String)
40+
return nil if string.empty?
41+
42+
dummy_time_string = "2000-01-01 #{string}"
43+
44+
fast_string_to_time(dummy_time_string) || begin
45+
time_hash = Date._parse(dummy_time_string)
46+
return nil if time_hash[:hour].nil?
47+
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
48+
end
49+
end
50+
51+
# convert something to a boolean
52+
def value_to_boolean(value)
53+
if value.is_a?(String) && value.empty?
54+
nil
55+
else
56+
TRUE_VALUES.include?(value)
57+
end
58+
end
59+
60+
# Used to convert values to integer.
61+
# handle the case when an integer column is used to store boolean values
62+
def value_to_integer(value)
63+
case value
64+
when TrueClass, FalseClass
65+
value ? 1 : 0
66+
else
67+
value.to_i rescue nil
68+
end
69+
end
70+
71+
# convert something to a BigDecimal
72+
def value_to_decimal(value)
73+
# Using .class is faster than .is_a? and
74+
# subclasses of BigDecimal will be handled
75+
# in the else clause
76+
if value.class == BigDecimal
77+
value
78+
elsif value.respond_to?(:to_d)
79+
value.to_d
80+
else
81+
value.to_s.to_d
82+
end
83+
end
84+
85+
protected
86+
# '0.123456' -> 123456
87+
# '1.123456' -> 123456
88+
def microseconds(time)
89+
time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0
90+
end
91+
92+
def new_date(year, mon, mday)
93+
if year && year != 0
94+
Date.new(year, mon, mday) rescue nil
95+
end
96+
end
97+
98+
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
99+
# Treat 0000-00-00 00:00:00 as nil.
100+
return nil if year.nil? || (year == 0 && mon == 0 && mday == 0)
101+
102+
if offset
103+
time = Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
104+
return nil unless time
105+
106+
time -= offset
107+
Base.default_timezone == :utc ? time : time.getlocal
108+
else
109+
Time.public_send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
110+
end
111+
end
112+
113+
def fast_string_to_date(string)
114+
if string =~ ISO_DATE
115+
new_date $1.to_i, $2.to_i, $3.to_i
116+
end
117+
end
118+
119+
# Doesn't handle time zones.
120+
def fast_string_to_time(string)
121+
if string =~ ISO_DATETIME
122+
microsec = ($7.to_r * 1_000_000).to_i
123+
new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
124+
end
125+
end
126+
127+
def fallback_string_to_date(string)
128+
new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
129+
end
130+
131+
def fallback_string_to_time(string)
132+
time_hash = Date._parse(string)
133+
time_hash[:sec_fraction] = microseconds(time_hash)
134+
135+
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
136+
end
137+
138+
end
139+
end
140+
end

lib/arjdbc/postgresql/column.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class << base
2828
include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
2929
end if AR4_COMPAT
3030

31+
include ActiveRecord::ConnectionAdapters::Jdbc::TypeCast if AR42_COMPAT
3132
include Cast
3233

3334
end

0 commit comments

Comments
 (0)