activerecord-jdbc-adapter 5.0.pre1 → 51.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -2
- data/.travis.yml +15 -416
- data/Gemfile +35 -37
- data/README.md +23 -118
- data/RUNNING_TESTS.md +31 -26
- data/Rakefile +2 -3
- data/activerecord-jdbc-adapter.gemspec +1 -2
- data/lib/arjdbc/abstract/connection_management.rb +21 -0
- data/lib/arjdbc/abstract/core.rb +62 -0
- data/lib/arjdbc/abstract/database_statements.rb +46 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/derby/adapter.rb +6 -1
- data/lib/arjdbc/discover.rb +0 -7
- data/lib/arjdbc/firebird/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +10 -252
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/connection.rb +6 -0
- data/lib/arjdbc/jdbc.rb +2 -2
- data/lib/arjdbc/mysql/adapter.rb +87 -944
- data/lib/arjdbc/mysql/connection_methods.rb +4 -2
- data/lib/arjdbc/postgresql/adapter.rb +288 -1023
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
- data/lib/arjdbc/postgresql/column.rb +10 -599
- data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +25 -110
- data/lib/arjdbc/sqlite3/adapter.rb +171 -170
- data/lib/arjdbc/tasks/database_tasks.rb +1 -3
- data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +3 -3
- data/rakelib/02-test.rake +0 -12
- data/rakelib/compile.rake +1 -1
- data/rakelib/db.rake +7 -5
- data/rakelib/rails.rake +63 -64
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
- data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
- metadata +20 -34
- data/Appraisals +0 -41
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
- data/lib/arjdbc/common_jdbc_methods.rb +0 -89
- data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
- data/lib/arjdbc/mysql/column.rb +0 -162
- data/lib/arjdbc/mysql/explain_support.rb +0 -82
- data/lib/arjdbc/mysql/schema_creation.rb +0 -58
- data/lib/arjdbc/oracle/adapter.rb +0 -952
- data/lib/arjdbc/oracle/column.rb +0 -126
- data/lib/arjdbc/oracle/connection_methods.rb +0 -21
- data/lib/arjdbc/oracle.rb +0 -4
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +0 -21
- data/lib/arjdbc/postgresql/base/oid.rb +0 -412
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
- data/lib/arjdbc/postgresql/explain_support.rb +0 -53
- data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
- data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
- data/src/java/arjdbc/oracle/OracleModule.java +0 -75
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -0,0 +1,26 @@
|
|
1
|
+
# This implements a basic decoder to work around ActiveRecord's dependence on the pg gem
|
2
|
+
module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
3
|
+
class Array < ActiveModel::Type::Value
|
4
|
+
module PG
|
5
|
+
module TextDecoder
|
6
|
+
class Array
|
7
|
+
# Loads pg_array_parser if available. String parsing can be
|
8
|
+
# performed quicker by a native extension, which will not create
|
9
|
+
# a large amount of Ruby objects that will need to be garbage
|
10
|
+
# collected. pg_array_parser has a C and Java extension
|
11
|
+
begin
|
12
|
+
require 'pg_array_parser'
|
13
|
+
include PgArrayParser
|
14
|
+
rescue LoadError
|
15
|
+
require_relative 'array_parser'
|
16
|
+
include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(name:, delimiter:); end
|
20
|
+
|
21
|
+
alias_method :decode, :parse_pg_array
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# This implements a basic encoder to work around ActiveRecord's dependence on the pg gem
|
2
|
+
module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
3
|
+
class Array < ActiveModel::Type::Value
|
4
|
+
module PG
|
5
|
+
module TextEncoder
|
6
|
+
class Array
|
7
|
+
|
8
|
+
def initialize(name:, delimiter:)
|
9
|
+
@type = if name == 'string[]'.freeze
|
10
|
+
'text'.freeze
|
11
|
+
else
|
12
|
+
base_type = name.chomp('[]'.freeze).to_sym
|
13
|
+
ActiveRecord::Base.connection.native_database_types[base_type][:name]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def encode(values)
|
18
|
+
ActiveRecord::Base.connection.jdbc_connection.create_array_of(@type, values.to_java).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
class Bytea < ActiveModel::Type::Binary
|
3
|
+
module PG
|
4
|
+
class Connection # emulate PG::Connection#unescape_bytea due #652
|
5
|
+
def self.unescape_bytea(escaped)
|
6
|
+
ArJdbc::PostgreSQL.unescape_bytea(escaped)
|
7
|
+
end
|
8
|
+
end
|
6
9
|
end
|
7
10
|
end
|
8
|
-
end
|
11
|
+
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
module ArJdbc
|
2
2
|
module PostgreSQL
|
3
3
|
|
4
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
|
5
|
-
def self.column_selector
|
6
|
-
[ /postgre/i, lambda { |cfg, column| column.extend(Column) } ]
|
7
|
-
end
|
8
|
-
|
9
4
|
# @private these are defined on the Adapter class since 4.2
|
10
5
|
module ColumnHelpers
|
11
6
|
|
@@ -20,13 +15,18 @@ module ArJdbc
|
|
20
15
|
end
|
21
16
|
|
22
17
|
# Extracts the value from a PostgreSQL column default definition.
|
23
|
-
def extract_value_from_default(
|
18
|
+
def extract_value_from_default(default) # :nodoc:
|
24
19
|
case default
|
25
20
|
# Quoted types
|
26
|
-
when /\A[\(B]?'(.*)'
|
27
|
-
|
21
|
+
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
22
|
+
# The default 'now'::date is CURRENT_DATE
|
23
|
+
if $1 == "now".freeze && $2 == "date".freeze
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
$1.gsub("''".freeze, "'".freeze)
|
27
|
+
end
|
28
28
|
# Boolean types
|
29
|
-
when 'true', 'false'
|
29
|
+
when 'true'.freeze, 'false'.freeze
|
30
30
|
default
|
31
31
|
# Numeric types
|
32
32
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -42,599 +42,10 @@ module ArJdbc
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def extract_default_function(default_value, default) # :nodoc:
|
45
|
-
default if ! default_value && ( %r{\w+\(.*\)} === default )
|
45
|
+
default if ! default_value && ( %r{\w+\(.*\)|\(.*\)::\w+} === default )
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
49
49
|
|
50
|
-
# Column behavior based on PostgreSQL adapter in Rails.
|
51
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcColumn
|
52
|
-
module Column
|
53
|
-
|
54
|
-
attr_accessor :array
|
55
|
-
alias array? array
|
56
|
-
|
57
|
-
def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil,
|
58
|
-
oid = nil, adapter = nil) # added arguments
|
59
|
-
if sql_type.to_s[-2, 2] == '[]'
|
60
|
-
@array = true
|
61
|
-
super(name, default, cast_type, sql_type[0..-3], null)
|
62
|
-
else
|
63
|
-
@array = false
|
64
|
-
super(name, default, cast_type, sql_type, null)
|
65
|
-
end
|
66
|
-
|
67
|
-
@oid = oid # used on Java side - expects @oid on Column instances
|
68
|
-
#@adapter = adapter
|
69
|
-
|
70
|
-
@default_function = default_function
|
71
|
-
end
|
72
|
-
|
73
|
-
end if AR42
|
74
|
-
|
75
|
-
# @private (AR < 4.2 version) documented above
|
76
|
-
module Column
|
77
|
-
|
78
|
-
def initialize(name, default, oid_type = nil, sql_type = nil, null = true,
|
79
|
-
fmod = nil, adapter = nil) # added due resolving #oid_type
|
80
|
-
if oid_type.is_a?(Integer) # the "main" if branch (on AR 4.x)
|
81
|
-
@oid = oid_type; @fmod = fmod; @adapter = adapter # see Column#oid_type
|
82
|
-
elsif oid_type.respond_to?(:type_cast) # MRI compatibility
|
83
|
-
@oid_type = oid_type; # @fmod = fmod; @adapter = adapter
|
84
|
-
else # NOTE: AR <= 3.2 : (name, default, sql_type = nil, null = true)
|
85
|
-
null, sql_type, oid_type = !! sql_type, oid_type, nil
|
86
|
-
end
|
87
|
-
if sql_type.to_s[-2, 2] == '[]' && AR40
|
88
|
-
@array = true if respond_to?(:array)
|
89
|
-
super(name, default, sql_type[0..-3], null)
|
90
|
-
else
|
91
|
-
@array = false if respond_to?(:array)
|
92
|
-
super(name, default, sql_type, null)
|
93
|
-
end
|
94
|
-
|
95
|
-
@default_function = extract_default_function(@default, default)
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.included(base)
|
99
|
-
# NOTE: assumes a standalone PostgreSQLColumn class
|
100
|
-
base_meta = class << base; self end
|
101
|
-
base_meta.send :attr_accessor, :money_precision
|
102
|
-
|
103
|
-
# Loads pg_array_parser if available. String parsing can be
|
104
|
-
# performed quicker by a native extension, which will not create
|
105
|
-
# a large amount of Ruby objects that will need to be garbage
|
106
|
-
# collected. pg_array_parser has a C and Java extension
|
107
|
-
begin
|
108
|
-
require 'pg_array_parser'
|
109
|
-
base_meta.send :include, PgArrayParser
|
110
|
-
rescue LoadError
|
111
|
-
if AR42
|
112
|
-
require 'active_record/connection_adapters/postgresql/array_parser'
|
113
|
-
else
|
114
|
-
require 'arjdbc/postgresql/base/array_parser'
|
115
|
-
end
|
116
|
-
base_meta.send :include, ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
|
117
|
-
end if AR40
|
118
|
-
|
119
|
-
base_meta.send :include, Cast
|
120
|
-
|
121
|
-
base.send :include, ColumnHelpers
|
122
|
-
end
|
123
|
-
|
124
|
-
if AR40 && ! AR42
|
125
|
-
|
126
|
-
# @private
|
127
|
-
def oid_type
|
128
|
-
@oid_type ||= begin
|
129
|
-
raise "oid not defined" unless oid = (@oid ||= nil)
|
130
|
-
@adapter.get_oid_type(oid.to_i, @fmod.to_i, name)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# @private
|
135
|
-
def accessor; oid_type.accessor end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
( attr_accessor :array; def array?; array; end ) if AR40
|
140
|
-
|
141
|
-
def number?; !array && super end if AR40
|
142
|
-
def text?; !array && super end if AR40
|
143
|
-
|
144
|
-
# Extracts the value from a PostgreSQL column default definition.
|
145
|
-
#
|
146
|
-
# @override JdbcColumn#default_value
|
147
|
-
# NOTE: based on `self.extract_value_from_default(default)` code
|
148
|
-
def default_value(default)
|
149
|
-
# This is a performance optimization for Ruby 1.9.2 in development.
|
150
|
-
# If the value is nil, we return nil straight away without checking
|
151
|
-
# the regular expressions. If we check each regular expression,
|
152
|
-
# Regexp#=== will call NilClass#to_str, which will trigger
|
153
|
-
# method_missing (defined by whiny nil in ActiveSupport) which
|
154
|
-
# makes this method very very slow.
|
155
|
-
return default unless default
|
156
|
-
|
157
|
-
case default
|
158
|
-
when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
|
159
|
-
$1
|
160
|
-
# Numeric types
|
161
|
-
when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
|
162
|
-
$1
|
163
|
-
# Character types
|
164
|
-
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
|
165
|
-
$1
|
166
|
-
# Binary data types
|
167
|
-
when /\A'(.*)'::bytea\z/m
|
168
|
-
$1
|
169
|
-
# Date/time types
|
170
|
-
when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
|
171
|
-
$1
|
172
|
-
when /\A'(.*)'::interval\z/
|
173
|
-
$1
|
174
|
-
# Boolean type
|
175
|
-
when 'true'
|
176
|
-
true
|
177
|
-
when 'false'
|
178
|
-
false
|
179
|
-
# Geometric types
|
180
|
-
when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
|
181
|
-
$1
|
182
|
-
# Network address types
|
183
|
-
when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
|
184
|
-
$1
|
185
|
-
# Bit string types
|
186
|
-
when /\AB'(.*)'::"?bit(?: varying)?"?\z/
|
187
|
-
$1
|
188
|
-
# XML type
|
189
|
-
when /\A'(.*)'::xml\z/m
|
190
|
-
$1
|
191
|
-
# Arrays
|
192
|
-
when /\A'(.*)'::"?\D+"?\[\]\z/
|
193
|
-
$1
|
194
|
-
when /\AARRAY\[(.*)\](::\D+)?\z/
|
195
|
-
"{#{$1.gsub(/'(.*?)'::[a-z]+(,)?\s?/, '\1\2')}}"
|
196
|
-
# Hstore
|
197
|
-
when /\A'(.*)'::hstore\z/
|
198
|
-
$1
|
199
|
-
# JSON
|
200
|
-
when /\A'(.*)'::json\z/
|
201
|
-
$1
|
202
|
-
# JSONB
|
203
|
-
when /\A'(.*)'::jsonb\z/
|
204
|
-
$1
|
205
|
-
# Object identifier types
|
206
|
-
when /\A-?\d+\z/
|
207
|
-
$1
|
208
|
-
else
|
209
|
-
# Anything else is blank, some user type, or some function
|
210
|
-
# and we can't know the value of that, so return nil.
|
211
|
-
nil
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# Casts value (which is a String) to an appropriate instance.
|
216
|
-
# @private
|
217
|
-
def type_cast(value) # AR < 4.0 version
|
218
|
-
return if value.nil?
|
219
|
-
return super if respond_to?(:encoded?) && encoded? # since AR-3.2
|
220
|
-
|
221
|
-
case sql_type
|
222
|
-
when 'money'
|
223
|
-
self.class.string_to_money(value)
|
224
|
-
else super
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
# Casts value (which is a String) to an appropriate instance.
|
229
|
-
def type_cast(value, type = false) # AR >= 4.0 version
|
230
|
-
return if value.nil?
|
231
|
-
return super(value) if encoded?
|
232
|
-
|
233
|
-
# NOTE: we do not use OID::Type
|
234
|
-
# @oid_type.type_cast value
|
235
|
-
|
236
|
-
return self.class.string_to_array(value, self) if array? && type == false
|
237
|
-
|
238
|
-
case type ||= self.type
|
239
|
-
when :hstore then self.class.string_to_hstore value
|
240
|
-
when :json then self.class.string_to_json value
|
241
|
-
when :jsonb then self.class.string_to_json value
|
242
|
-
when :cidr, :inet then self.class.string_to_cidr value
|
243
|
-
when :macaddr then value
|
244
|
-
when :tsvector then value
|
245
|
-
when :datetime, :timestamp then self.class.string_to_time value
|
246
|
-
else
|
247
|
-
if ( sql_type = self.sql_type.to_s ) == 'money'
|
248
|
-
self.class.string_to_money(value)
|
249
|
-
elsif sql_type[0, 5] == 'point'
|
250
|
-
value.is_a?(String) ? self.class.string_to_point(value) : value
|
251
|
-
elsif sql_type[0, 3] == 'bit' || sql_type[0, 6] == 'varbit'
|
252
|
-
value.is_a?(String) ? self.class.string_to_bit(value) : value
|
253
|
-
elsif sql_type[-5, 5] == 'range'
|
254
|
-
return if value.nil? || value == 'empty'
|
255
|
-
return value if value.is_a?(::Range)
|
256
|
-
|
257
|
-
extracted = extract_bounds(value)
|
258
|
-
|
259
|
-
case sql_type[0...-5] # range sub-type
|
260
|
-
when 'date' # :date
|
261
|
-
from = self.class.value_to_date(extracted[:from])
|
262
|
-
from += 1.day if extracted[:exclude_start]
|
263
|
-
to = self.class.value_to_date(extracted[:to])
|
264
|
-
when 'num' # :decimal
|
265
|
-
from = ::BigDecimal.new(extracted[:from].to_s)
|
266
|
-
# FIXME: add exclude start for ::Range, same for timestamp ranges
|
267
|
-
to = ::BigDecimal.new(extracted[:to].to_s)
|
268
|
-
when 'ts', 'tstz' # :time
|
269
|
-
from = self.class.string_to_time(extracted[:from])
|
270
|
-
to = self.class.string_to_time(extracted[:to])
|
271
|
-
when 'int4', 'int8' # :integer
|
272
|
-
from = extracted[:from]
|
273
|
-
unless (from.respond_to?(:infinite?) && from.infinite?)
|
274
|
-
from = from.respond_to?(:to_i) ? from.to_i : ( value ? 1 : 0 )
|
275
|
-
end
|
276
|
-
from += 1 if extracted[:exclude_start]
|
277
|
-
to = extracted[:to]
|
278
|
-
unless (to.respond_to?(:infinite?) && to.infinite?)
|
279
|
-
to = to.respond_to?(:to_i) ? to.to_i : ( value ? 1 : 0 )
|
280
|
-
end
|
281
|
-
else
|
282
|
-
return value
|
283
|
-
end
|
284
|
-
|
285
|
-
::Range.new(from, to, extracted[:exclude_end])
|
286
|
-
else
|
287
|
-
super(value)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end if AR40
|
291
|
-
|
292
|
-
private
|
293
|
-
|
294
|
-
# Extracts the scale from PostgreSQL-specific data types.
|
295
|
-
def extract_scale(sql_type)
|
296
|
-
# Money type has a fixed scale of 2.
|
297
|
-
sql_type =~ /^money/ ? 2 : super
|
298
|
-
end
|
299
|
-
|
300
|
-
# Extracts the precision from PostgreSQL-specific data types.
|
301
|
-
def extract_precision(sql_type)
|
302
|
-
if sql_type == 'money'
|
303
|
-
self.class.money_precision
|
304
|
-
elsif sql_type =~ /timestamp/i
|
305
|
-
$1.to_i if sql_type =~ /\((\d+)\)/
|
306
|
-
else
|
307
|
-
super
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
# Maps PostgreSQL-specific data types to logical Rails types.
|
312
|
-
def simplified_type(field_type)
|
313
|
-
case field_type
|
314
|
-
# Numeric and monetary types
|
315
|
-
when /^(?:real|double precision)$/ then :float
|
316
|
-
# Monetary types
|
317
|
-
when 'money' then :decimal
|
318
|
-
# Character types
|
319
|
-
when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
|
320
|
-
# Binary data types
|
321
|
-
when 'bytea' then :binary
|
322
|
-
# Date/time types
|
323
|
-
when /^timestamp with(?:out)? time zone$/ then :datetime
|
324
|
-
when 'interval' then :string
|
325
|
-
# Geometric types
|
326
|
-
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
|
327
|
-
# Network address types
|
328
|
-
when /^(?:cidr|inet|macaddr)$/ then :string
|
329
|
-
# Bit strings
|
330
|
-
when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
|
331
|
-
# XML type
|
332
|
-
when 'xml' then :xml
|
333
|
-
# tsvector type
|
334
|
-
when 'tsvector' then :tsvector
|
335
|
-
# Arrays
|
336
|
-
when /^\D+\[\]$/ then :string
|
337
|
-
# Object identifier types
|
338
|
-
when 'oid' then :integer
|
339
|
-
# UUID type
|
340
|
-
when 'uuid' then :string
|
341
|
-
# Small and big integer types
|
342
|
-
when /^(?:small|big)int$/ then :integer
|
343
|
-
# AR-JDBC added :
|
344
|
-
when 'bool' then :boolean
|
345
|
-
when 'char' then :string
|
346
|
-
when 'serial' then :integer
|
347
|
-
# Pass through all types that are not specific to PostgreSQL.
|
348
|
-
else
|
349
|
-
super
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
# @private
|
354
|
-
def simplified_type(field_type)
|
355
|
-
case field_type
|
356
|
-
# Numeric and monetary types
|
357
|
-
when /^(?:real|double precision)$/ then :float
|
358
|
-
# Monetary types
|
359
|
-
when 'money' then :decimal
|
360
|
-
when 'hstore' then :hstore
|
361
|
-
when 'ltree' then :ltree
|
362
|
-
# Network address types
|
363
|
-
when 'inet' then :inet
|
364
|
-
when 'cidr' then :cidr
|
365
|
-
when 'macaddr' then :macaddr
|
366
|
-
# Character types
|
367
|
-
when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
|
368
|
-
# Binary data types
|
369
|
-
when 'bytea' then :binary
|
370
|
-
# Date/time types
|
371
|
-
when /^timestamp with(?:out)? time zone$/ then :datetime
|
372
|
-
when /^interval(?:|\(\d+\))$/ then :string
|
373
|
-
# Geometric types
|
374
|
-
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
|
375
|
-
# Bit strings
|
376
|
-
when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
|
377
|
-
# XML type
|
378
|
-
when 'xml' then :xml
|
379
|
-
# tsvector type
|
380
|
-
when 'tsvector' then :tsvector
|
381
|
-
# Arrays
|
382
|
-
when /^\D+\[\]$/ then :string
|
383
|
-
# Object identifier types
|
384
|
-
when 'oid' then :integer
|
385
|
-
# UUID type
|
386
|
-
when 'uuid' then :uuid
|
387
|
-
# JSON type
|
388
|
-
when 'json' then :json
|
389
|
-
when 'jsonb' then :jsonb
|
390
|
-
# Small and big integer types
|
391
|
-
when /^(?:small|big)int$/ then :integer
|
392
|
-
when /(num|date|tstz|ts|int4|int8)range$/
|
393
|
-
field_type.to_sym
|
394
|
-
# AR-JDBC added :
|
395
|
-
when 'bool' then :boolean
|
396
|
-
when 'char' then :string
|
397
|
-
when 'serial' then :integer
|
398
|
-
# Pass through all types that are not specific to PostgreSQL.
|
399
|
-
else
|
400
|
-
super
|
401
|
-
end
|
402
|
-
end if AR40
|
403
|
-
|
404
|
-
# OID Type::Range helpers :
|
405
|
-
|
406
|
-
def extract_bounds(value)
|
407
|
-
f, t = value[1..-2].split(',')
|
408
|
-
{
|
409
|
-
:from => (value[1] == ',' || f == '-infinity') ? infinity(:negative => true) : f,
|
410
|
-
:to => (value[-2] == ',' || t == 'infinity') ? infinity : t,
|
411
|
-
:exclude_start => (value[0] == '('), :exclude_end => (value[-1] == ')')
|
412
|
-
}
|
413
|
-
end if AR40
|
414
|
-
|
415
|
-
def infinity(options = {})
|
416
|
-
::Float::INFINITY * (options[:negative] ? -1 : 1)
|
417
|
-
end if AR40
|
418
|
-
|
419
|
-
private
|
420
|
-
|
421
|
-
# TODO marshaling worked in 1.3.7 ,,, got broken in 1.3.8 (due @adapter)
|
422
|
-
# but the fix introduced in 1.3.10 causes backwards (1.3) incompatibility
|
423
|
-
# ... for now should be fine - there's likely more refactoring to happen!
|
424
|
-
|
425
|
-
def marshal_dump
|
426
|
-
# NOTE: disabled oid_type ... due range warnings (maybe they're fine) :
|
427
|
-
# unknown OID 3904: failed to recognize type of 'int4_range'. It will be treated as String.
|
428
|
-
#oid_type if respond_to?(:oid_type)
|
429
|
-
@adapter = nil
|
430
|
-
instance_variables.map { |var| [ var, instance_variable_get(var) ] }
|
431
|
-
end
|
432
|
-
|
433
|
-
def marshal_load(data)
|
434
|
-
data.each { |pair| instance_variable_set( pair[0], pair[1] ) }
|
435
|
-
end
|
436
|
-
|
437
|
-
# @note Based on *active_record/connection_adapters/postgresql/cast.rb* (4.0).
|
438
|
-
module Cast
|
439
|
-
|
440
|
-
def string_to_money(string)
|
441
|
-
return string unless String === string
|
442
|
-
|
443
|
-
# Because money output is formatted according to the locale, there
|
444
|
-
# are two cases to consider (note the decimal separators) :
|
445
|
-
# (1) $12,345,678.12
|
446
|
-
# (2) $12.345.678,12
|
447
|
-
# Negative values are represented as follows:
|
448
|
-
# (3) -$2.55
|
449
|
-
# (4) ($2.55)
|
450
|
-
string = string.sub(/^\((.+)\)$/, '-\1') # (4)
|
451
|
-
case string
|
452
|
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
453
|
-
string.gsub!(/[^-\d.]/, '')
|
454
|
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
455
|
-
string.gsub!(/[^-\d,]/, '')
|
456
|
-
string.sub!(/,/, '.')
|
457
|
-
end
|
458
|
-
value_to_decimal string
|
459
|
-
end
|
460
|
-
|
461
|
-
def point_to_string(point)
|
462
|
-
"(#{point[0]},#{point[1]})"
|
463
|
-
end
|
464
|
-
|
465
|
-
def string_to_point(string)
|
466
|
-
if string[0] == '(' && string[-1] == ')'
|
467
|
-
string = string[1...-1]
|
468
|
-
end
|
469
|
-
string.split(',').map { |v| Float(v) }
|
470
|
-
end
|
471
|
-
|
472
|
-
def string_to_time(string)
|
473
|
-
return string unless String === string
|
474
|
-
|
475
|
-
case string
|
476
|
-
when 'infinity' then 1.0 / 0.0
|
477
|
-
when '-infinity' then -1.0 / 0.0
|
478
|
-
when / BC$/
|
479
|
-
super("-#{string.sub(/ BC$/, "")}")
|
480
|
-
else
|
481
|
-
super
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
def string_to_bit(value)
|
486
|
-
case value
|
487
|
-
when /^[01]*$/ then value # Bit-string notation
|
488
|
-
when /^[0-9A-F]*$/i then value.hex.to_s(2) # Hexadecimal notation
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
def string_to_bit(value)
|
493
|
-
case value
|
494
|
-
when /^0x/i
|
495
|
-
value[2..-1].hex.to_s(2) # Hexadecimal notation
|
496
|
-
else
|
497
|
-
value # Bit-string notation
|
498
|
-
end
|
499
|
-
end if AR40
|
500
|
-
|
501
|
-
def hstore_to_string(object, array_member = false)
|
502
|
-
if Hash === object
|
503
|
-
string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
|
504
|
-
string = escape_hstore(string) if array_member
|
505
|
-
string
|
506
|
-
else
|
507
|
-
object
|
508
|
-
end
|
509
|
-
end
|
510
|
-
|
511
|
-
def string_to_hstore(string)
|
512
|
-
if string.nil?
|
513
|
-
nil
|
514
|
-
elsif String === string
|
515
|
-
Hash[string.scan(HstorePair).map { |k, v|
|
516
|
-
v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
|
517
|
-
k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
|
518
|
-
[k, v]
|
519
|
-
}]
|
520
|
-
else
|
521
|
-
string
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
|
-
def json_to_string(object)
|
526
|
-
if Hash === object || Array === object
|
527
|
-
ActiveSupport::JSON.encode(object)
|
528
|
-
else
|
529
|
-
object
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
def array_to_string(value, column, adapter)
|
534
|
-
casted_values = value.map do |val|
|
535
|
-
if String === val
|
536
|
-
if val == "NULL"
|
537
|
-
"\"#{val}\""
|
538
|
-
else
|
539
|
-
quote_and_escape(adapter.type_cast(val, column, true))
|
540
|
-
end
|
541
|
-
else
|
542
|
-
adapter.type_cast(val, column, true)
|
543
|
-
end
|
544
|
-
end
|
545
|
-
"{#{casted_values.join(',')}}"
|
546
|
-
end
|
547
|
-
|
548
|
-
def range_to_string(object)
|
549
|
-
from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
|
550
|
-
to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
|
551
|
-
"[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
|
552
|
-
end
|
553
|
-
|
554
|
-
def string_to_json(string)
|
555
|
-
if String === string
|
556
|
-
ActiveSupport::JSON.decode(string)
|
557
|
-
else
|
558
|
-
string
|
559
|
-
end
|
560
|
-
end
|
561
|
-
|
562
|
-
def string_to_cidr(string)
|
563
|
-
if string.nil?
|
564
|
-
nil
|
565
|
-
elsif String === string
|
566
|
-
begin
|
567
|
-
IPAddr.new(string)
|
568
|
-
rescue ArgumentError
|
569
|
-
nil
|
570
|
-
end
|
571
|
-
else
|
572
|
-
string
|
573
|
-
end
|
574
|
-
end
|
575
|
-
|
576
|
-
def cidr_to_string(object)
|
577
|
-
if IPAddr === object
|
578
|
-
"#{object.to_s}/#{object.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
|
579
|
-
else
|
580
|
-
object
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
|
-
# @note Only used for default values - we get a "parsed" array from JDBC.
|
585
|
-
def string_to_array(string, column_or_oid)
|
586
|
-
return string unless String === string
|
587
|
-
parse_pg_array(string).map { |val| type_cast_array(column_or_oid, val) }
|
588
|
-
end
|
589
|
-
|
590
|
-
private
|
591
|
-
|
592
|
-
# @private
|
593
|
-
HstorePair = begin
|
594
|
-
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
595
|
-
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
596
|
-
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
|
597
|
-
end
|
598
|
-
|
599
|
-
def escape_hstore(value)
|
600
|
-
if value.nil?
|
601
|
-
'NULL'
|
602
|
-
else
|
603
|
-
if value == ""
|
604
|
-
'""'
|
605
|
-
else
|
606
|
-
'"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
|
607
|
-
end
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
|
612
|
-
|
613
|
-
def quote_and_escape(value)
|
614
|
-
case value
|
615
|
-
when "NULL", Numeric
|
616
|
-
value
|
617
|
-
else
|
618
|
-
value = value.gsub(/\\/, ARRAY_ESCAPE)
|
619
|
-
value.gsub!(/"/,"\\\"")
|
620
|
-
"\"#{value}\""
|
621
|
-
end
|
622
|
-
end
|
623
|
-
|
624
|
-
def type_cast_array(oid, value)
|
625
|
-
if ::Array === value
|
626
|
-
value.map { |item| type_cast_array(oid, item) }
|
627
|
-
else
|
628
|
-
if oid.is_a?(Column)
|
629
|
-
oid.type_cast value, oid.type # column.type
|
630
|
-
else
|
631
|
-
oid.type_cast value
|
632
|
-
end
|
633
|
-
end
|
634
|
-
end
|
635
|
-
|
636
|
-
end
|
637
|
-
|
638
|
-
end unless AR42
|
639
50
|
end
|
640
51
|
end
|