activerecord-jdbc-alt-adapter 61.1.0-java → 70.0.0.rc1-java
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/.github/workflows/ruby.yml +273 -0
- data/.gitignore +1 -0
- data/.travis.yml +3 -4
- data/Gemfile +8 -6
- data/README.md +2 -1
- data/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +2 -2
- data/lib/arel/visitors/compat.rb +5 -33
- data/lib/arel/visitors/h2.rb +1 -13
- data/lib/arel/visitors/hsqldb.rb +1 -21
- data/lib/arel/visitors/sql_server.rb +2 -103
- data/lib/arjdbc/abstract/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +4 -4
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/hsqldb/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +3 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc/type_cast.rb +2 -2
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/mssql/adapter.rb +134 -105
- data/lib/arjdbc/mssql/quoting.rb +26 -27
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +32 -17
- data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
- data/lib/arjdbc/mssql/schema_statements.rb +61 -36
- data/lib/arjdbc/mssql/transaction.rb +2 -2
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +6 -6
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -2
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +4 -23
- data/lib/arjdbc/postgresql/adapter.rb +64 -1
- data/lib/arjdbc/postgresql/oid_types.rb +68 -47
- data/lib/arjdbc/sqlite3/adapter.rb +132 -88
- data/lib/arjdbc/tasks/database_tasks.rb +0 -12
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
- metadata +8 -40
- data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
- data/lib/arel/visitors/db2.rb +0 -137
- data/lib/arel/visitors/derby.rb +0 -112
- data/lib/arel/visitors/firebird.rb +0 -79
- data/lib/arjdbc/db2/adapter.rb +0 -808
- data/lib/arjdbc/db2/as400.rb +0 -142
- data/lib/arjdbc/db2/column.rb +0 -131
- data/lib/arjdbc/db2/connection_methods.rb +0 -48
- data/lib/arjdbc/db2.rb +0 -4
- data/lib/arjdbc/derby/active_record_patch.rb +0 -13
- data/lib/arjdbc/derby/adapter.rb +0 -521
- data/lib/arjdbc/derby/connection_methods.rb +0 -20
- data/lib/arjdbc/derby/schema_creation.rb +0 -15
- data/lib/arjdbc/derby.rb +0 -3
- data/lib/arjdbc/firebird/adapter.rb +0 -413
- data/lib/arjdbc/firebird/connection_methods.rb +0 -23
- data/lib/arjdbc/firebird.rb +0 -4
- data/lib/arjdbc/informix/adapter.rb +0 -139
- data/lib/arjdbc/informix/connection_methods.rb +0 -9
- data/lib/arjdbc/sybase/adapter.rb +0 -47
- data/lib/arjdbc/sybase.rb +0 -2
- data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
- data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
- data/src/java/arjdbc/derby/DerbyModule.java +0 -178
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +0 -75
data/lib/arjdbc/db2/adapter.rb
DELETED
@@ -1,808 +0,0 @@
|
|
1
|
-
# NOTE: file contains code adapted from **ruby-ibmdb** adapter, license follows
|
2
|
-
=begin
|
3
|
-
Copyright (c) 2006 - 2015 IBM Corporation
|
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 :DB2
|
26
|
-
|
27
|
-
require 'arjdbc/db2/column'
|
28
|
-
|
29
|
-
module ArJdbc
|
30
|
-
# @note This adapter doesn't support explain `config.active_record.auto_explain_threshold_in_seconds` should be commented (Rails < 4.0)
|
31
|
-
module DB2
|
32
|
-
|
33
|
-
|
34
|
-
module ActiveRecord::ConnectionAdapters
|
35
|
-
|
36
|
-
remove_const(:DB2Adapter) if const_defined?(:DB2Adapter)
|
37
|
-
|
38
|
-
class DB2Adapter < JdbcAdapter
|
39
|
-
|
40
|
-
include ArJdbc::DB2
|
41
|
-
include ArJdbc::DB2::Column
|
42
|
-
|
43
|
-
# AR 5.2 Fix
|
44
|
-
def initialize(connection, logger = nil, connection_parameters = nil, config = {})
|
45
|
-
super(connection, logger, config) # configure_connection happens in super
|
46
|
-
end
|
47
|
-
|
48
|
-
def jdbc_connection_class(spec)
|
49
|
-
ArJdbc::DB2.jdbc_connection_class
|
50
|
-
end
|
51
|
-
|
52
|
-
def data_source_sql(name = nil, type: nil)
|
53
|
-
scope = quoted_scope(name, type: type)
|
54
|
-
|
55
|
-
sql = if scope[:type] == "'T'"
|
56
|
-
"select table_name from sysibm.tables".dup
|
57
|
-
else
|
58
|
-
"select table_name from sysibm.views".dup
|
59
|
-
end
|
60
|
-
|
61
|
-
wheres = []
|
62
|
-
|
63
|
-
wheres << " table_type = #{scope[:type]}" if scope[:type]
|
64
|
-
wheres << " table_schema = #{scope[:schema]}" if scope[:schema]
|
65
|
-
wheres << " UPPER(table_name) = UPPER(#{scope[:name]})" if scope[:name]
|
66
|
-
|
67
|
-
if wheres.present?
|
68
|
-
sql << ' WHERE '
|
69
|
-
sql << wheres.join(' AND ')
|
70
|
-
end
|
71
|
-
sql
|
72
|
-
end
|
73
|
-
|
74
|
-
def quoted_scope(name = nil, type: nil)
|
75
|
-
type = \
|
76
|
-
case type
|
77
|
-
when "BASE TABLE"
|
78
|
-
"'T'"
|
79
|
-
when "VIEW"
|
80
|
-
"'V'"
|
81
|
-
end
|
82
|
-
scope = {}
|
83
|
-
scope[:name] = quote(name) if name
|
84
|
-
scope[:type] = type if type
|
85
|
-
scope[:schema] = quote(scope[:schema] || schema)
|
86
|
-
scope
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# @private
|
93
|
-
def self.extended(adapter); initialize!; end
|
94
|
-
|
95
|
-
# @private
|
96
|
-
@@_initialized = nil
|
97
|
-
|
98
|
-
# @private
|
99
|
-
def self.initialize!
|
100
|
-
return if @@_initialized; @@_initialized = true
|
101
|
-
|
102
|
-
require 'arjdbc/util/serialized_attributes'
|
103
|
-
Util::SerializedAttributes.setup /blob|clob/i, 'after_save_with_db2_lob'
|
104
|
-
end
|
105
|
-
|
106
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
107
|
-
def self.jdbc_connection_class
|
108
|
-
::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
|
109
|
-
end
|
110
|
-
|
111
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
112
|
-
def jdbc_column_class
|
113
|
-
::ActiveRecord::ConnectionAdapters::DB2Column
|
114
|
-
end
|
115
|
-
|
116
|
-
# @private
|
117
|
-
@@emulate_booleans = true
|
118
|
-
|
119
|
-
# Boolean emulation can be disabled using :
|
120
|
-
#
|
121
|
-
# ArJdbc::DB2.emulate_booleans = false
|
122
|
-
#
|
123
|
-
def self.emulate_booleans?; @@emulate_booleans; end
|
124
|
-
# @deprecated Use {#emulate_booleans?} instead.
|
125
|
-
def self.emulate_booleans; @@emulate_booleans; end
|
126
|
-
# @see #emulate_booleans?
|
127
|
-
def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
|
128
|
-
|
129
|
-
# @private
|
130
|
-
@@update_lob_values = true
|
131
|
-
|
132
|
-
# Updating records with LOB values (binary/text columns) in a separate
|
133
|
-
# statement can be disabled using :
|
134
|
-
#
|
135
|
-
# ArJdbc::DB2.update_lob_values = false
|
136
|
-
#
|
137
|
-
# @note This only applies when prepared statements are not used.
|
138
|
-
def self.update_lob_values?; @@update_lob_values; end
|
139
|
-
# @see #update_lob_values?
|
140
|
-
def self.update_lob_values=(update); @@update_lob_values = update; end
|
141
|
-
|
142
|
-
# @see #update_lob_values?
|
143
|
-
# @see ArJdbc::Util::SerializedAttributes#update_lob_columns
|
144
|
-
def update_lob_value?(value, column = nil)
|
145
|
-
DB2.update_lob_values? && ! prepared_statements? # && value
|
146
|
-
end
|
147
|
-
|
148
|
-
# @see #quote
|
149
|
-
# @private
|
150
|
-
BLOB_VALUE_MARKER = "BLOB('')"
|
151
|
-
# @see #quote
|
152
|
-
# @private
|
153
|
-
CLOB_VALUE_MARKER = "''"
|
154
|
-
|
155
|
-
def configure_connection
|
156
|
-
schema = self.schema
|
157
|
-
set_schema(schema) if schema && schema != config[:username]
|
158
|
-
end
|
159
|
-
|
160
|
-
ADAPTER_NAME = 'DB2'.freeze
|
161
|
-
|
162
|
-
def adapter_name
|
163
|
-
ADAPTER_NAME
|
164
|
-
end
|
165
|
-
|
166
|
-
NATIVE_DATABASE_TYPES = {
|
167
|
-
:string => { :name => "varchar", :limit => 255 },
|
168
|
-
:integer => { :name => "integer" },
|
169
|
-
:bigint => { :name => 'bigint' },
|
170
|
-
:float => { :name => "real" }, # :limit => 24
|
171
|
-
:double => { :name => "double" }, # :limit => 53
|
172
|
-
:text => { :name => "clob" },
|
173
|
-
:binary => { :name => "blob" },
|
174
|
-
:xml => { :name => "xml" },
|
175
|
-
:decimal => { :name => "decimal" }, # :limit => 31
|
176
|
-
:char => { :name => "char" }, # :limit => 254
|
177
|
-
:date => { :name => "date" },
|
178
|
-
:datetime => { :name => "timestamp" },
|
179
|
-
:timestamp => { :name => "timestamp" },
|
180
|
-
:time => { :name => "time" },
|
181
|
-
:boolean => { :name => "smallint" }, # no native boolean type
|
182
|
-
#:rowid => { :name => "rowid" }, # rowid is a supported datatype on z/OS and i/5
|
183
|
-
#:serial => { :name => "serial" }, # supported datatype on Informix Dynamic Server
|
184
|
-
#:graphic => { :name => "graphic", :limit => 1 }, # :limit => 127
|
185
|
-
}
|
186
|
-
|
187
|
-
# @override
|
188
|
-
def initialize_type_map(m)
|
189
|
-
register_class_with_limit m, %r(boolean)i, ActiveRecord::Type::Boolean
|
190
|
-
register_class_with_limit m, %r(char)i, ActiveRecord::Type::String
|
191
|
-
register_class_with_limit m, %r(binary)i, ActiveRecord::Type::Binary
|
192
|
-
register_class_with_limit m, %r(text)i, ActiveRecord::Type::Text
|
193
|
-
register_class_with_limit m, %r(date)i, ActiveRecord::Type::Date
|
194
|
-
register_class_with_limit m, %r(time)i, ActiveRecord::Type::Time
|
195
|
-
register_class_with_limit m, %r(datetime)i, ActiveRecord::Type::DateTime
|
196
|
-
register_class_with_limit m, %r(float)i, ActiveRecord::Type::Float
|
197
|
-
register_class_with_limit m, %r(int)i, ActiveRecord::Type::Integer
|
198
|
-
|
199
|
-
m.alias_type %r(blob)i, 'binary'
|
200
|
-
m.alias_type %r(clob)i, 'text'
|
201
|
-
m.alias_type %r(timestamp)i, 'datetime'
|
202
|
-
m.alias_type %r(numeric)i, 'decimal'
|
203
|
-
m.alias_type %r(number)i, 'decimal'
|
204
|
-
m.alias_type %r(double)i, 'float'
|
205
|
-
m.alias_type %r(real)i, 'float'
|
206
|
-
|
207
|
-
m.register_type(%r(decimal)i) do |sql_type|
|
208
|
-
scale = extract_scale(sql_type)
|
209
|
-
precision = extract_precision(sql_type)
|
210
|
-
limit = extract_limit(sql_type)
|
211
|
-
if scale == 0
|
212
|
-
ActiveRecord::Type::BigInteger.new(:precision => precision, :limit => limit)
|
213
|
-
else
|
214
|
-
ActiveRecord::Type::Decimal.new(:precision => precision, :scale => scale)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
m.alias_type %r(for bit data)i, 'binary'
|
219
|
-
m.alias_type %r(smallint)i, 'boolean'
|
220
|
-
m.alias_type %r(serial)i, 'int'
|
221
|
-
m.alias_type %r(decfloat)i, 'decimal'
|
222
|
-
#m.alias_type %r(real)i, 'decimal'
|
223
|
-
m.alias_type %r(graphic)i, 'binary'
|
224
|
-
m.alias_type %r(rowid)i, 'int'
|
225
|
-
|
226
|
-
m.register_type(%r(smallint)i) do
|
227
|
-
if DB2.emulate_booleans?
|
228
|
-
ActiveRecord::Type::Boolean.new
|
229
|
-
else
|
230
|
-
ActiveRecord::Type::Integer.new(:limit => 1)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
m.register_type %r(xml)i, XmlType.new
|
235
|
-
end if AR42
|
236
|
-
|
237
|
-
# @private
|
238
|
-
class XmlType < ActiveRecord::Type::String
|
239
|
-
def type; :xml end
|
240
|
-
|
241
|
-
def type_cast_for_database(value)
|
242
|
-
return unless value
|
243
|
-
Data.new(super)
|
244
|
-
end
|
245
|
-
|
246
|
-
class Data
|
247
|
-
def initialize(value)
|
248
|
-
@value = value
|
249
|
-
end
|
250
|
-
def to_s; @value end
|
251
|
-
end
|
252
|
-
end if AR42
|
253
|
-
|
254
|
-
# @override
|
255
|
-
def reset_column_information
|
256
|
-
initialize_type_map(type_map)
|
257
|
-
end if AR42
|
258
|
-
|
259
|
-
# @override
|
260
|
-
def native_database_types
|
261
|
-
# NOTE: currently merging with what JDBC gives us since there's a lot
|
262
|
-
# of DB2-like stuff we could be connecting e.g. "classic", Z/OS etc.
|
263
|
-
# types = super
|
264
|
-
types = super.merge(NATIVE_DATABASE_TYPES)
|
265
|
-
types
|
266
|
-
end
|
267
|
-
|
268
|
-
# @private
|
269
|
-
class TableDefinition < ::ActiveRecord::ConnectionAdapters::TableDefinition
|
270
|
-
|
271
|
-
def xml(*args)
|
272
|
-
options = args.extract_options!
|
273
|
-
column(args[0], 'xml', options)
|
274
|
-
end
|
275
|
-
|
276
|
-
# IBM DB adapter (MRI) compatibility :
|
277
|
-
|
278
|
-
# @private
|
279
|
-
# @deprecated
|
280
|
-
def double(*args)
|
281
|
-
options = args.extract_options!
|
282
|
-
column(args[0], 'double', options)
|
283
|
-
end
|
284
|
-
|
285
|
-
# @private
|
286
|
-
def decfloat(*args)
|
287
|
-
options = args.extract_options!
|
288
|
-
column(args[0], 'decfloat', options)
|
289
|
-
end
|
290
|
-
|
291
|
-
def graphic(*args)
|
292
|
-
options = args.extract_options!
|
293
|
-
column(args[0], 'graphic', options)
|
294
|
-
end
|
295
|
-
|
296
|
-
# @private
|
297
|
-
# @deprecated
|
298
|
-
def vargraphic(*args)
|
299
|
-
options = args.extract_options!
|
300
|
-
column(args[0], 'vargraphic', options)
|
301
|
-
end
|
302
|
-
|
303
|
-
# @private
|
304
|
-
# @deprecated
|
305
|
-
def bigint(*args)
|
306
|
-
options = args.extract_options!
|
307
|
-
column(args[0], 'bigint', options)
|
308
|
-
end
|
309
|
-
|
310
|
-
def char(*args)
|
311
|
-
options = args.extract_options!
|
312
|
-
column(args[0], 'char', options)
|
313
|
-
end
|
314
|
-
# alias_method :character, :char
|
315
|
-
|
316
|
-
end
|
317
|
-
|
318
|
-
def table_definition(*args)
|
319
|
-
new_table_definition(TableDefinition, *args)
|
320
|
-
end
|
321
|
-
|
322
|
-
def prefetch_primary_key?(table_name = nil)
|
323
|
-
# TRUE if the table has no identity column
|
324
|
-
names = table_name.upcase.split(".")
|
325
|
-
sql = "SELECT 1 FROM SYSCAT.COLUMNS WHERE IDENTITY = 'Y' "
|
326
|
-
sql << "AND TABSCHEMA = '#{names.first}' " if names.size == 2
|
327
|
-
sql << "AND TABNAME = '#{names.last}'"
|
328
|
-
select_one(sql).nil?
|
329
|
-
end
|
330
|
-
|
331
|
-
# @override
|
332
|
-
def primary_keys(table)
|
333
|
-
# If no schema in table name is given but present in URL parameter. Use the URL parameter one
|
334
|
-
# This avoids issues if the table is present in multiple schemas
|
335
|
-
if table.split(".").size == 1 && schema
|
336
|
-
table = "#{schema}.#{table}"
|
337
|
-
end
|
338
|
-
|
339
|
-
super
|
340
|
-
end
|
341
|
-
|
342
|
-
def next_sequence_value(sequence_name)
|
343
|
-
select_value("SELECT NEXT VALUE FOR #{sequence_name} FROM sysibm.sysdummy1")
|
344
|
-
end
|
345
|
-
|
346
|
-
def create_table(name, options = {}, &block)
|
347
|
-
if zos?
|
348
|
-
zos_create_table(name, options, &block)
|
349
|
-
else
|
350
|
-
super
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
def zos_create_table(name, options = {})
|
355
|
-
table_definition = new_table_definition TableDefinition, name, options[:temporary], options[:options], options[:as]
|
356
|
-
|
357
|
-
unless options[:id] == false
|
358
|
-
table_definition.primary_key(options[:primary_key] || primary_key(name))
|
359
|
-
end
|
360
|
-
|
361
|
-
yield table_definition if block_given?
|
362
|
-
|
363
|
-
# Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
|
364
|
-
clob_columns = []
|
365
|
-
table_definition.columns.delete_if do |column|
|
366
|
-
if column.type && column.type.to_sym == :text
|
367
|
-
clob_columns << column; true
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
drop_table(name, options) if options[:force] && table_exists?(name)
|
372
|
-
|
373
|
-
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
374
|
-
create_sql << "#{quote_table_name(name)} ("
|
375
|
-
create_sql << table_definition.to_sql
|
376
|
-
create_sql << ") #{options[:options]}"
|
377
|
-
if @config[:database] && @config[:tablespace]
|
378
|
-
create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}"
|
379
|
-
end
|
380
|
-
|
381
|
-
execute create_sql
|
382
|
-
|
383
|
-
# Table definition is complete only when a unique index is created on the primary_key column for DB2 V8 on zOS
|
384
|
-
# create index on id column if options[:id] is nil or id ==true
|
385
|
-
# else check if options[:primary_key]is not nil then create an unique index on that column
|
386
|
-
# TODO someone on Z/OS should test this out - also not needed for V9 ?
|
387
|
-
#primary_column = options[:id] == true ? 'id' : options[:primary_key]
|
388
|
-
#add_index(name, (primary_column || 'id').to_s, :unique => true)
|
389
|
-
|
390
|
-
clob_columns.each do |clob_column|
|
391
|
-
column_name = clob_column.name.to_s
|
392
|
-
execute "ALTER TABLE #{name} ADD COLUMN #{column_name} clob"
|
393
|
-
clob_table_name = "#{name}_#{column_name}_CD_"
|
394
|
-
if @config[:database] && @config[:lob_tablespaces]
|
395
|
-
in_lob_table_space = " IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]}"
|
396
|
-
end
|
397
|
-
execute "CREATE AUXILIARY TABLE #{clob_table_name} #{in_lob_table_space} STORES #{name} COLUMN #{column_name}"
|
398
|
-
execute "CREATE UNIQUE INDEX #{clob_table_name} ON #{clob_table_name};"
|
399
|
-
end
|
400
|
-
end
|
401
|
-
private :zos_create_table
|
402
|
-
|
403
|
-
def pk_and_sequence_for(table)
|
404
|
-
# In JDBC/DB2 side, only upcase names of table and column are handled.
|
405
|
-
keys = super(table.upcase)
|
406
|
-
if keys && keys[0]
|
407
|
-
# In ActiveRecord side, only downcase names of table and column are handled.
|
408
|
-
keys[0] = keys[0].downcase
|
409
|
-
end
|
410
|
-
keys
|
411
|
-
end
|
412
|
-
|
413
|
-
# Properly quotes the various data types.
|
414
|
-
# @param value contains the data
|
415
|
-
# @override
|
416
|
-
def quote(value)
|
417
|
-
return value if sql_literal?(value)
|
418
|
-
super
|
419
|
-
end
|
420
|
-
|
421
|
-
# @override
|
422
|
-
def quoted_date(value)
|
423
|
-
if value.acts_like?(:time) && value.respond_to?(:usec)
|
424
|
-
usec = sprintf("%06d", value.usec)
|
425
|
-
value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
|
426
|
-
"#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
|
427
|
-
else
|
428
|
-
super
|
429
|
-
end
|
430
|
-
end if ::ActiveRecord::VERSION::MAJOR >= 3
|
431
|
-
|
432
|
-
def quote_time(value)
|
433
|
-
value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
|
434
|
-
# AS400 doesn't support date in time column
|
435
|
-
"'#{value.strftime("%H:%M:%S")}'"
|
436
|
-
end
|
437
|
-
|
438
|
-
def quote_column_name(column_name)
|
439
|
-
column_name.to_s
|
440
|
-
end
|
441
|
-
|
442
|
-
def modify_types(types)
|
443
|
-
super(types)
|
444
|
-
types[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
|
445
|
-
types[:string][:limit] = 255
|
446
|
-
types[:integer][:limit] = nil
|
447
|
-
types[:boolean] = {:name => "decimal(1)"}
|
448
|
-
types
|
449
|
-
end
|
450
|
-
|
451
|
-
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
452
|
-
limit = nil if type.to_sym == :integer
|
453
|
-
super
|
454
|
-
end
|
455
|
-
|
456
|
-
# @private
|
457
|
-
VALUES_DEFAULT = 'VALUES ( DEFAULT )' # NOTE: Arel::Visitors::DB2 uses this
|
458
|
-
|
459
|
-
# @override
|
460
|
-
def empty_insert_statement_value
|
461
|
-
VALUES_DEFAULT # won't work as DB2 needs to know the column count
|
462
|
-
end
|
463
|
-
|
464
|
-
def add_column(table_name, column_name, type, options = {})
|
465
|
-
# The keyword COLUMN allows to use reserved names for columns (ex: date)
|
466
|
-
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options)}"
|
467
|
-
add_column_options!(add_column_sql, options)
|
468
|
-
execute(add_column_sql)
|
469
|
-
end
|
470
|
-
|
471
|
-
def add_column_options!(sql, options)
|
472
|
-
# handle case of defaults for CLOB columns,
|
473
|
-
# which might get incorrect if we write LOBs in the after_save callback
|
474
|
-
if options_include_default?(options)
|
475
|
-
column = options[:column]
|
476
|
-
if column && column.type == :text
|
477
|
-
sql << " DEFAULT #{quote(options.delete(:default))}"
|
478
|
-
end
|
479
|
-
if column && column.type == :binary
|
480
|
-
# quoting required for the default value of a column :
|
481
|
-
value = options.delete(:default)
|
482
|
-
# DB2 z/OS only allows NULL or "" (empty) string as DEFAULT value
|
483
|
-
# for a BLOB column. non-empty string and non-NULL, return error!
|
484
|
-
if value.nil?
|
485
|
-
sql_value = "NULL"
|
486
|
-
else
|
487
|
-
sql_value = zos? ? "#{value}" : "BLOB('#{quote_string(value)}'"
|
488
|
-
end
|
489
|
-
sql << " DEFAULT #{sql_value}"
|
490
|
-
end
|
491
|
-
end
|
492
|
-
super
|
493
|
-
end
|
494
|
-
|
495
|
-
# @note Only used with (non-AREL) ActiveRecord **2.3**.
|
496
|
-
# @see Arel::Visitors::DB2
|
497
|
-
def add_limit_offset!(sql, options)
|
498
|
-
limit = options[:limit]
|
499
|
-
replace_limit_offset!(sql, limit, options[:offset]) if limit
|
500
|
-
end if ::ActiveRecord::VERSION::MAJOR < 3
|
501
|
-
|
502
|
-
# @private shared with {Arel::Visitors::DB2}
|
503
|
-
def replace_limit_offset!(sql, limit, offset, orders = nil)
|
504
|
-
limit = limit.to_i
|
505
|
-
|
506
|
-
if offset # && limit
|
507
|
-
over_order_by = nil # NOTE: orders matching got reverted as it was not complete and there were no case covering it ...
|
508
|
-
|
509
|
-
start_sql = "SELECT B.* FROM (SELECT A.*, row_number() OVER (#{over_order_by}) AS internal$rownum FROM (SELECT"
|
510
|
-
end_sql = ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset.to_i}"
|
511
|
-
|
512
|
-
if sql.is_a?(String)
|
513
|
-
sql.sub!(/SELECT/i, start_sql)
|
514
|
-
sql << end_sql
|
515
|
-
else # AR 4.2 sql.class ... Arel::Collectors::Bind
|
516
|
-
sql.parts[0] = start_sql # sql.sub! /SELECT/i
|
517
|
-
sql.parts[ sql.parts.length ] = end_sql
|
518
|
-
end
|
519
|
-
else
|
520
|
-
limit_sql = limit == 1 ? " FETCH FIRST ROW ONLY" : " FETCH FIRST #{limit} ROWS ONLY"
|
521
|
-
if sql.is_a?(String)
|
522
|
-
sql << limit_sql
|
523
|
-
else # AR 4.2 sql.class ... Arel::Collectors::Bind
|
524
|
-
sql.parts[ sql.parts.length ] = limit_sql
|
525
|
-
end
|
526
|
-
end
|
527
|
-
sql
|
528
|
-
end
|
529
|
-
|
530
|
-
# @deprecated seems not sued nor tested ?!
|
531
|
-
def runstats_for_table(tablename, priority = 10)
|
532
|
-
@connection.execute_update "call sysproc.admin_cmd('RUNSTATS ON TABLE #{tablename} WITH DISTRIBUTION AND DETAILED INDEXES ALL UTIL_IMPACT_PRIORITY #{priority}')"
|
533
|
-
end
|
534
|
-
|
535
|
-
if ::ActiveRecord::VERSION::MAJOR >= 4
|
536
|
-
|
537
|
-
def select(sql, name = nil, binds = [])
|
538
|
-
exec_query(to_sql(suble_null_test(sql), binds), name, binds)
|
539
|
-
end
|
540
|
-
|
541
|
-
else
|
542
|
-
|
543
|
-
def select(sql, name = nil, binds = [])
|
544
|
-
exec_query_raw(to_sql(suble_null_test(sql), binds), name, binds)
|
545
|
-
end
|
546
|
-
|
547
|
-
end
|
548
|
-
|
549
|
-
# @private
|
550
|
-
IS_NOT_NULL = /(!=|<>)\s*NULL/i
|
551
|
-
# @private
|
552
|
-
IS_NULL = /=\s*NULL/i
|
553
|
-
|
554
|
-
def suble_null_test(sql)
|
555
|
-
return sql unless sql.is_a?(String)
|
556
|
-
# DB2 does not like "= NULL", "!= NULL", or "<> NULL" :
|
557
|
-
sql = sql.dup
|
558
|
-
sql.gsub! IS_NOT_NULL, 'IS NOT NULL'
|
559
|
-
sql.gsub! IS_NULL, 'IS NULL'
|
560
|
-
sql
|
561
|
-
end
|
562
|
-
private :suble_null_test
|
563
|
-
|
564
|
-
def add_index(table_name, column_name, options = {})
|
565
|
-
if ! zos? || ( table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s )
|
566
|
-
column_name = column_name.to_s if column_name.is_a?(Symbol)
|
567
|
-
super
|
568
|
-
else
|
569
|
-
statement = 'CREATE'
|
570
|
-
statement << ' UNIQUE ' if options[:unique]
|
571
|
-
statement << " INDEX #{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
|
572
|
-
statement << " ON #{table_name}(#{column_name})"
|
573
|
-
|
574
|
-
execute statement
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
# @override
|
579
|
-
def remove_index!(table_name, index_name)
|
580
|
-
execute "DROP INDEX #{quote_column_name(index_name)}"
|
581
|
-
end
|
582
|
-
|
583
|
-
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
|
584
|
-
# ...not supported on IBM i, so we raise in this case
|
585
|
-
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
586
|
-
sql = "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
|
587
|
-
execute_table_change(sql, table_name, 'Rename Column')
|
588
|
-
end
|
589
|
-
|
590
|
-
def change_column_null(table_name, column_name, null)
|
591
|
-
if null
|
592
|
-
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
|
593
|
-
else
|
594
|
-
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
|
595
|
-
end
|
596
|
-
execute_table_change(sql, table_name, 'Change Column')
|
597
|
-
end
|
598
|
-
|
599
|
-
def change_column_default(table_name, column_name, default)
|
600
|
-
if default.nil?
|
601
|
-
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
|
602
|
-
else
|
603
|
-
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
|
604
|
-
end
|
605
|
-
execute_table_change(sql, table_name, 'Change Column')
|
606
|
-
end
|
607
|
-
|
608
|
-
def change_column(table_name, column_name, type, options = {})
|
609
|
-
data_type = type_to_sql(type, options)
|
610
|
-
sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
|
611
|
-
execute_table_change(sql, table_name, 'Change Column')
|
612
|
-
|
613
|
-
if options.include?(:default) and options.include?(:null)
|
614
|
-
# which to run first?
|
615
|
-
if options[:null] or options[:default].nil?
|
616
|
-
change_column_null(table_name, column_name, options[:null])
|
617
|
-
change_column_default(table_name, column_name, options[:default])
|
618
|
-
else
|
619
|
-
change_column_default(table_name, column_name, options[:default])
|
620
|
-
change_column_null(table_name, column_name, options[:null])
|
621
|
-
end
|
622
|
-
elsif options.include?(:default)
|
623
|
-
change_column_default(table_name, column_name, options[:default])
|
624
|
-
elsif options.include?(:null)
|
625
|
-
change_column_null(table_name, column_name, options[:null])
|
626
|
-
end
|
627
|
-
end
|
628
|
-
|
629
|
-
if ActiveRecord::VERSION::MAJOR >= 4
|
630
|
-
|
631
|
-
def remove_column(table_name, column_name, type = nil, options = {})
|
632
|
-
db2_remove_column(table_name, column_name)
|
633
|
-
end
|
634
|
-
|
635
|
-
else
|
636
|
-
|
637
|
-
def remove_column(table_name, *column_names)
|
638
|
-
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
|
639
|
-
outcome = nil
|
640
|
-
column_names = column_names.flatten
|
641
|
-
for column_name in column_names
|
642
|
-
outcome = db2_remove_column(table_name, column_name)
|
643
|
-
end
|
644
|
-
column_names.size == 1 ? outcome : nil
|
645
|
-
end
|
646
|
-
|
647
|
-
end
|
648
|
-
|
649
|
-
def rename_table(name, new_name)
|
650
|
-
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
|
651
|
-
execute_table_change("RENAME TABLE #{name} TO #{new_name}", new_name, 'Rename Table')
|
652
|
-
end
|
653
|
-
|
654
|
-
def tables
|
655
|
-
@connection.tables(nil, schema)
|
656
|
-
end
|
657
|
-
|
658
|
-
# only record precision and scale for types that can set them via CREATE TABLE:
|
659
|
-
# http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
|
660
|
-
|
661
|
-
HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) # TIMESTAMP
|
662
|
-
HAVE_PRECISION = %w(DECIMAL NUMERIC)
|
663
|
-
HAVE_SCALE = %w(DECIMAL NUMERIC)
|
664
|
-
|
665
|
-
def columns(table_name, name = nil)
|
666
|
-
columns = @connection.columns_internal(table_name.to_s, nil, schema) # catalog == nil
|
667
|
-
|
668
|
-
if zos?
|
669
|
-
# Remove the mighty db2_generated_rowid_for_lobs from the list of columns
|
670
|
-
columns = columns.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
|
671
|
-
end
|
672
|
-
# scrub out sizing info when CREATE TABLE doesn't support it
|
673
|
-
# but JDBC reports it (doh!)
|
674
|
-
for column in columns
|
675
|
-
base_sql_type = column.sql_type.sub(/\(.*/, "").upcase
|
676
|
-
column.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
|
677
|
-
column.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
|
678
|
-
#column.scale = nil unless HAVE_SCALE.include?(base_sql_type)
|
679
|
-
end
|
680
|
-
|
681
|
-
columns
|
682
|
-
end
|
683
|
-
|
684
|
-
def indexes(table_name, name = nil)
|
685
|
-
@connection.indexes(table_name, name, schema)
|
686
|
-
end
|
687
|
-
|
688
|
-
def recreate_database(name = nil, options = {})
|
689
|
-
drop_database(name)
|
690
|
-
end
|
691
|
-
|
692
|
-
def drop_database(name = nil)
|
693
|
-
tables.each { |table| drop_table("#{table}") }
|
694
|
-
end
|
695
|
-
|
696
|
-
def truncate(table_name, name = nil)
|
697
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)} IMMEDIATE", name
|
698
|
-
end
|
699
|
-
|
700
|
-
# @override
|
701
|
-
def supports_views?; true end
|
702
|
-
|
703
|
-
def execute_table_change(sql, table_name, name = nil)
|
704
|
-
outcome = execute(sql, name)
|
705
|
-
reorg_table(table_name, name)
|
706
|
-
outcome
|
707
|
-
end
|
708
|
-
protected :execute_table_change
|
709
|
-
|
710
|
-
def reorg_table(table_name, name = nil)
|
711
|
-
exec_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')", name, []
|
712
|
-
end
|
713
|
-
private :reorg_table
|
714
|
-
|
715
|
-
# alias_method :execute_and_auto_confirm, :execute
|
716
|
-
|
717
|
-
# Returns the value of an identity column of the last *INSERT* statement made over this connection.
|
718
|
-
# @note Check the *IDENTITY_VAL_LOCAL* function for documentation.
|
719
|
-
# @return [Integer, NilClass]
|
720
|
-
def last_inserted_id(result)
|
721
|
-
@connection.identity_val_local
|
722
|
-
end
|
723
|
-
|
724
|
-
# NOTE: only setup query analysis on AR <= 3.0 since on 3.1 {#exec_query},
|
725
|
-
# {#exec_insert} will be used for AR generated queries/inserts etc.
|
726
|
-
# Also there's prepared statement support and {#execute} is meant to stay
|
727
|
-
# as a way of running non-prepared SQL statements (returning raw results).
|
728
|
-
if ActiveRecord::VERSION::MAJOR < 3 ||
|
729
|
-
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
|
730
|
-
|
731
|
-
def _execute(sql, name = nil)
|
732
|
-
if self.class.select?(sql)
|
733
|
-
@connection.execute_query_raw(sql)
|
734
|
-
elsif self.class.insert?(sql)
|
735
|
-
@connection.execute_insert(sql) || last_insert_id
|
736
|
-
else
|
737
|
-
@connection.execute_update(sql)
|
738
|
-
end
|
739
|
-
end
|
740
|
-
private :_execute
|
741
|
-
|
742
|
-
end
|
743
|
-
|
744
|
-
DRIVER_NAME = 'com.ibm.db2.jcc.DB2Driver'.freeze
|
745
|
-
|
746
|
-
# @private
|
747
|
-
def zos?
|
748
|
-
@zos = nil unless defined? @zos
|
749
|
-
return @zos unless @zos.nil?
|
750
|
-
@zos =
|
751
|
-
if url = config[:url]
|
752
|
-
!!( url =~ /^jdbc:db2j:net:/ && config[:driver] == DRIVER_NAME )
|
753
|
-
else
|
754
|
-
nil
|
755
|
-
end
|
756
|
-
end
|
757
|
-
|
758
|
-
# @private
|
759
|
-
# @deprecated no longer used
|
760
|
-
def as400?
|
761
|
-
false
|
762
|
-
end
|
763
|
-
|
764
|
-
def schema
|
765
|
-
db2_schema
|
766
|
-
end
|
767
|
-
|
768
|
-
def schema=(schema)
|
769
|
-
set_schema(@db2_schema = schema) if db2_schema != schema
|
770
|
-
end
|
771
|
-
|
772
|
-
private
|
773
|
-
|
774
|
-
def set_schema(schema)
|
775
|
-
execute("SET SCHEMA #{schema}")
|
776
|
-
end
|
777
|
-
|
778
|
-
def db2_schema
|
779
|
-
@db2_schema = false unless defined? @db2_schema
|
780
|
-
return @db2_schema if @db2_schema != false
|
781
|
-
schema = config[:schema]
|
782
|
-
@db2_schema =
|
783
|
-
if schema then schema
|
784
|
-
elsif config[:jndi] || config[:data_source]
|
785
|
-
nil # let JNDI worry about schema
|
786
|
-
else
|
787
|
-
# LUW implementation uses schema name of username by default
|
788
|
-
config[:username] || ENV['USER']
|
789
|
-
end
|
790
|
-
end
|
791
|
-
|
792
|
-
def db2_remove_column(table_name, column_name)
|
793
|
-
sql = "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
|
794
|
-
execute_table_change(sql, table_name, 'Remove Column')
|
795
|
-
end
|
796
|
-
|
797
|
-
end
|
798
|
-
end
|
799
|
-
|
800
|
-
module ActiveRecord::ConnectionAdapters
|
801
|
-
|
802
|
-
remove_const(:DB2Column) if const_defined?(:DB2Column)
|
803
|
-
|
804
|
-
class DB2Column < JdbcColumn
|
805
|
-
include ::ArJdbc::DB2::Column
|
806
|
-
end
|
807
|
-
|
808
|
-
end
|