activerecord-jdbc-adapter 1.3.7 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +33 -3
  3. data/Appraisals +11 -5
  4. data/Gemfile +21 -15
  5. data/History.md +31 -1
  6. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  7. data/lib/arel/visitors/firebird.rb +7 -10
  8. data/lib/arel/visitors/h2.rb +9 -0
  9. data/lib/arel/visitors/sql_server.rb +21 -2
  10. data/lib/arjdbc/h2/adapter.rb +31 -2
  11. data/lib/arjdbc/h2/connection_methods.rb +1 -1
  12. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  13. data/lib/arjdbc/jdbc/column.rb +2 -1
  14. data/lib/arjdbc/mssql/adapter.rb +40 -23
  15. data/lib/arjdbc/mssql/column.rb +4 -4
  16. data/lib/arjdbc/mysql/adapter.rb +36 -10
  17. data/lib/arjdbc/mysql/column.rb +12 -7
  18. data/lib/arjdbc/mysql/connection_methods.rb +53 -21
  19. data/lib/arjdbc/oracle/adapter.rb +22 -5
  20. data/lib/arjdbc/postgresql/adapter.rb +54 -18
  21. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  22. data/lib/arjdbc/postgresql/base/oid.rb +460 -0
  23. data/lib/arjdbc/postgresql/column.rb +50 -15
  24. data/lib/arjdbc/postgresql/oid_types.rb +126 -0
  25. data/lib/arjdbc/tasks/h2_database_tasks.rb +4 -2
  26. data/lib/arjdbc/version.rb +1 -1
  27. data/rakelib/02-test.rake +3 -30
  28. data/src/java/arjdbc/derby/DerbyModule.java +0 -8
  29. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +1 -0
  30. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +2 -0
  31. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +8 -8
  32. data/src/java/arjdbc/mssql/MSSQLModule.java +50 -19
  33. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +1 -0
  34. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +6 -6
  35. data/src/java/arjdbc/oracle/OracleModule.java +1 -1
  36. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +66 -2
  37. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +23 -10
  38. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +1 -0
  39. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  40. data/src/java/arjdbc/util/QuotingUtils.java +14 -7
  41. metadata +8 -3
  42. data/lib/arjdbc/postgresql/array_parser.rb +0 -89
@@ -0,0 +1,95 @@
1
+ # based on active_record/connection_adapters/postgresql/array_parser.rb
2
+ # until it's some day shareable with Rails ... this is not public API !
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module ArrayParser
7
+
8
+ DOUBLE_QUOTE = '"'
9
+ BACKSLASH = "\\"
10
+ COMMA = ','
11
+ BRACKET_OPEN = '{'
12
+ BRACKET_CLOSE = '}'
13
+
14
+ def parse_pg_array(string)
15
+ local_index = 0
16
+ array = []
17
+ while(local_index < string.length)
18
+ case string[local_index]
19
+ when BRACKET_OPEN
20
+ local_index,array = parse_array_contents(array, string, local_index + 1)
21
+ when BRACKET_CLOSE
22
+ return array
23
+ end
24
+ local_index += 1
25
+ end
26
+
27
+ array
28
+ end
29
+
30
+ private
31
+
32
+ def parse_array_contents(array, string, index)
33
+ is_escaping = false
34
+ is_quoted = false
35
+ was_quoted = false
36
+ current_item = ''
37
+
38
+ local_index = index
39
+ while local_index
40
+ token = string[local_index]
41
+ if is_escaping
42
+ current_item << token
43
+ is_escaping = false
44
+ else
45
+ if is_quoted
46
+ case token
47
+ when DOUBLE_QUOTE
48
+ is_quoted = false
49
+ was_quoted = true
50
+ when BACKSLASH
51
+ is_escaping = true
52
+ else
53
+ current_item << token
54
+ end
55
+ else
56
+ case token
57
+ when BACKSLASH
58
+ is_escaping = true
59
+ when COMMA
60
+ add_item_to_array(array, current_item, was_quoted)
61
+ current_item = ''
62
+ was_quoted = false
63
+ when DOUBLE_QUOTE
64
+ is_quoted = true
65
+ when BRACKET_OPEN
66
+ internal_items = []
67
+ local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
68
+ array.push(internal_items)
69
+ when BRACKET_CLOSE
70
+ add_item_to_array(array, current_item, was_quoted)
71
+ return local_index,array
72
+ else
73
+ current_item << token
74
+ end
75
+ end
76
+ end
77
+
78
+ local_index += 1
79
+ end
80
+ return local_index,array
81
+ end
82
+
83
+ def add_item_to_array(array, current_item, quoted)
84
+ return if !quoted && current_item.length == 0
85
+
86
+ if !quoted && current_item == 'NULL'
87
+ array.push nil
88
+ else
89
+ array.push current_item
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,460 @@
1
+ # copied from active_record/connection_adapters/postgresql/oid.rb
2
+ # until it's some day shareable with Rails ... this is not public API !
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module OID
7
+ class Type
8
+ def type; end
9
+ def simplified_type(sql_type); type end
10
+
11
+ def infinity(options = {})
12
+ ::Float::INFINITY * (options[:negative] ? -1 : 1)
13
+ end
14
+ end
15
+
16
+ class Identity < Type
17
+ def type_cast(value)
18
+ value
19
+ end
20
+ end
21
+
22
+ if ActiveRecord::VERSION::MINOR >= 2 # >= 4.2
23
+
24
+ class String < Type
25
+ def type; :string end
26
+
27
+ def type_cast(value)
28
+ return if value.nil?
29
+
30
+ value.to_s
31
+ end
32
+ end
33
+
34
+ else
35
+
36
+ # String, Text types do not exist in AR 4.0/4.1
37
+ # AR reports Identity for them - make it similar
38
+
39
+ class String < Identity
40
+ def type; :string end
41
+ end
42
+
43
+ end
44
+
45
+ class SpecializedString < OID::String
46
+ def type; @type end
47
+
48
+ def initialize(type)
49
+ @type = type
50
+ end
51
+ end
52
+
53
+ class Text < OID::String
54
+ def type; :text end
55
+ end
56
+
57
+ class Bit < Type
58
+ def type; :string end
59
+
60
+ def type_cast(value)
61
+ if ::String === value
62
+ ConnectionAdapters::PostgreSQLColumn.string_to_bit value
63
+ else
64
+ value
65
+ end
66
+ end
67
+ end
68
+
69
+ class Bytea < Type
70
+ def type; :binary end
71
+
72
+ def type_cast(value)
73
+ return if value.nil?
74
+ PGconn.unescape_bytea value
75
+ end
76
+ end
77
+
78
+ class Money < Type
79
+ def type; :decimal end
80
+
81
+ def type_cast(value)
82
+ return if value.nil?
83
+ return value unless ::String === value
84
+
85
+ # Because money output is formatted according to the locale, there are two
86
+ # cases to consider (note the decimal separators):
87
+ # (1) $12,345,678.12
88
+ # (2) $12.345.678,12
89
+ # Negative values are represented as follows:
90
+ # (3) -$2.55
91
+ # (4) ($2.55)
92
+
93
+ value.sub!(/^\((.+)\)$/, '-\1') # (4)
94
+ case value
95
+ when /^-?\D+[\d,]+\.\d{2}$/ # (1)
96
+ value.gsub!(/[^-\d.]/, '')
97
+ when /^-?\D+[\d.]+,\d{2}$/ # (2)
98
+ value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
99
+ end
100
+
101
+ ConnectionAdapters::Column.value_to_decimal value
102
+ end
103
+ end
104
+
105
+ class Vector < Type
106
+ attr_reader :delim, :subtype
107
+
108
+ # +delim+ corresponds to the `typdelim` column in the pg_types
109
+ # table. +subtype+ is derived from the `typelem` column in the
110
+ # pg_types table.
111
+ def initialize(delim, subtype)
112
+ @delim = delim
113
+ @subtype = subtype
114
+ end
115
+
116
+ # FIXME: this should probably split on +delim+ and use +subtype+
117
+ # to cast the values. Unfortunately, the current Rails behavior
118
+ # is to just return the string.
119
+ def type_cast(value)
120
+ value
121
+ end
122
+ end
123
+
124
+ class Point < Type
125
+ def type; :string end
126
+
127
+ def type_cast(value)
128
+ if ::String === value
129
+ ConnectionAdapters::PostgreSQLColumn.string_to_point value
130
+ else
131
+ value
132
+ end
133
+ end
134
+ end
135
+
136
+ class Array < Type
137
+ def type; @subtype.type end
138
+
139
+ attr_reader :subtype
140
+ def initialize(subtype)
141
+ @subtype = subtype
142
+ end
143
+
144
+ def type_cast(value)
145
+ if ::String === value
146
+ ConnectionAdapters::PostgreSQLColumn.string_to_array value, @subtype
147
+ else
148
+ value
149
+ end
150
+ end
151
+ end
152
+
153
+ class Range < Type
154
+ attr_reader :subtype
155
+ def simplified_type(sql_type); sql_type.to_sym end
156
+
157
+ def initialize(subtype)
158
+ @subtype = subtype
159
+ end
160
+
161
+ def extract_bounds(value)
162
+ from, to = value[1..-2].split(',')
163
+ {
164
+ from: (value[1] == ',' || from == '-infinity') ? @subtype.infinity(negative: true) : from,
165
+ to: (value[-2] == ',' || to == 'infinity') ? @subtype.infinity : to,
166
+ exclude_start: (value[0] == '('),
167
+ exclude_end: (value[-1] == ')')
168
+ }
169
+ end
170
+
171
+ def infinity?(value)
172
+ value.respond_to?(:infinite?) && value.infinite?
173
+ end
174
+
175
+ def type_cast_single(value)
176
+ infinity?(value) ? value : @subtype.type_cast(value)
177
+ end
178
+
179
+ def type_cast(value)
180
+ return if value.nil? || value == 'empty'
181
+ return value if value.is_a?(::Range)
182
+
183
+ extracted = extract_bounds(value)
184
+ from = type_cast_single extracted[:from]
185
+ to = type_cast_single extracted[:to]
186
+
187
+ if !infinity?(from) && extracted[:exclude_start]
188
+ if from.respond_to?(:succ)
189
+ from = from.succ
190
+ ActiveSupport::Deprecation.warn <<-MESSAGE
191
+ Excluding the beginning of a Range is only partialy supported through `#succ`.
192
+ This is not reliable and will be removed in the future.
193
+ MESSAGE
194
+ else
195
+ raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
196
+ end
197
+ end
198
+ ::Range.new(from, to, extracted[:exclude_end])
199
+ end
200
+ end
201
+
202
+ class Integer < Type
203
+ def type; :integer end
204
+
205
+ def type_cast(value)
206
+ return if value.nil?
207
+
208
+ ConnectionAdapters::Column.value_to_integer value
209
+ end
210
+ end
211
+
212
+ class Boolean < Type
213
+ def type; :boolean end
214
+
215
+ def type_cast(value)
216
+ return if value.nil?
217
+
218
+ ConnectionAdapters::Column.value_to_boolean value
219
+ end
220
+ end
221
+
222
+ class Timestamp < Type
223
+ def type; :timestamp; end
224
+ def simplified_type(sql_type)
225
+ :datetime
226
+ end
227
+
228
+ def type_cast(value)
229
+ return if value.nil?
230
+
231
+ # FIXME: probably we can improve this since we know it is PG
232
+ # specific
233
+ ConnectionAdapters::PostgreSQLColumn.string_to_time value
234
+ end
235
+ end
236
+
237
+ class Date < Type
238
+ def type; :date; end
239
+
240
+ def type_cast(value)
241
+ return if value.nil?
242
+
243
+ # FIXME: probably we can improve this since we know it is PG
244
+ # specific
245
+ ConnectionAdapters::Column.value_to_date value
246
+ end
247
+ end
248
+
249
+ class Time < Type
250
+ def type; :time end
251
+
252
+ def type_cast(value)
253
+ return if value.nil?
254
+
255
+ # FIXME: probably we can improve this since we know it is PG
256
+ # specific
257
+ ConnectionAdapters::Column.string_to_dummy_time value
258
+ end
259
+ end
260
+
261
+ class Float < Type
262
+ def type; :float end
263
+
264
+ def type_cast(value)
265
+ case value
266
+ when nil; nil
267
+ when 'Infinity'; ::Float::INFINITY
268
+ when '-Infinity'; -::Float::INFINITY
269
+ when 'NaN'; ::Float::NAN
270
+ else
271
+ value.to_f
272
+ end
273
+ end
274
+ end
275
+
276
+ class Decimal < Type
277
+ def type; :decimal end
278
+
279
+ def type_cast(value)
280
+ return if value.nil?
281
+
282
+ ConnectionAdapters::Column.value_to_decimal value
283
+ end
284
+
285
+ def infinity(options = {})
286
+ BigDecimal.new("Infinity") * (options[:negative] ? -1 : 1)
287
+ end
288
+ end
289
+
290
+ class Enum < Type
291
+ def type; :enum end
292
+
293
+ def type_cast(value)
294
+ value.to_s
295
+ end
296
+ end
297
+
298
+ class Hstore < Type
299
+ def type; :hstore end
300
+
301
+ def type_cast_for_write(value)
302
+ ConnectionAdapters::PostgreSQLColumn.hstore_to_string value
303
+ end
304
+
305
+ def type_cast(value)
306
+ return if value.nil?
307
+
308
+ ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
309
+ end
310
+
311
+ def accessor
312
+ ActiveRecord::Store::StringKeyedHashAccessor
313
+ end
314
+ end
315
+
316
+ class Cidr < Type
317
+ def type; :cidr end
318
+ def type_cast(value)
319
+ return if value.nil?
320
+
321
+ ConnectionAdapters::PostgreSQLColumn.string_to_cidr value
322
+ end
323
+ end
324
+ class Inet < Cidr
325
+ def type; :inet end
326
+ end
327
+
328
+ class Json < Type
329
+ def type; :json end
330
+
331
+ def type_cast_for_write(value)
332
+ ConnectionAdapters::PostgreSQLColumn.json_to_string value
333
+ end
334
+
335
+ def type_cast(value)
336
+ return if value.nil?
337
+
338
+ ConnectionAdapters::PostgreSQLColumn.string_to_json value
339
+ end
340
+
341
+ def accessor
342
+ ActiveRecord::Store::StringKeyedHashAccessor
343
+ end
344
+ end
345
+
346
+ class Uuid < Type
347
+ def type; :uuid end
348
+ def type_cast(value)
349
+ value.presence
350
+ end
351
+ end
352
+
353
+ class TypeMap
354
+ def initialize
355
+ @mapping = {}
356
+ end
357
+
358
+ def []=(oid, type)
359
+ @mapping[oid] = type
360
+ end
361
+
362
+ def [](oid)
363
+ @mapping[oid]
364
+ end
365
+
366
+ def clear
367
+ @mapping.clear
368
+ end
369
+
370
+ def key?(oid)
371
+ @mapping.key? oid
372
+ end
373
+
374
+ def fetch(ftype, fmod)
375
+ # The type for the numeric depends on the width of the field,
376
+ # so we'll do something special here.
377
+ #
378
+ # When dealing with decimal columns:
379
+ #
380
+ # places after decimal = fmod - 4 & 0xffff
381
+ # places before decimal = (fmod - 4) >> 16 & 0xffff
382
+ if ftype == 1700 && (fmod - 4 & 0xffff).zero?
383
+ ftype = 23
384
+ end
385
+
386
+ @mapping.fetch(ftype) { |oid| yield oid, fmod }
387
+ end
388
+ end
389
+
390
+ # When the PG adapter connects, the pg_type table is queried. The
391
+ # key of this hash maps to the `typname` column from the table.
392
+ # type_map is then dynamically built with oids as the key and type
393
+ # objects as values.
394
+ NAMES = Hash.new { |h,k| # :nodoc:
395
+ h[k] = OID::Identity.new
396
+ }
397
+
398
+ # Register an OID type named +name+ with a typecasting object in
399
+ # +type+. +name+ should correspond to the `typname` column in
400
+ # the `pg_type` table.
401
+ def self.register_type(name, type)
402
+ NAMES[name] = type
403
+ end
404
+
405
+ # Alias the +old+ type to the +new+ type.
406
+ def self.alias_type(new, old)
407
+ NAMES[new] = NAMES[old]
408
+ end
409
+
410
+ # Is +name+ a registered type?
411
+ def self.registered_type?(name)
412
+ NAMES.key? name
413
+ end
414
+
415
+ register_type 'int2', OID::Integer.new
416
+ alias_type 'int4', 'int2'
417
+ alias_type 'int8', 'int2'
418
+ alias_type 'oid', 'int2'
419
+ register_type 'numeric', OID::Decimal.new
420
+ register_type 'float4', OID::Float.new
421
+ alias_type 'float8', 'float4'
422
+ register_type 'text', OID::Text.new
423
+ register_type 'varchar', OID::String.new
424
+ alias_type 'char', 'varchar'
425
+ alias_type 'name', 'varchar'
426
+ alias_type 'bpchar', 'varchar'
427
+ register_type 'bool', OID::Boolean.new
428
+ register_type 'bit', OID::Bit.new
429
+ alias_type 'varbit', 'bit'
430
+ register_type 'timestamp', OID::Timestamp.new
431
+ alias_type 'timestamptz', 'timestamp'
432
+ register_type 'date', OID::Date.new
433
+ register_type 'time', OID::Time.new
434
+
435
+ register_type 'money', OID::Money.new
436
+ register_type 'bytea', OID::Bytea.new
437
+ register_type 'point', OID::Point.new
438
+ register_type 'hstore', OID::Hstore.new
439
+ register_type 'json', OID::Json.new
440
+ register_type 'cidr', OID::Cidr.new
441
+ register_type 'inet', OID::Inet.new
442
+ register_type 'uuid', OID::Uuid.new
443
+ register_type 'xml', SpecializedString.new(:xml)
444
+ register_type 'tsvector', SpecializedString.new(:tsvector)
445
+ register_type 'macaddr', SpecializedString.new(:macaddr)
446
+ register_type 'citext', SpecializedString.new(:citext)
447
+ register_type 'ltree', SpecializedString.new(:ltree)
448
+
449
+ # FIXME: why are we keeping these types as strings?
450
+ alias_type 'interval', 'varchar'
451
+ alias_type 'path', 'varchar'
452
+ alias_type 'line', 'varchar'
453
+ alias_type 'polygon', 'varchar'
454
+ alias_type 'circle', 'varchar'
455
+ alias_type 'lseg', 'varchar'
456
+ alias_type 'box', 'varchar'
457
+ end
458
+ end
459
+ end
460
+ end