activerecord-jdbc-adapter 5.0.pre1 → 51.0

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 (68) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +15 -416
  4. data/Gemfile +35 -37
  5. data/README.md +23 -118
  6. data/RUNNING_TESTS.md +31 -26
  7. data/Rakefile +2 -3
  8. data/activerecord-jdbc-adapter.gemspec +1 -2
  9. data/lib/arjdbc/abstract/connection_management.rb +21 -0
  10. data/lib/arjdbc/abstract/core.rb +62 -0
  11. data/lib/arjdbc/abstract/database_statements.rb +46 -0
  12. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  13. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  14. data/lib/arjdbc/derby/adapter.rb +6 -1
  15. data/lib/arjdbc/discover.rb +0 -7
  16. data/lib/arjdbc/firebird/adapter.rb +2 -2
  17. data/lib/arjdbc/jdbc/adapter.rb +10 -252
  18. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  19. data/lib/arjdbc/jdbc/connection.rb +6 -0
  20. data/lib/arjdbc/jdbc.rb +2 -2
  21. data/lib/arjdbc/mysql/adapter.rb +87 -944
  22. data/lib/arjdbc/mysql/connection_methods.rb +4 -2
  23. data/lib/arjdbc/postgresql/adapter.rb +288 -1023
  24. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  25. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  26. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
  27. data/lib/arjdbc/postgresql/column.rb +10 -599
  28. data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
  29. data/lib/arjdbc/postgresql/name.rb +24 -0
  30. data/lib/arjdbc/postgresql/oid_types.rb +25 -110
  31. data/lib/arjdbc/sqlite3/adapter.rb +171 -170
  32. data/lib/arjdbc/tasks/database_tasks.rb +1 -3
  33. data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
  34. data/lib/arjdbc/version.rb +1 -1
  35. data/pom.xml +3 -3
  36. data/rakelib/02-test.rake +0 -12
  37. data/rakelib/compile.rake +1 -1
  38. data/rakelib/db.rake +7 -5
  39. data/rakelib/rails.rake +63 -64
  40. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
  41. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
  42. data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
  43. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
  44. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
  45. data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
  46. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
  47. metadata +20 -34
  48. data/Appraisals +0 -41
  49. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  50. data/lib/arjdbc/common_jdbc_methods.rb +0 -89
  51. data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
  52. data/lib/arjdbc/mysql/column.rb +0 -162
  53. data/lib/arjdbc/mysql/explain_support.rb +0 -82
  54. data/lib/arjdbc/mysql/schema_creation.rb +0 -58
  55. data/lib/arjdbc/oracle/adapter.rb +0 -952
  56. data/lib/arjdbc/oracle/column.rb +0 -126
  57. data/lib/arjdbc/oracle/connection_methods.rb +0 -21
  58. data/lib/arjdbc/oracle.rb +0 -4
  59. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +0 -21
  60. data/lib/arjdbc/postgresql/base/oid.rb +0 -412
  61. data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
  62. data/lib/arjdbc/postgresql/explain_support.rb +0 -53
  63. data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
  64. data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
  65. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
  66. data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
  67. data/src/java/arjdbc/oracle/OracleModule.java +0 -75
  68. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -1,952 +0,0 @@
1
- # NOTE: file contains code adapted from **oracle-enhanced** adapter, license follows
2
- =begin
3
- Copyright (c) 2008-2011 Graham Jenkins, Michael Schoen, Raimonds Simanovskis
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
- =end
24
-
25
- ArJdbc.load_java_part :Oracle
26
-
27
- module ArJdbc
28
- module Oracle
29
-
30
- require 'arjdbc/oracle/column'
31
-
32
- # @private
33
- def self.extended(adapter); initialize!; end
34
-
35
- # @private
36
- @@_initialized = nil
37
-
38
- # @private
39
- def self.initialize!
40
- return if @@_initialized; @@_initialized = true
41
-
42
- require 'arjdbc/util/serialized_attributes'
43
- Util::SerializedAttributes.setup /LOB\(|LOB$/i, 'after_save_with_oracle_lob'
44
-
45
- unless ActiveRecord::ConnectionAdapters::AbstractAdapter.
46
- instance_methods(false).detect { |m| m.to_s == "prefetch_primary_key?" }
47
- require 'arjdbc/jdbc/quoted_primary_key'
48
- ActiveRecord::Base.extend ArJdbc::QuotedPrimaryKeyExtension
49
- end
50
- end
51
-
52
- # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
53
- def self.jdbc_connection_class
54
- ::ActiveRecord::ConnectionAdapters::OracleJdbcConnection
55
- end
56
-
57
- # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
58
- def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::OracleColumn end
59
-
60
- # @private
61
- @@update_lob_values = true
62
-
63
- # Updating records with LOB values (binary/text columns) in a separate
64
- # statement can be disabled using :
65
- #
66
- # ArJdbc::Oracle.update_lob_values = false
67
- #
68
- # @note This only applies when prepared statements are not used.
69
- def self.update_lob_values?; @@update_lob_values; end
70
- # @see #update_lob_values?
71
- def self.update_lob_values=(update); @@update_lob_values = update; end
72
-
73
- # @see #update_lob_values?
74
- # @see ArJdbc::Util::SerializedAttributes#update_lob_columns
75
- def update_lob_value?(value, column = nil)
76
- Oracle.update_lob_values? && ! prepared_statements? && ! ( value.nil? || value == '' )
77
- end
78
-
79
- # @private
80
- @@emulate_booleans = true
81
-
82
- # Boolean emulation can be disabled using :
83
- #
84
- # ArJdbc::Oracle.emulate_booleans = false
85
- #
86
- # @see ActiveRecord::ConnectionAdapters::OracleAdapter#emulate_booleans
87
- def self.emulate_booleans?; @@emulate_booleans; end
88
- # @deprecated Use {#emulate_booleans?} instead.
89
- def self.emulate_booleans; @@emulate_booleans; end
90
- # @see #emulate_booleans?
91
- def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
92
-
93
- class TableDefinition < ::ActiveRecord::ConnectionAdapters::TableDefinition
94
- def raw(*args)
95
- options = args.extract_options!
96
- column(args[0], 'raw', options)
97
- end unless AR42
98
-
99
- def raw(name, options={})
100
- column(name, :raw, options)
101
- end if AR42
102
-
103
- def xml(*args)
104
- options = args.extract_options!
105
- column(args[0], 'xml', options)
106
- end unless AR42
107
-
108
- def raw(name, options={})
109
- column(name, :xml, options)
110
- end if AR42
111
-
112
- def aliased_types(name, fallback)
113
- # NOTE: disable aliasing :timestamp as :datetime :
114
- fallback # 'timestamp' == name ? :datetime : fallback
115
- end if AR42
116
- end
117
-
118
- def table_definition(*args)
119
- new_table_definition(TableDefinition, *args)
120
- end
121
-
122
- def create_table_definition(name, temporary, options, as = nil)
123
- TableDefinition.new native_database_types, name, temporary, options, as
124
- end if AR42
125
-
126
- ADAPTER_NAME = 'Oracle'.freeze
127
-
128
- def adapter_name
129
- ADAPTER_NAME
130
- end
131
-
132
- def initialize_type_map(m)
133
- super
134
-
135
- m.register_type(%r(NUMBER)i) do |sql_type|
136
- scale = extract_scale(sql_type)
137
- precision = extract_precision(sql_type)
138
- limit = extract_limit(sql_type)
139
- if scale == 0
140
- if Oracle.emulate_booleans? && limit == 1
141
- ActiveRecord::Type::Boolean.new
142
- else
143
- ActiveRecord::Type::Integer.new(:precision => precision, :limit => limit)
144
- end
145
- else
146
- ActiveRecord::Type::Decimal.new(:precision => precision, :scale => scale)
147
- end
148
- end
149
-
150
- register_class_with_limit m, %r(date)i, ActiveRecord::Type::DateTime
151
- register_class_with_limit m, %r(raw)i, RawType
152
- register_class_with_limit m, %r(timestamp)i, TimestampType
153
-
154
- m.register_type %r(xmltype)i, XmlType.new
155
- end if AR42
156
-
157
- def clear_cache!
158
- super
159
- reload_type_map
160
- end if AR42
161
-
162
- # @private
163
- class RawType < ActiveRecord::Type::String
164
- def type; :raw end
165
- end if AR42
166
-
167
- # @private
168
- class TimestampType < ActiveRecord::Type::DateTime
169
- def type; :timestamp end
170
- end if AR42
171
-
172
- # @private
173
- class XmlType < ActiveRecord::Type::String
174
- def type; :xml end
175
-
176
- def type_cast_for_database(value)
177
- return unless value
178
- Data.new(super)
179
- end
180
-
181
- class Data
182
- def initialize(value)
183
- @value = value
184
- end
185
- def to_s; @value end
186
- end
187
- end if AR42
188
-
189
- NATIVE_DATABASE_TYPES = {
190
- :primary_key => "NUMBER(38) NOT NULL PRIMARY KEY",
191
- :string => { :name => "VARCHAR2", :limit => 255 },
192
- :text => { :name => "CLOB" },
193
- :integer => { :name => "NUMBER", :limit => 38 },
194
- :float => { :name => "NUMBER" },
195
- :decimal => { :name => "DECIMAL" },
196
- :datetime => { :name => "DATE" },
197
- :timestamp => { :name => "TIMESTAMP" },
198
- :time => { :name => "DATE" },
199
- :date => { :name => "DATE" },
200
- :binary => { :name => "BLOB" },
201
- :boolean => { :name => "NUMBER", :limit => 1 },
202
- :raw => { :name => "RAW", :limit => 2000 },
203
- :xml => { :name => 'XMLTYPE' }
204
- }
205
-
206
- def native_database_types
207
- super.merge(NATIVE_DATABASE_TYPES)
208
- end
209
-
210
- def modify_types(types)
211
- super(types)
212
- NATIVE_DATABASE_TYPES.each do |key, value|
213
- types[key] = value.dup
214
- end
215
- types
216
- end
217
-
218
- # Prevent ORA-01795 for in clauses with more than 1000
219
- def in_clause_length
220
- 1000
221
- end
222
- alias_method :ids_in_list_limit, :in_clause_length
223
-
224
- IDENTIFIER_LENGTH = 30
225
-
226
- # maximum length of Oracle identifiers is 30
227
- def table_alias_length; IDENTIFIER_LENGTH; end
228
- def table_name_length; IDENTIFIER_LENGTH; end
229
- def index_name_length; IDENTIFIER_LENGTH; end
230
- def column_name_length; IDENTIFIER_LENGTH; end
231
- def sequence_name_length; IDENTIFIER_LENGTH end
232
-
233
- # @private
234
- # Will take all or first 26 characters of table name and append _seq suffix
235
- def default_sequence_name(table_name, primary_key = nil)
236
- len = IDENTIFIER_LENGTH - 4
237
- table_name.to_s.gsub (/(^|\.)([\w$-]{1,#{len}})([\w$-]*)$/), '\1\2_seq'
238
- end
239
-
240
- # @private
241
- def default_trigger_name(table_name)
242
- "#{table_name.to_s[0, IDENTIFIER_LENGTH - 4]}_pkt"
243
- end
244
-
245
- # @override
246
- def create_table(name, options = {})
247
- super(name, options)
248
- unless options[:id] == false
249
- seq_name = options[:sequence_name] || default_sequence_name(name)
250
- start_value = options[:sequence_start_value] || 10000
251
- raise ActiveRecord::StatementInvalid.new("name #{seq_name} too long") if seq_name.length > table_alias_length
252
- execute "CREATE SEQUENCE #{quote_table_name(seq_name)} START WITH #{start_value}"
253
- end
254
- end
255
-
256
- # @override
257
- def rename_table(name, new_name)
258
- if new_name.to_s.length > table_name_length
259
- raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{table_name_length} characters"
260
- end
261
- if "#{new_name}_seq".to_s.length > sequence_name_length
262
- raise ArgumentError, "New sequence name '#{new_name}_seq' is too long; the limit is #{sequence_name_length} characters"
263
- end
264
- execute "RENAME #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
265
- execute "RENAME #{quote_table_name("#{name}_seq")} TO #{quote_table_name("#{new_name}_seq")}" rescue nil
266
- end
267
-
268
- # @override
269
- def drop_table(name, options = {})
270
- outcome = super(name)
271
- return outcome if name == 'schema_migrations'
272
- seq_name = options.key?(:sequence_name) ? # pass nil/false - no sequence
273
- options[:sequence_name] : default_sequence_name(name)
274
- return outcome unless seq_name
275
- execute_quietly "DROP SEQUENCE #{quote_table_name(seq_name)}"
276
- end
277
-
278
- # @override
279
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
280
- case type.to_sym
281
- when :binary
282
- # { BLOB | BINARY LARGE OBJECT } [ ( length [{K |M |G }] ) ]
283
- # although Oracle does not like limit (length) with BLOB (or CLOB) :
284
- #
285
- # CREATE TABLE binaries (data BLOB, short_data BLOB(1024));
286
- # ORA-00907: missing right parenthesis *
287
- #
288
- # TODO do we need to worry about NORMAL vs. non IN-TABLE BLOBs ?!
289
- # http://dba.stackexchange.com/questions/8770/improve-blob-writing-performance-in-oracle-11g
290
- # - if the LOB is smaller than 3900 bytes it can be stored inside the
291
- # table row; by default this is enabled,
292
- # unless you specify DISABLE STORAGE IN ROW
293
- # - normal LOB - stored in a separate segment, outside of table,
294
- # you may even put it in another tablespace;
295
- super(type, nil, nil, nil)
296
- when :text
297
- super(type, nil, nil, nil)
298
- else
299
- super
300
- end
301
- end
302
-
303
- def indexes(table, name = nil)
304
- @connection.indexes(table, name, schema_owner)
305
- end
306
-
307
- # @note Only used with (non-AREL) ActiveRecord **2.3**.
308
- # @see Arel::Visitors::Oracle
309
- def add_limit_offset!(sql, options)
310
- offset = options[:offset] || 0
311
- if limit = options[:limit]
312
- sql.replace "SELECT * FROM " <<
313
- "(select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset + limit})" <<
314
- " WHERE raw_rnum_ > #{offset}"
315
- elsif offset > 0
316
- sql.replace "SELECT * FROM " <<
317
- "(select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_)" <<
318
- " WHERE raw_rnum_ > #{offset}"
319
- end
320
- end if ::ActiveRecord::VERSION::MAJOR < 3
321
-
322
- def current_user
323
- @current_user ||= execute("SELECT sys_context('userenv', 'session_user') su FROM dual").first['su']
324
- end
325
-
326
- def current_database
327
- @current_database ||= execute("SELECT sys_context('userenv', 'db_name') db FROM dual").first['db']
328
- end
329
-
330
- def current_schema
331
- execute("SELECT sys_context('userenv', 'current_schema') schema FROM dual").first['schema']
332
- end
333
-
334
- def current_schema=(schema_owner)
335
- execute("ALTER SESSION SET current_schema=#{schema_owner}")
336
- end
337
-
338
- # @override
339
- def release_savepoint(name = nil)
340
- # no RELEASE SAVEPOINT statement in Oracle (JDBC driver throws "Unsupported feature")
341
- end
342
-
343
- # @override
344
- def add_index(table_name, column_name, options = {})
345
- index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, options)
346
- execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
347
- if index_type == 'UNIQUE'
348
- unless quoted_column_names =~ /\(.*\)/
349
- execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
350
- end
351
- end
352
- end if AR42
353
-
354
- # @private
355
- def add_index_options(table_name, column_name, options = {})
356
- column_names = Array(column_name)
357
- index_name = index_name(table_name, column: column_names)
358
-
359
- options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :tablespace, :options, :using)
360
-
361
- index_type = options[:unique] ? "UNIQUE" : ""
362
- index_name = options[:name].to_s if options.key?(:name)
363
- tablespace = '' # tablespace_for(:index, options[:tablespace])
364
- max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
365
- index_options = '' # index_options = options[:options]
366
-
367
- if index_name.to_s.length > max_index_length
368
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
369
- end
370
- if index_name_exists?(table_name, index_name, false)
371
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
372
- end
373
-
374
- quoted_column_names = column_names.map { |e| quote_column_name(e, true) }.join(", ")
375
- [ index_name, index_type, quoted_column_names, tablespace, index_options ]
376
- end if AR42
377
-
378
- # @override
379
- def remove_index(table_name, options = {})
380
- index_name = index_name(table_name, options)
381
- unless index_name_exists?(table_name, index_name, true)
382
- # sometimes options can be String or Array with column names
383
- options = {} unless options.is_a?(Hash)
384
- if options.has_key? :name
385
- options_without_column = options.dup
386
- options_without_column.delete :column
387
- index_name_without_column = index_name(table_name, options_without_column)
388
- return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
389
- end
390
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
391
- end
392
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
393
- execute "DROP INDEX #{quote_column_name(index_name)}"
394
- end if AR42
395
-
396
- # @private
397
- def remove_index(table_name, options = {})
398
- execute "DROP INDEX #{index_name(table_name, options)}"
399
- end unless AR42
400
-
401
- def change_column_default(table_name, column_name, default)
402
- execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
403
- end
404
-
405
- # @override
406
- def add_column_options!(sql, options)
407
- # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
408
- if options_include_default?(options) && (column = options[:column]) && column.type == :text
409
- sql << " DEFAULT #{quote(options.delete(:default))}"
410
- end
411
- super
412
- end
413
-
414
- # @override
415
- def change_column(table_name, column_name, type, options = {})
416
- change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} " <<
417
- "MODIFY #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
418
- add_column_options!(change_column_sql, options)
419
- execute(change_column_sql)
420
- end
421
-
422
- # @override
423
- def rename_column(table_name, column_name, new_column_name)
424
- execute "ALTER TABLE #{quote_table_name(table_name)} " <<
425
- "RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
426
- end
427
-
428
- if ActiveRecord::VERSION::MAJOR >= 4
429
-
430
- # @override
431
- def remove_column(table_name, column_name, type = nil, options = {})
432
- do_remove_column(table_name, column_name)
433
- end
434
-
435
- else
436
-
437
- # @override
438
- def remove_column(table_name, *column_names)
439
- for column_name in column_names.flatten
440
- do_remove_column(table_name, column_name)
441
- end
442
- end
443
- alias remove_columns remove_column
444
-
445
- end
446
-
447
- def do_remove_column(table_name, column_name)
448
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
449
- end
450
- private :do_remove_column
451
-
452
- # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
453
- #
454
- # Oracle requires the ORDER BY columns to be in the SELECT list for DISTINCT
455
- # queries. However, with those columns included in the SELECT DISTINCT list, you
456
- # won't actually get a distinct list of the column you want (presuming the column
457
- # has duplicates with multiple values for the ordered-by columns. So we use the
458
- # FIRST_VALUE function to get a single (first) value for each column, effectively
459
- # making every row the same.
460
- #
461
- # distinct("posts.id", "posts.created_at desc")
462
- #
463
- # @override
464
- def distinct(columns, order_by)
465
- "DISTINCT #{columns_for_distinct(columns, order_by)}"
466
- end
467
-
468
- # @override Since AR 4.0 (on 4.1 {#distinct} is gone and won't be called).
469
- def columns_for_distinct(columns, orders)
470
- return columns if orders.blank?
471
- if orders.is_a?(Array) # AR 3.x vs 4.x
472
- orders = orders.map { |column| column.is_a?(String) ? column : column.to_sql }
473
- else
474
- orders = extract_order_columns(orders)
475
- end
476
- # construct a valid DISTINCT clause, ie. one that includes the ORDER BY columns, using
477
- # FIRST_VALUE such that the inclusion of these columns doesn't invalidate the DISTINCT
478
- order_columns = orders.map do |c, i|
479
- "FIRST_VALUE(#{c.split.first}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
480
- end
481
- columns = [ columns ]; columns.flatten!
482
- columns.push( *order_columns ).join(', ')
483
- end
484
-
485
- # ORDER BY clause for the passed order option.
486
- #
487
- # Uses column aliases as defined by {#distinct}.
488
- def add_order_by_for_association_limiting!(sql, options)
489
- return sql if options[:order].blank?
490
-
491
- order_columns = extract_order_columns(options[:order]) do |columns|
492
- columns.map! { |s| $1 if s =~ / (.*)/ }; columns
493
- end
494
- order = order_columns.map { |s, i| "alias_#{i}__ #{s}" } # @see {#distinct}
495
-
496
- sql << "ORDER BY #{order.join(', ')}"
497
- end
498
-
499
- def extract_order_columns(order_by)
500
- columns = order_by.split(',')
501
- columns.map!(&:strip); columns.reject!(&:blank?)
502
- columns = yield(columns) if block_given?
503
- columns.zip( (0...columns.size).to_a )
504
- end
505
- private :extract_order_columns
506
-
507
- def temporary_table?(table_name)
508
- select_value("SELECT temporary FROM user_tables WHERE table_name = '#{table_name.upcase}'") == 'Y'
509
- end
510
-
511
- def tables
512
- @connection.tables(nil, oracle_schema)
513
- end
514
-
515
- # NOTE: better to use current_schema instead of the configured one ?!
516
- def columns(table_name, name = nil)
517
- @connection.columns_internal(table_name.to_s, nil, oracle_schema)
518
- end
519
-
520
- def tablespace(table_name)
521
- select_value "SELECT tablespace_name FROM user_tables WHERE table_name='#{table_name.to_s.upcase}'"
522
- end
523
-
524
- def charset
525
- database_parameters['NLS_CHARACTERSET']
526
- end
527
-
528
- def collation
529
- database_parameters['NLS_COMP']
530
- end
531
-
532
- def database_parameters
533
- return @database_parameters unless ( @database_parameters ||= {} ).empty?
534
- @connection.execute_query_raw("SELECT * FROM NLS_DATABASE_PARAMETERS") do
535
- |name, value| @database_parameters[name] = value
536
- end
537
- @database_parameters
538
- end
539
-
540
- # QUOTING ==================================================
541
-
542
- # @override
543
- def quote_table_name(name)
544
- name.to_s.split('.').map{ |n| n.split('@').map{ |m| quote_column_name(m) }.join('@') }.join('.')
545
- end
546
-
547
- # @private
548
- LOWER_CASE_ONLY = /\A[a-z][a-z_0-9\$#]*\Z/
549
-
550
- # @override
551
- def quote_column_name(name, handle_expression = false)
552
- # if only valid lowercase column characters in name
553
- if ( name = name.to_s ) =~ LOWER_CASE_ONLY
554
- # putting double-quotes around an identifier causes Oracle to treat the
555
- # identifier as case sensitive (otherwise assumes case-insensitivity) !
556
- # all upper case is an exception, where double-quotes are meaningless
557
- "\"#{name.upcase}\"" # name.upcase
558
- else
559
- if handle_expression
560
- name =~ /^[a-z][a-z_0-9\$#\-]*$/i ? "\"#{name}\"" : name
561
- else
562
- # remove double quotes which cannot be used inside quoted identifier
563
- "\"#{name.gsub('"', '')}\""
564
- end
565
- end
566
- end
567
-
568
- def unquote_table_name(name)
569
- name = name[1...-1] if name[0, 1] == '"'
570
- name.upcase == name ? name.downcase : name
571
- end
572
-
573
- # @override
574
- def quote(value, column = nil)
575
- return value if sql_literal?(value)
576
-
577
- column_type = column && column.type
578
- if column_type == :text || column_type == :binary
579
- return 'NULL' if value.nil? || value == ''
580
- if update_lob_value?(value, column)
581
- if /(.*?)\([0-9]+\)/ =~ ( sql_type = column.sql_type )
582
- %Q{empty_#{ $1.downcase }()}
583
- else
584
- %Q{empty_#{ sql_type.respond_to?(:downcase) ? sql_type.downcase : 'blob' }()}
585
- end
586
- else
587
- "'#{quote_string(value.to_s)}'"
588
- end
589
- elsif column_type == :xml
590
- "XMLTYPE('#{quote_string(value)}')" # XMLTYPE ?
591
- elsif column_type == :raw
592
- quote_raw(value)
593
- else
594
- if column.respond_to?(:primary) && column.primary && column.klass != String
595
- return value.to_i.to_s
596
- end
597
-
598
- if column_type == :datetime || column_type == :time
599
- if value.acts_like?(:time)
600
- %Q{TO_DATE('#{get_time(value).strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')}
601
- else
602
- value.blank? ? 'NULL' : %Q{DATE'#{value}'} # assume correctly formated DATE (string)
603
- end
604
- elsif ( like_date = value.acts_like?(:date) ) || column_type == :date
605
- if value.acts_like?(:time) # value.respond_to?(:strftime)
606
- %Q{DATE'#{get_time(value).strftime("%Y-%m-%d")}'}
607
- elsif like_date
608
- %Q{DATE'#{quoted_date(value)}'} # DATE 'YYYY-MM-DD'
609
- else
610
- value.blank? ? 'NULL' : %Q{DATE'#{value}'} # assume correctly formated DATE (string)
611
- end
612
- elsif ( like_time = value.acts_like?(:time) ) || column_type == :timestamp
613
- if like_time
614
- %Q{TIMESTAMP'#{quoted_date(value, true)}'} # TIMESTAMP 'YYYY-MM-DD HH24:MI:SS.FF'
615
- else
616
- value.blank? ? 'NULL' : %Q{TIMESTAMP'#{value}'} # assume correctly formated TIMESTAMP (string)
617
- end
618
- else
619
- super
620
- end
621
- end
622
- end
623
-
624
- # Quote date/time values for use in SQL input.
625
- # Includes milliseconds if the value is a Time responding to usec.
626
- # @override
627
- def quoted_date(value, time = nil)
628
- if time || ( time.nil? && value.acts_like?(:time) )
629
- usec = value.respond_to?(:usec) && (value.usec / 10000.0).round # .428000 -> .43
630
- return "#{get_time(value).to_s(:db)}.#{sprintf("%02d", usec)}" if usec
631
- # value.strftime("%Y-%m-%d %H:%M:%S")
632
- end
633
- value.to_s(:db)
634
- end
635
-
636
- def quote_raw(value)
637
- value = value.unpack('C*') if value.is_a?(String)
638
- "'#{value.map { |x| "%02X" % x }.join}'"
639
- end
640
-
641
- # @override
642
- def supports_migrations?; true end
643
-
644
- # @override
645
- def supports_primary_key?; true end
646
-
647
- # @override
648
- def supports_savepoints?; true end
649
-
650
- # @override
651
- def supports_explain?; true end
652
-
653
- # @override
654
- def supports_views?; true end
655
-
656
- def truncate(table_name, name = nil)
657
- execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
658
- end
659
-
660
- def explain(arel, binds = [])
661
- sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
662
- return if sql =~ /FROM all_/
663
- exec_update(sql, 'EXPLAIN', binds)
664
- select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", 'EXPLAIN').join("\n")
665
- end
666
-
667
- def select(sql, name = nil, binds = [])
668
- result = super # AR::Result (4.0) or Array (<= 3.2)
669
- result.columns.delete('raw_rnum_') if result.respond_to?(:columns)
670
- result.each { |row| row.delete('raw_rnum_') } # Hash rows even for AR::Result
671
- result
672
- end
673
-
674
- @@do_not_prefetch_primary_key = {}
675
-
676
- # Returns true for Oracle adapter (since Oracle requires primary key
677
- # values to be pre-fetched before insert).
678
- # @see #next_sequence_value
679
- # @override
680
- def prefetch_primary_key?(table_name = nil)
681
- return true if table_name.nil?
682
- do_not_prefetch_hash = @@do_not_prefetch_primary_key
683
- do_not_prefetch = do_not_prefetch_hash[ table_name = table_name.to_s ]
684
- if do_not_prefetch.nil?
685
- owner, desc_table_name, db_link = describe(table_name)
686
- do_not_prefetch_hash[table_name] = do_not_prefetch =
687
- ! has_primary_key?(table_name, owner, desc_table_name, db_link) ||
688
- has_primary_key_trigger?(table_name, owner, desc_table_name, db_link)
689
- end
690
- ! do_not_prefetch
691
- end
692
-
693
- # used to clear prefetch primary key flag for all tables
694
- # @private
695
- def clear_prefetch_primary_key; @@do_not_prefetch_primary_key = {} end
696
-
697
- # @private
698
- def has_primary_key?(table_name, owner = nil, desc_table_name = nil, db_link = nil)
699
- ! pk_and_sequence_for(table_name, owner, desc_table_name, db_link).nil?
700
- end
701
-
702
- # @private check if table has primary key trigger with _pkt suffix
703
- def has_primary_key_trigger?(table_name, owner = nil, desc_table_name = nil, db_link = nil)
704
- (owner, desc_table_name, db_link) = describe(table_name) unless desc_table_name
705
-
706
- trigger_name = default_trigger_name(table_name).upcase
707
- pkt_sql = "SELECT trigger_name FROM all_triggers#{db_link} WHERE owner = '#{owner}'" <<
708
- " AND trigger_name = '#{trigger_name}'" <<
709
- " AND table_owner = '#{owner}'" <<
710
- " AND table_name = '#{desc_table_name}'" <<
711
- " AND status = 'ENABLED'"
712
- select_value(pkt_sql, 'Primary Key Trigger') ? true : false
713
- end
714
-
715
- # use in set_sequence_name to avoid fetching primary key value from sequence
716
- AUTOGENERATED_SEQUENCE_NAME = 'autogenerated'.freeze
717
-
718
- # Returns the next sequence value from a sequence generator. Not generally
719
- # called directly; used by ActiveRecord to get the next primary key value
720
- # when inserting a new database record (see #prefetch_primary_key?).
721
- def next_sequence_value(sequence_name)
722
- # if sequence_name is set to :autogenerated then it means that primary key will be populated by trigger
723
- return nil if sequence_name == AUTOGENERATED_SEQUENCE_NAME
724
- sequence_name = quote_table_name(sequence_name)
725
- sql = "SELECT #{sequence_name}.NEXTVAL id FROM dual"
726
- log(sql, 'SQL') { @connection.next_sequence_value(sequence_name) }
727
- end
728
-
729
- def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil, db_link = nil)
730
- (owner, desc_table_name, db_link) = describe(table_name) unless desc_table_name
731
-
732
- seqs = "SELECT us.sequence_name" <<
733
- " FROM all_sequences#{db_link} us" <<
734
- " WHERE us.sequence_owner = '#{owner}'" <<
735
- " AND us.sequence_name = '#{desc_table_name}_SEQ'"
736
- seqs = select_values(seqs, 'Sequence')
737
-
738
- # changed back from user_constraints to all_constraints for consistency
739
- pks = "SELECT cc.column_name" <<
740
- " FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc" <<
741
- " WHERE c.owner = '#{owner}'" <<
742
- " AND c.table_name = '#{desc_table_name}'" <<
743
- " AND c.constraint_type = 'P'" <<
744
- " AND cc.owner = c.owner" <<
745
- " AND cc.constraint_name = c.constraint_name"
746
- pks = select_values(pks, 'Primary Key')
747
-
748
- # only support single column keys
749
- pks.size == 1 ? [oracle_downcase(pks.first), oracle_downcase(seqs.first)] : nil
750
- end
751
- private :pk_and_sequence_for
752
-
753
- # Returns just a table's primary key
754
- def primary_key(table_name)
755
- pk_and_sequence = pk_and_sequence_for(table_name)
756
- pk_and_sequence && pk_and_sequence.first
757
- end
758
-
759
- # @override
760
- def supports_foreign_keys?; true end
761
-
762
- # @private
763
- def disable_referential_integrity
764
- sql_constraints = "SELECT constraint_name, owner, table_name FROM user_constraints WHERE constraint_type = 'R' AND status = 'ENABLED'"
765
- old_constraints = select_all(sql_constraints)
766
- begin
767
- old_constraints.each do |constraint|
768
- execute "ALTER TABLE #{constraint["table_name"]} DISABLE CONSTRAINT #{constraint["constraint_name"]}"
769
- end
770
- yield
771
- ensure
772
- old_constraints.reverse_each do |constraint|
773
- execute "ALTER TABLE #{constraint["table_name"]} ENABLE CONSTRAINT #{constraint["constraint_name"]}"
774
- end
775
- end
776
- end
777
-
778
- # @override (for AR <= 3.0)
779
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
780
- # if PK is already pre-fetched from sequence or if there is no PK :
781
- if id_value || pk.nil?
782
- execute(sql, name)
783
- return id_value
784
- end
785
-
786
- if pk && use_insert_returning? # true by default on AR <= 3.0
787
- sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO ?"
788
- exec_insert_returning(sql, name, nil, pk)
789
- else
790
- execute(sql, name)
791
- end
792
- end
793
- protected :insert_sql
794
-
795
- # @override
796
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
797
- unless id_value || pk.nil?
798
- if pk && use_insert_returning?
799
- sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO ?"
800
- end
801
- end
802
- [ sql, binds ]
803
- end
804
-
805
- # @override
806
- def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
807
- # NOTE: ActiveRecord::Relation calls our {#next_sequence_value}
808
- # (from its `insert`) and passes the returned id_value here ...
809
- sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
810
- if id_value
811
- exec_update(sql, name, binds)
812
- return id_value
813
- else
814
- value = exec_insert(sql, name, binds, pk, sequence_name)
815
- id_value || last_inserted_id(value)
816
- end
817
- end
818
-
819
- # @override
820
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
821
- if pk && use_insert_returning?
822
- if sql.is_a?(String) && sql.index('RETURNING')
823
- return exec_insert_returning(sql, name, binds, pk)
824
- end
825
- end
826
- super(sql, name, binds) # assume no generated id for table
827
- end
828
-
829
- def exec_insert_returning(sql, name, binds, pk = nil)
830
- sql = to_sql(sql, binds) if sql.respond_to?(:to_sql)
831
- if prepared_statements?
832
- log(sql, name, binds) { @connection.execute_insert_returning(sql, binds) }
833
- else
834
- log(sql, name) { @connection.execute_insert_returning(sql, nil) }
835
- end
836
- end
837
- # private :exec_insert_returning
838
-
839
- def next_id_value(sql, sequence_name = nil)
840
- # Assume the SQL contains a bind-variable for the ID
841
- sequence_name ||= begin
842
- # Extract the table from the insert SQL. Yuck.
843
- table = extract_table_ref_from_insert_sql(sql)
844
- default_sequence_name(table)
845
- end
846
- next_sequence_value(sequence_name)
847
- end
848
- private :next_id_value
849
-
850
- def use_insert_returning?
851
- if @use_insert_returning.nil?
852
- @use_insert_returning = false
853
- end
854
- @use_insert_returning
855
- end
856
-
857
- private
858
-
859
- def _execute(sql, name = nil)
860
- if self.class.select?(sql)
861
- @connection.execute_query_raw(sql)
862
- elsif self.class.insert?(sql)
863
- @connection.execute_insert(sql)
864
- else
865
- @connection.execute_update(sql)
866
- end
867
- end
868
-
869
- def extract_table_ref_from_insert_sql(sql)
870
- table = sql.split(" ", 4)[2]
871
- if idx = table.index('(')
872
- table = table[0...idx] # INTO table(col1, col2) ...
873
- end
874
- unquote_table_name(table)
875
- end
876
-
877
- # In Oracle, schemas are usually created under your username :
878
- # http://www.oracle.com/technology/obe/2day_dba/schema/schema.htm
879
- #
880
- # A schema is the set of objects (tables, views, indexes, etc) that belongs
881
- # to an user, often used as another way to refer to an Oracle user account.
882
- #
883
- # But allow separate configuration as "schema:" anyway (see #53)
884
- def oracle_schema
885
- if @config[:schema]
886
- @config[:schema].to_s
887
- elsif @config[:username]
888
- @config[:username].to_s
889
- end
890
- end
891
-
892
- # default schema owner
893
- def schema_owner(force = true)
894
- unless defined? @schema_owner
895
- username = config[:username] ? config[:username].to_s : nil
896
- username = jdbc_connection.meta_data.user_name if force && username.nil?
897
- @schema_owner = username.nil? ? nil : username.upcase
898
- end
899
- @schema_owner
900
- end
901
-
902
- # do not force reading schema_owner as we're read on our own ...
903
- def describe(table_name, owner = schema_owner(false))
904
- @connection.describe(table_name, owner)
905
- end
906
-
907
- def oracle_downcase(column_name)
908
- return nil if column_name.nil?
909
- column_name =~ /[a-z]/ ? column_name : column_name.downcase
910
- end
911
-
912
- end
913
- end
914
-
915
- require 'arjdbc/util/quoted_cache'
916
-
917
- module ActiveRecord::ConnectionAdapters
918
-
919
- remove_const(:OracleAdapter) if const_defined?(:OracleAdapter)
920
-
921
- class OracleAdapter < JdbcAdapter
922
- include ::ArJdbc::Oracle
923
- include ::ArJdbc::Util::QuotedCache
924
-
925
- # By default, the OracleAdapter will consider all columns of type
926
- # <tt>NUMBER(1)</tt> as boolean. If you wish to disable this :
927
- #
928
- # ActiveRecord::ConnectionAdapters::OracleAdapter.emulate_booleans = false
929
- #
930
- def self.emulate_booleans?; ::ArJdbc::Oracle.emulate_booleans?; end
931
- def self.emulate_booleans; ::ArJdbc::Oracle.emulate_booleans?; end # oracle-enhanced
932
- def self.emulate_booleans=(emulate); ::ArJdbc::Oracle.emulate_booleans = emulate; end
933
-
934
- def initialize(*args)
935
- ::ArJdbc::Oracle.initialize!
936
- super # configure_connection happens in super
937
-
938
- @use_insert_returning = config.key?(:insert_returning) ?
939
- self.class.type_cast_config_to_boolean(config[:insert_returning]) : nil
940
- end
941
-
942
- end
943
-
944
- class OracleColumn < JdbcColumn
945
- include ::ArJdbc::Oracle::Column
946
-
947
- # def returning_id?; @returning_id ||= nil end
948
- # def returning_id!; @returning_id = true end
949
-
950
- end
951
-
952
- end