activerecord-jdbc-adapter 1.3.17 → 1.3.18
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.
- checksums.yaml +4 -4
- data/.travis.yml +24 -5
- data/History.md +54 -0
- data/lib/arel/visitors/compat.rb +30 -2
- data/lib/arel/visitors/db2.rb +118 -29
- data/lib/arel/visitors/derby.rb +84 -29
- data/lib/arel/visitors/firebird.rb +66 -9
- data/lib/arel/visitors/h2.rb +16 -0
- data/lib/arel/visitors/hsqldb.rb +6 -3
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +121 -40
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +1 -7
- data/lib/arjdbc/db2.rb +1 -0
- data/lib/arjdbc/db2/adapter.rb +118 -18
- data/lib/arjdbc/derby/adapter.rb +29 -8
- data/lib/arjdbc/firebird.rb +1 -0
- data/lib/arjdbc/firebird/adapter.rb +126 -11
- data/lib/arjdbc/hsqldb/adapter.rb +3 -0
- data/lib/arjdbc/informix.rb +1 -0
- data/lib/arjdbc/jdbc.rb +17 -0
- data/lib/arjdbc/jdbc/adapter.rb +28 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +7 -3
- data/lib/arjdbc/jdbc/type_cast.rb +2 -0
- data/lib/arjdbc/jdbc/type_converter.rb +28 -15
- data/lib/arjdbc/mimer.rb +1 -0
- data/lib/arjdbc/mssql.rb +2 -1
- data/lib/arjdbc/mssql/adapter.rb +105 -30
- data/lib/arjdbc/mssql/column.rb +30 -7
- data/lib/arjdbc/mssql/limit_helpers.rb +22 -9
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +25 -2
- data/lib/arjdbc/mysql/adapter.rb +22 -21
- data/lib/arjdbc/oracle.rb +1 -0
- data/lib/arjdbc/oracle/adapter.rb +291 -19
- data/lib/arjdbc/oracle/column.rb +9 -5
- data/lib/arjdbc/oracle/connection_methods.rb +4 -1
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
- data/lib/arjdbc/postgresql/adapter.rb +7 -1
- data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
- data/lib/arjdbc/postgresql/oid_types.rb +2 -1
- data/lib/arjdbc/tasks/database_tasks.rb +3 -0
- data/lib/arjdbc/util/quoted_cache.rb +2 -2
- data/lib/arjdbc/util/serialized_attributes.rb +11 -0
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/db.rake +3 -1
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +259 -61
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +13 -2
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +192 -15
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +10 -2
- metadata +9 -4
data/lib/arjdbc/mssql/utils.rb
CHANGED
@@ -1,12 +1,35 @@
|
|
1
|
+
# NOTE: file contains code adapted from **sqlserver** adapter, license follows
|
2
|
+
=begin
|
3
|
+
Copyright (c) 2008-2015
|
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
|
+
|
1
25
|
module ArJdbc
|
2
26
|
module MSSQL
|
3
|
-
# @note Lot of code kindly borrowed from **activerecord-sqlserver-adapter**.
|
4
27
|
module Utils
|
5
28
|
|
6
29
|
module_function
|
7
30
|
|
8
31
|
GET_TABLE_NAME_INSERT_UPDATE_RE =
|
9
|
-
/^\s*(INSERT|EXEC sp_executesql N'INSERT)
|
32
|
+
/^\s*(INSERT|EXEC sp_executesql N'INSERT)(?:\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
|
10
33
|
|
11
34
|
GET_TABLE_NAME_FROM_RE = /\bFROM\s+([^\(\)\s,]+)\s*/i
|
12
35
|
|
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -553,6 +553,7 @@ module ArJdbc
|
|
553
553
|
# @private
|
554
554
|
ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition if ::ActiveRecord::ConnectionAdapters.const_defined? :ForeignKeyDefinition
|
555
555
|
|
556
|
+
# @override
|
556
557
|
def supports_foreign_keys?; true end
|
557
558
|
|
558
559
|
def foreign_keys(table_name)
|
@@ -786,22 +787,22 @@ module ArJdbc
|
|
786
787
|
|
787
788
|
register_class_with_limit m, %r(char)i, MysqlString
|
788
789
|
|
789
|
-
m.register_type %r(tinytext)i, Type::Text.new(limit
|
790
|
-
m.register_type %r(tinyblob)i, Type::Binary.new(limit
|
791
|
-
m.register_type %r(text)i, Type::Text.new(limit
|
792
|
-
m.register_type %r(blob)i, Type::Binary.new(limit
|
793
|
-
m.register_type %r(mediumtext)i, Type::Text.new(limit
|
794
|
-
m.register_type %r(mediumblob)i, Type::Binary.new(limit
|
795
|
-
m.register_type %r(longtext)i, Type::Text.new(limit
|
796
|
-
m.register_type %r(longblob)i, Type::Binary.new(limit
|
797
|
-
m.register_type %r(^float)i, Type::Float.new(limit
|
798
|
-
m.register_type %r(^double)i, Type::Float.new(limit
|
799
|
-
|
800
|
-
register_integer_type m, %r(^bigint)i, limit
|
801
|
-
register_integer_type m, %r(^int)i, limit
|
802
|
-
register_integer_type m, %r(^mediumint)i, limit
|
803
|
-
register_integer_type m, %r(^smallint)i, limit
|
804
|
-
register_integer_type m, %r(^tinyint)i, limit
|
790
|
+
m.register_type %r(tinytext)i, Type::Text.new(:limit => 2**8 - 1)
|
791
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(:limit => 2**8 - 1)
|
792
|
+
m.register_type %r(text)i, Type::Text.new(:limit => 2**16 - 1)
|
793
|
+
m.register_type %r(blob)i, Type::Binary.new(:limit => 2**16 - 1)
|
794
|
+
m.register_type %r(mediumtext)i, Type::Text.new(:limit => 2**24 - 1)
|
795
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(:limit => 2**24 - 1)
|
796
|
+
m.register_type %r(longtext)i, Type::Text.new(:limit => 2**32 - 1)
|
797
|
+
m.register_type %r(longblob)i, Type::Binary.new(:limit => 2**32 - 1)
|
798
|
+
m.register_type %r(^float)i, Type::Float.new(:limit => 24)
|
799
|
+
m.register_type %r(^double)i, Type::Float.new(:limit => 53)
|
800
|
+
|
801
|
+
register_integer_type m, %r(^bigint)i, :limit => 8
|
802
|
+
register_integer_type m, %r(^int)i, :limit => 4
|
803
|
+
register_integer_type m, %r(^mediumint)i, :limit => 3
|
804
|
+
register_integer_type m, %r(^smallint)i, :limit => 2
|
805
|
+
register_integer_type m, %r(^tinyint)i, :limit => 1
|
805
806
|
|
806
807
|
m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
|
807
808
|
m.alias_type %r(set)i, 'varchar'
|
@@ -810,13 +811,13 @@ module ArJdbc
|
|
810
811
|
|
811
812
|
m.register_type(%r(datetime)i) do |sql_type|
|
812
813
|
precision = extract_precision(sql_type)
|
813
|
-
MysqlDateTime.new(precision
|
814
|
+
MysqlDateTime.new(:precision => precision)
|
814
815
|
end
|
815
816
|
|
816
817
|
m.register_type(%r(enum)i) do |sql_type|
|
817
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
818
|
-
|
819
|
-
MysqlString.new(limit
|
818
|
+
limit = sql_type[/^enum\((.+)\)/i, 1].split(',').
|
819
|
+
map{|enum| enum.strip.length - 2}.max
|
820
|
+
MysqlString.new(:limit => limit)
|
820
821
|
end
|
821
822
|
end if AR42
|
822
823
|
|
@@ -890,7 +891,7 @@ module ArJdbc
|
|
890
891
|
version << jdbc_connection.serverMinorVersion
|
891
892
|
version << jdbc_connection.serverSubMinorVersion
|
892
893
|
else
|
893
|
-
if match = full_version.match(/^(\d)\.(\d+)\.(\d+)/)
|
894
|
+
if match = full_version.match(/^(\d+)\.(\d+)\.(\d+)/)
|
894
895
|
version << match[1].to_i
|
895
896
|
version << match[2].to_i
|
896
897
|
version << match[3].to_i
|
data/lib/arjdbc/oracle.rb
CHANGED
@@ -1,3 +1,27 @@
|
|
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
|
+
|
1
25
|
ArJdbc.load_java_part :Oracle
|
2
26
|
|
3
27
|
module ArJdbc
|
@@ -70,18 +94,35 @@ module ArJdbc
|
|
70
94
|
def raw(*args)
|
71
95
|
options = args.extract_options!
|
72
96
|
column(args[0], 'raw', options)
|
73
|
-
end
|
97
|
+
end unless AR42
|
98
|
+
|
99
|
+
def raw(name, options={})
|
100
|
+
column(name, :raw, options)
|
101
|
+
end if AR42
|
74
102
|
|
75
103
|
def xml(*args)
|
76
104
|
options = args.extract_options!
|
77
105
|
column(args[0], 'xml', options)
|
78
|
-
end
|
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
|
79
116
|
end
|
80
117
|
|
81
118
|
def table_definition(*args)
|
82
119
|
new_table_definition(TableDefinition, *args)
|
83
120
|
end
|
84
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
|
+
|
85
126
|
def self.arel_visitor_type(config = nil)
|
86
127
|
::Arel::Visitors::Oracle
|
87
128
|
end
|
@@ -98,6 +139,63 @@ module ArJdbc
|
|
98
139
|
ADAPTER_NAME
|
99
140
|
end
|
100
141
|
|
142
|
+
def initialize_type_map(m)
|
143
|
+
super
|
144
|
+
|
145
|
+
m.register_type(%r(NUMBER)i) do |sql_type|
|
146
|
+
scale = extract_scale(sql_type)
|
147
|
+
precision = extract_precision(sql_type)
|
148
|
+
limit = extract_limit(sql_type)
|
149
|
+
if scale == 0
|
150
|
+
if Oracle.emulate_booleans? && limit == 1
|
151
|
+
ActiveRecord::Type::Boolean.new
|
152
|
+
else
|
153
|
+
ActiveRecord::Type::Integer.new(:precision => precision, :limit => limit)
|
154
|
+
end
|
155
|
+
else
|
156
|
+
ActiveRecord::Type::Decimal.new(:precision => precision, :scale => scale)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
register_class_with_limit m, %r(date)i, ActiveRecord::Type::DateTime
|
161
|
+
register_class_with_limit m, %r(raw)i, RawType
|
162
|
+
register_class_with_limit m, %r(timestamp)i, TimestampType
|
163
|
+
|
164
|
+
m.register_type %r(xmltype)i, XmlType.new
|
165
|
+
end if AR42
|
166
|
+
|
167
|
+
def clear_cache!
|
168
|
+
super
|
169
|
+
reload_type_map
|
170
|
+
end if AR42
|
171
|
+
|
172
|
+
# @private
|
173
|
+
class RawType < ActiveRecord::Type::String
|
174
|
+
def type; :raw end
|
175
|
+
end if AR42
|
176
|
+
|
177
|
+
# @private
|
178
|
+
class TimestampType < ActiveRecord::Type::DateTime
|
179
|
+
def type; :timestamp end
|
180
|
+
end if AR42
|
181
|
+
|
182
|
+
# @private
|
183
|
+
class XmlType < ActiveRecord::Type::String
|
184
|
+
def type; :xml end
|
185
|
+
|
186
|
+
def type_cast_for_database(value)
|
187
|
+
return unless value
|
188
|
+
Data.new(super)
|
189
|
+
end
|
190
|
+
|
191
|
+
class Data
|
192
|
+
def initialize(value)
|
193
|
+
@value = value
|
194
|
+
end
|
195
|
+
def to_s; @value end
|
196
|
+
end
|
197
|
+
end if AR42
|
198
|
+
|
101
199
|
NATIVE_DATABASE_TYPES = {
|
102
200
|
:primary_key => "NUMBER(38) NOT NULL PRIMARY KEY",
|
103
201
|
:string => { :name => "VARCHAR2", :limit => 255 },
|
@@ -142,9 +240,16 @@ module ArJdbc
|
|
142
240
|
def column_name_length; IDENTIFIER_LENGTH; end
|
143
241
|
def sequence_name_length; IDENTIFIER_LENGTH end
|
144
242
|
|
145
|
-
|
146
|
-
|
147
|
-
|
243
|
+
# @private
|
244
|
+
# Will take all or first 26 characters of table name and append _seq suffix
|
245
|
+
def default_sequence_name(table_name, primary_key = nil)
|
246
|
+
len = IDENTIFIER_LENGTH - 4
|
247
|
+
table_name.to_s.gsub (/(^|\.)([\w$-]{1,#{len}})([\w$-]*)$/), '\1\2_seq'
|
248
|
+
end
|
249
|
+
|
250
|
+
# @private
|
251
|
+
def default_trigger_name(table_name)
|
252
|
+
"#{table_name.to_s[0, IDENTIFIER_LENGTH - 4]}_pkt"
|
148
253
|
end
|
149
254
|
|
150
255
|
# @override
|
@@ -177,7 +282,7 @@ module ArJdbc
|
|
177
282
|
seq_name = options.key?(:sequence_name) ? # pass nil/false - no sequence
|
178
283
|
options[:sequence_name] : default_sequence_name(name)
|
179
284
|
return outcome unless seq_name
|
180
|
-
|
285
|
+
execute_quietly "DROP SEQUENCE #{quote_table_name(seq_name)}"
|
181
286
|
end
|
182
287
|
|
183
288
|
# @override
|
@@ -206,7 +311,7 @@ module ArJdbc
|
|
206
311
|
end
|
207
312
|
|
208
313
|
def indexes(table, name = nil)
|
209
|
-
@connection.indexes(table, name,
|
314
|
+
@connection.indexes(table, name, schema_owner)
|
210
315
|
end
|
211
316
|
|
212
317
|
# @note Only used with (non-AREL) ActiveRecord **2.3**.
|
@@ -245,13 +350,66 @@ module ArJdbc
|
|
245
350
|
# no RELEASE SAVEPOINT statement in Oracle (JDBC driver throws "Unsupported feature")
|
246
351
|
end
|
247
352
|
|
353
|
+
# @override
|
354
|
+
def add_index(table_name, column_name, options = {})
|
355
|
+
index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, options)
|
356
|
+
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
|
357
|
+
if index_type == 'UNIQUE'
|
358
|
+
unless quoted_column_names =~ /\(.*\)/
|
359
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end if AR42
|
363
|
+
|
364
|
+
# @private
|
365
|
+
def add_index_options(table_name, column_name, options = {})
|
366
|
+
column_names = Array(column_name)
|
367
|
+
index_name = index_name(table_name, column: column_names)
|
368
|
+
|
369
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :tablespace, :options, :using)
|
370
|
+
|
371
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
372
|
+
index_name = options[:name].to_s if options.key?(:name)
|
373
|
+
tablespace = '' # tablespace_for(:index, options[:tablespace])
|
374
|
+
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
375
|
+
index_options = '' # index_options = options[:options]
|
376
|
+
|
377
|
+
if index_name.to_s.length > max_index_length
|
378
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
379
|
+
end
|
380
|
+
if index_name_exists?(table_name, index_name, false)
|
381
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
382
|
+
end
|
383
|
+
|
384
|
+
quoted_column_names = column_names.map { |e| quote_column_name(e, true) }.join(", ")
|
385
|
+
[ index_name, index_type, quoted_column_names, tablespace, index_options ]
|
386
|
+
end if AR42
|
387
|
+
|
388
|
+
# @override
|
389
|
+
def remove_index(table_name, options = {})
|
390
|
+
index_name = index_name(table_name, options)
|
391
|
+
unless index_name_exists?(table_name, index_name, true)
|
392
|
+
# sometimes options can be String or Array with column names
|
393
|
+
options = {} unless options.is_a?(Hash)
|
394
|
+
if options.has_key? :name
|
395
|
+
options_without_column = options.dup
|
396
|
+
options_without_column.delete :column
|
397
|
+
index_name_without_column = index_name(table_name, options_without_column)
|
398
|
+
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
399
|
+
end
|
400
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
401
|
+
end
|
402
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
|
403
|
+
execute "DROP INDEX #{quote_column_name(index_name)}"
|
404
|
+
end if AR42
|
405
|
+
|
406
|
+
# @private
|
248
407
|
def remove_index(table_name, options = {})
|
249
408
|
execute "DROP INDEX #{index_name(table_name, options)}"
|
250
|
-
end
|
409
|
+
end unless AR42
|
251
410
|
|
252
411
|
def change_column_default(table_name, column_name, default)
|
253
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} "
|
254
|
-
"MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
412
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
255
413
|
end
|
256
414
|
|
257
415
|
# @override
|
@@ -396,17 +554,24 @@ module ArJdbc
|
|
396
554
|
name.to_s.split('.').map{ |n| n.split('@').map{ |m| quote_column_name(m) }.join('@') }.join('.')
|
397
555
|
end
|
398
556
|
|
557
|
+
# @private
|
558
|
+
LOWER_CASE_ONLY = /\A[a-z][a-z_0-9\$#]*\Z/
|
559
|
+
|
399
560
|
# @override
|
400
|
-
def quote_column_name(name)
|
561
|
+
def quote_column_name(name, handle_expression = false)
|
401
562
|
# if only valid lowercase column characters in name
|
402
|
-
if ( name = name.to_s ) =~
|
563
|
+
if ( name = name.to_s ) =~ LOWER_CASE_ONLY
|
403
564
|
# putting double-quotes around an identifier causes Oracle to treat the
|
404
565
|
# identifier as case sensitive (otherwise assumes case-insensitivity) !
|
405
566
|
# all upper case is an exception, where double-quotes are meaningless
|
406
567
|
"\"#{name.upcase}\"" # name.upcase
|
407
568
|
else
|
408
|
-
|
409
|
-
|
569
|
+
if handle_expression
|
570
|
+
name =~ /^[a-z][a-z_0-9\$#\-]*$/i ? "\"#{name}\"" : name
|
571
|
+
else
|
572
|
+
# remove double quotes which cannot be used inside quoted identifier
|
573
|
+
"\"#{name.gsub('"', '')}\""
|
574
|
+
end
|
410
575
|
end
|
411
576
|
end
|
412
577
|
|
@@ -516,23 +681,110 @@ module ArJdbc
|
|
516
681
|
result
|
517
682
|
end
|
518
683
|
|
684
|
+
@@do_not_prefetch_primary_key = {}
|
685
|
+
|
519
686
|
# Returns true for Oracle adapter (since Oracle requires primary key
|
520
687
|
# values to be pre-fetched before insert).
|
521
688
|
# @see #next_sequence_value
|
522
689
|
# @override
|
523
690
|
def prefetch_primary_key?(table_name = nil)
|
524
691
|
return true if table_name.nil?
|
525
|
-
|
526
|
-
|
692
|
+
do_not_prefetch_hash = @@do_not_prefetch_primary_key
|
693
|
+
do_not_prefetch = do_not_prefetch_hash[ table_name = table_name.to_s ]
|
694
|
+
if do_not_prefetch.nil?
|
695
|
+
owner, desc_table_name, db_link = describe(table_name)
|
696
|
+
do_not_prefetch_hash[table_name] = do_not_prefetch =
|
697
|
+
! has_primary_key?(table_name, owner, desc_table_name, db_link) ||
|
698
|
+
has_primary_key_trigger?(table_name, owner, desc_table_name, db_link)
|
699
|
+
end
|
700
|
+
! do_not_prefetch
|
527
701
|
end
|
528
702
|
|
529
|
-
#
|
703
|
+
# used to clear prefetch primary key flag for all tables
|
704
|
+
# @private
|
705
|
+
def clear_prefetch_primary_key; @@do_not_prefetch_primary_key = {} end
|
706
|
+
|
707
|
+
# @private
|
708
|
+
def has_primary_key?(table_name, owner = nil, desc_table_name = nil, db_link = nil)
|
709
|
+
! pk_and_sequence_for(table_name, owner, desc_table_name, db_link).nil?
|
710
|
+
end
|
711
|
+
|
712
|
+
# @private check if table has primary key trigger with _pkt suffix
|
713
|
+
def has_primary_key_trigger?(table_name, owner = nil, desc_table_name = nil, db_link = nil)
|
714
|
+
(owner, desc_table_name, db_link) = describe(table_name) unless desc_table_name
|
715
|
+
|
716
|
+
trigger_name = default_trigger_name(table_name).upcase
|
717
|
+
pkt_sql = "SELECT trigger_name FROM all_triggers#{db_link} WHERE owner = '#{owner}'" <<
|
718
|
+
" AND trigger_name = '#{trigger_name}'" <<
|
719
|
+
" AND table_owner = '#{owner}'" <<
|
720
|
+
" AND table_name = '#{desc_table_name}'" <<
|
721
|
+
" AND status = 'ENABLED'"
|
722
|
+
select_value(pkt_sql, 'Primary Key Trigger') ? true : false
|
723
|
+
end
|
724
|
+
|
725
|
+
# use in set_sequence_name to avoid fetching primary key value from sequence
|
726
|
+
AUTOGENERATED_SEQUENCE_NAME = 'autogenerated'.freeze
|
727
|
+
|
728
|
+
# Returns the next sequence value from a sequence generator. Not generally
|
729
|
+
# called directly; used by ActiveRecord to get the next primary key value
|
730
|
+
# when inserting a new database record (see #prefetch_primary_key?).
|
530
731
|
def next_sequence_value(sequence_name)
|
732
|
+
# if sequence_name is set to :autogenerated then it means that primary key will be populated by trigger
|
733
|
+
return nil if sequence_name == AUTOGENERATED_SEQUENCE_NAME
|
531
734
|
sequence_name = quote_table_name(sequence_name)
|
532
735
|
sql = "SELECT #{sequence_name}.NEXTVAL id FROM dual"
|
533
736
|
log(sql, 'SQL') { @connection.next_sequence_value(sequence_name) }
|
534
737
|
end
|
535
738
|
|
739
|
+
def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil, db_link = nil)
|
740
|
+
(owner, desc_table_name, db_link) = describe(table_name) unless desc_table_name
|
741
|
+
|
742
|
+
seqs = "SELECT us.sequence_name" <<
|
743
|
+
" FROM all_sequences#{db_link} us" <<
|
744
|
+
" WHERE us.sequence_owner = '#{owner}'" <<
|
745
|
+
" AND us.sequence_name = '#{desc_table_name}_SEQ'"
|
746
|
+
seqs = select_values(seqs, 'Sequence')
|
747
|
+
|
748
|
+
# changed back from user_constraints to all_constraints for consistency
|
749
|
+
pks = "SELECT cc.column_name" <<
|
750
|
+
" FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc" <<
|
751
|
+
" WHERE c.owner = '#{owner}'" <<
|
752
|
+
" AND c.table_name = '#{desc_table_name}'" <<
|
753
|
+
" AND c.constraint_type = 'P'" <<
|
754
|
+
" AND cc.owner = c.owner" <<
|
755
|
+
" AND cc.constraint_name = c.constraint_name"
|
756
|
+
pks = select_values(pks, 'Primary Key')
|
757
|
+
|
758
|
+
# only support single column keys
|
759
|
+
pks.size == 1 ? [oracle_downcase(pks.first), oracle_downcase(seqs.first)] : nil
|
760
|
+
end
|
761
|
+
private :pk_and_sequence_for
|
762
|
+
|
763
|
+
# Returns just a table's primary key
|
764
|
+
def primary_key(table_name)
|
765
|
+
pk_and_sequence = pk_and_sequence_for(table_name)
|
766
|
+
pk_and_sequence && pk_and_sequence.first
|
767
|
+
end
|
768
|
+
|
769
|
+
# @override
|
770
|
+
def supports_foreign_keys?; true end
|
771
|
+
|
772
|
+
# @private
|
773
|
+
def disable_referential_integrity
|
774
|
+
sql_constraints = "SELECT constraint_name, owner, table_name FROM user_constraints WHERE constraint_type = 'R' AND status = 'ENABLED'"
|
775
|
+
old_constraints = select_all(sql_constraints)
|
776
|
+
begin
|
777
|
+
old_constraints.each do |constraint|
|
778
|
+
execute "ALTER TABLE #{constraint["table_name"]} DISABLE CONSTRAINT #{constraint["constraint_name"]}"
|
779
|
+
end
|
780
|
+
yield
|
781
|
+
ensure
|
782
|
+
old_constraints.reverse_each do |constraint|
|
783
|
+
execute "ALTER TABLE #{constraint["table_name"]} ENABLE CONSTRAINT #{constraint["constraint_name"]}"
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
536
788
|
# @override (for AR <= 3.0)
|
537
789
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
538
790
|
# if PK is already pre-fetched from sequence or if there is no PK :
|
@@ -647,6 +899,26 @@ module ArJdbc
|
|
647
899
|
end
|
648
900
|
end
|
649
901
|
|
902
|
+
# default schema owner
|
903
|
+
def schema_owner(force = true)
|
904
|
+
unless defined? @schema_owner
|
905
|
+
username = config[:username] ? config[:username].to_s : nil
|
906
|
+
username = jdbc_connection.meta_data.user_name if force && username.nil?
|
907
|
+
@schema_owner = username.nil? ? nil : username.upcase
|
908
|
+
end
|
909
|
+
@schema_owner
|
910
|
+
end
|
911
|
+
|
912
|
+
# do not force reading schema_owner as we're read on our own ...
|
913
|
+
def describe(table_name, owner = schema_owner(false))
|
914
|
+
@connection.describe(table_name, owner)
|
915
|
+
end
|
916
|
+
|
917
|
+
def oracle_downcase(column_name)
|
918
|
+
return nil if column_name.nil?
|
919
|
+
column_name =~ /[a-z]/ ? column_name : column_name.downcase
|
920
|
+
end
|
921
|
+
|
650
922
|
end
|
651
923
|
end
|
652
924
|
|
@@ -660,8 +932,8 @@ module ActiveRecord::ConnectionAdapters
|
|
660
932
|
include ::ArJdbc::Oracle
|
661
933
|
include ::ArJdbc::Util::QuotedCache
|
662
934
|
|
663
|
-
# By default, the
|
664
|
-
# <tt>
|
935
|
+
# By default, the OracleAdapter will consider all columns of type
|
936
|
+
# <tt>NUMBER(1)</tt> as boolean. If you wish to disable this :
|
665
937
|
#
|
666
938
|
# ActiveRecord::ConnectionAdapters::OracleAdapter.emulate_booleans = false
|
667
939
|
#
|