activerecord-jdbc-adapter 1.3.13 → 1.3.14

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.
@@ -187,28 +187,30 @@ module ArJdbc
187
187
  select_value("SELECT NEXT VALUE FOR #{sequence_name} FROM sysibm.sysdummy1")
188
188
  end
189
189
 
190
- def create_table(name, options = {})
190
+ def create_table(name, options = {}, &block)
191
191
  if zos?
192
- zos_create_table(name, options)
192
+ zos_create_table(name, options, &block)
193
193
  else
194
- super(name, options)
194
+ super
195
195
  end
196
196
  end
197
197
 
198
198
  def zos_create_table(name, options = {})
199
- # NOTE: this won't work for 4.0 - need to pass different initialize args :
200
- table_definition = TableDefinition.new(self)
199
+ table_definition = new_table_definition TableDefinition, name, options[:temporary], options[:options], options[:as]
200
+
201
201
  unless options[:id] == false
202
202
  table_definition.primary_key(options[:primary_key] || primary_key(name))
203
203
  end
204
204
 
205
- yield table_definition
205
+ yield table_definition if block_given?
206
206
 
207
207
  # Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
208
- # First: Save them for later in Array "clobs"
209
- clobs = table_definition.columns.select { |x| x.type.to_s == "text" }
210
- # Second: and delete them from the original Colums-Array
211
- table_definition.columns.delete_if { |x| x.type.to_s == "text" }
208
+ clob_columns = []
209
+ table_definition.columns.delete_if do |column|
210
+ if column.type && column.type.to_sym == :text
211
+ clob_columns << column; true
212
+ end
213
+ end
212
214
 
213
215
  drop_table(name, options) if options[:force] && table_exists?(name)
214
216
 
@@ -217,11 +219,8 @@ module ArJdbc
217
219
  create_sql << table_definition.to_sql
218
220
  create_sql << ") #{options[:options]}"
219
221
  if @config[:database] && @config[:tablespace]
220
- in_db_table_space = " IN #{@config[:database]}.#{@config[:tablespace]}"
221
- else
222
- in_db_table_space = ''
222
+ create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}"
223
223
  end
224
- create_sql << in_db_table_space
225
224
 
226
225
  execute create_sql
227
226
 
@@ -232,14 +231,12 @@ module ArJdbc
232
231
  #primary_column = options[:id] == true ? 'id' : options[:primary_key]
233
232
  #add_index(name, (primary_column || 'id').to_s, :unique => true)
234
233
 
235
- clobs.each do |clob_column|
234
+ clob_columns.each do |clob_column|
236
235
  column_name = clob_column.name.to_s
237
- execute "ALTER TABLE #{name + ' ADD COLUMN ' + column_name + ' clob'}"
238
- clob_table_name = name + '_' + column_name + '_CD_'
236
+ execute "ALTER TABLE #{name} ADD COLUMN #{column_name} clob"
237
+ clob_table_name = "#{name}_#{column_name}_CD_"
239
238
  if @config[:database] && @config[:lob_tablespaces]
240
239
  in_lob_table_space = " IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]}"
241
- else
242
- in_lob_table_space = ''
243
240
  end
244
241
  execute "CREATE AUXILIARY TABLE #{clob_table_name} #{in_lob_table_space} STORES #{name} COLUMN #{column_name}"
245
242
  execute "CREATE UNIQUE INDEX #{clob_table_name} ON #{clob_table_name};"
@@ -350,6 +347,14 @@ module ArJdbc
350
347
  super(type, limit, precision, scale)
351
348
  end
352
349
 
350
+ # @private
351
+ VALUES_DEFAULT = 'VALUES ( DEFAULT )' # NOTE: Arel::Visitors::DB2 uses this
352
+
353
+ # @override
354
+ def empty_insert_statement_value
355
+ VALUES_DEFAULT # won't work as DB2 needs to know the column count
356
+ end
357
+
353
358
  def add_column(table_name, column_name, type, options = {})
354
359
  # The keyword COLUMN allows to use reserved names for columns (ex: date)
355
360
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
@@ -393,7 +398,7 @@ module ArJdbc
393
398
 
394
399
  limit = limit.to_i
395
400
  if offset
396
- replace_limit_offset_with_ordering(sql, limit, offset)
401
+ replace_limit_offset_with_ordering!(sql, limit, offset)
397
402
  else
398
403
  if limit == 1
399
404
  sql << " FETCH FIRST ROW ONLY"
@@ -404,42 +409,48 @@ module ArJdbc
404
409
  end
405
410
  end
406
411
 
407
- # @private only used from {Arel::Visitors::DB2}
408
- def replace_limit_offset_for_arel!( query, sql )
409
- replace_limit_offset_with_ordering sql, query.limit.value, query.offset && query.offset.value, query.orders
410
- end
411
-
412
- def replace_limit_offset_with_ordering( sql, limit, offset, orders=[] )
413
- sql.sub!(/SELECT/i, "SELECT B.* FROM (SELECT A.*, row_number() over (#{build_ordering(orders)}) AS internal$rownum FROM (SELECT")
412
+ # @private used from {Arel::Visitors::DB2}
413
+ def replace_limit_offset_with_ordering!(sql, limit, offset, orders = nil)
414
+ over_order_by = nil # NOTE: orders matching got reverted as it was not complete and there were no case covering it ...
415
+ sql.sub!(/SELECT/i, "SELECT B.* FROM (SELECT A.*, row_number() OVER (#{over_order_by}) AS internal$rownum FROM (SELECT")
414
416
  sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
415
417
  sql
416
418
  end
417
- private :replace_limit_offset_with_ordering
418
-
419
- def build_ordering( orders )
420
- return '' unless orders.size > 0
421
- # need to remove the library/table names from the orderings because we are not really ordering by them anymore
422
- # we are actually ordering by the results of a query where the result set has the same column names
423
- orders = orders.map do |o|
424
- # need to keep in mind that the order clause could be wrapped in a function
425
- matches = /(?:\w+\(|\s)*(\S+)(?:\)|\s)*/.match(o)
426
- o = o.gsub( matches[1], matches[1].split('.').last ) if matches
427
- o
428
- end
429
- "ORDER BY " + orders.join( ', ')
430
- end
431
- private :build_ordering
432
419
 
433
420
  # @deprecated seems not sued nor tested ?!
434
421
  def runstats_for_table(tablename, priority = 10)
435
422
  @connection.execute_update "call sysproc.admin_cmd('RUNSTATS ON TABLE #{tablename} WITH DISTRIBUTION AND DETAILED INDEXES ALL UTIL_IMPACT_PRIORITY #{priority}')"
436
423
  end
437
424
 
438
- def select(sql, name, binds)
439
- # DB2 does not like "= NULL", "!= NULL", or "<> NULL".
440
- exec_query(to_sql(sql.gsub(/(!=|<>)\s*null/i, "IS NOT NULL").gsub(/=\s*null/i, "IS NULL"), binds), name, binds)
425
+ if ::ActiveRecord::VERSION::MAJOR >= 4
426
+
427
+ def select(sql, name = nil, binds = [])
428
+ exec_query(to_sql(suble_null_test(sql), binds), name, binds)
429
+ end
430
+
431
+ else
432
+
433
+ def select(sql, name = nil, binds = [])
434
+ exec_query_raw(to_sql(suble_null_test(sql), binds), name, binds)
435
+ end
436
+
441
437
  end
442
438
 
439
+ # @private
440
+ IS_NOT_NULL = /(!=|<>)\s*NULL/i
441
+ # @private
442
+ IS_NULL = /=\s*NULL/i
443
+
444
+ def suble_null_test(sql)
445
+ return sql unless sql.is_a?(String)
446
+ # DB2 does not like "= NULL", "!= NULL", or "<> NULL" :
447
+ sql = sql.dup
448
+ sql.gsub! IS_NOT_NULL, 'IS NOT NULL'
449
+ sql.gsub! IS_NULL, 'IS NULL'
450
+ sql
451
+ end
452
+ private :suble_null_test
453
+
443
454
  def add_index(table_name, column_name, options = {})
444
455
  if ! zos? || ( table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s )
445
456
  column_name = column_name.to_s if column_name.is_a?(Symbol)
@@ -654,14 +665,14 @@ module ArJdbc
654
665
  def db2_schema
655
666
  @db2_schema = false unless defined? @db2_schema
656
667
  return @db2_schema if @db2_schema != false
668
+ schema = config[:schema]
657
669
  @db2_schema =
658
- if config[:schema].present?
659
- config[:schema]
660
- elsif config[:jndi].present?
670
+ if schema then schema
671
+ elsif config[:jndi] || config[:data_source]
661
672
  nil # let JNDI worry about schema
662
673
  else
663
674
  # LUW implementation uses schema name of username by default
664
- config[:username].presence || ENV['USER']
675
+ config[:username] || ENV['USER']
665
676
  end
666
677
  end
667
678
 
@@ -681,4 +692,4 @@ module ActiveRecord::ConnectionAdapters
681
692
  include ::ArJdbc::DB2::Column
682
693
  end
683
694
 
684
- end
695
+ end
@@ -248,7 +248,7 @@ module ArJdbc
248
248
 
249
249
  # @override
250
250
  def empty_insert_statement_value
251
- 'VALUES ( DEFAULT )' # won't work as Derby does need to know the columns count
251
+ ::Arel::Visitors::Derby::VALUES_DEFAULT # Derby needs to know the columns
252
252
  end
253
253
 
254
254
  # Set the sequence to the max value of the table's column.
@@ -104,9 +104,10 @@ module ActiveRecord::ConnectionAdapters
104
104
  return nil unless time
105
105
 
106
106
  time -= offset
107
- Base.default_timezone == :utc ? time : time.getlocal
107
+ ActiveRecord::Base.default_timezone == :utc ? time : time.getlocal
108
108
  else
109
- Time.public_send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
109
+ timezone = ActiveRecord::Base.default_timezone
110
+ Time.public_send(timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
110
111
  end
111
112
  end
112
113
 
@@ -390,6 +390,76 @@ module ArJdbc
390
390
  columns
391
391
  end
392
392
 
393
+ if defined? ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
394
+
395
+ class SchemaCreation < ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
396
+
397
+ # @private
398
+ def visit_AddColumn(o)
399
+ add_column_position!(super, column_options(o))
400
+ end
401
+
402
+ # @private re-defined since AR 4.1
403
+ def visit_ChangeColumnDefinition(o)
404
+ column = o.column
405
+ options = o.options
406
+ sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale])
407
+ change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}"
408
+ add_column_options!(change_column_sql, options.merge(:column => column))
409
+ add_column_position!(change_column_sql, options)
410
+ end
411
+
412
+ # @private since AR 4.2
413
+ def visit_DropForeignKey(name)
414
+ "DROP FOREIGN KEY #{name}"
415
+ end
416
+
417
+ # @private since AR 4.2
418
+ def visit_TableDefinition(o)
419
+ name = o.name
420
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} "
421
+
422
+ statements = o.columns.map { |c| accept c }
423
+ statements.concat(o.indexes.map { |column_name, options| index_in_create(name, column_name, options) })
424
+
425
+ create_sql << "(#{statements.join(', ')}) " if statements.present?
426
+ create_sql << "#{o.options}"
427
+ create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
428
+ create_sql
429
+ end if AR42
430
+
431
+ private
432
+
433
+ def add_column_position!(sql, options)
434
+ if options[:first]
435
+ sql << " FIRST"
436
+ elsif options[:after]
437
+ sql << " AFTER #{quote_column_name(options[:after])}"
438
+ end
439
+ sql
440
+ end
441
+
442
+ def column_options(o)
443
+ column_options = {}
444
+ column_options[:null] = o.null unless o.null.nil?
445
+ column_options[:default] = o.default unless o.default.nil?
446
+ column_options[:column] = o
447
+ column_options[:first] = o.first
448
+ column_options[:after] = o.after
449
+ column_options
450
+ end
451
+
452
+ def index_in_create(table_name, column_name, options)
453
+ index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options)
454
+ "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}"
455
+ end
456
+
457
+ end
458
+
459
+ def schema_creation; SchemaCreation.new self end
460
+
461
+ end
462
+
393
463
  # @private
394
464
  def recreate_database(name, options = {})
395
465
  drop_database(name)
@@ -417,7 +487,7 @@ module ArJdbc
417
487
 
418
488
  # @override
419
489
  def create_table(name, options = {})
420
- super(name, {:options => "ENGINE=InnoDB DEFAULT CHARSET=utf8"}.merge(options))
490
+ super(name, { :options => "ENGINE=InnoDB" }.merge(options))
421
491
  end
422
492
 
423
493
  def drop_table(table_name, options = {})
@@ -572,7 +642,7 @@ module ArJdbc
572
642
  when 0..0xfff; "varbinary(#{limit})"
573
643
  when nil; "blob"
574
644
  when 0x1000..0xffffffff; "blob(#{limit})"
575
- else raise(ActiveRecordError, "No binary type has character length #{limit}")
645
+ else raise ActiveRecord::ActiveRecordError, "No binary type has character length #{limit}"
576
646
  end
577
647
  when 'integer'
578
648
  case limit
@@ -581,7 +651,7 @@ module ArJdbc
581
651
  when 3; 'mediumint'
582
652
  when nil, 4, 11; 'int(11)' # compatibility with MySQL default
583
653
  when 5..8; 'bigint'
584
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
654
+ else raise ActiveRecord::ActiveRecordError, "No integer type has byte size #{limit}"
585
655
  end
586
656
  when 'text'
587
657
  case limit
@@ -589,7 +659,7 @@ module ArJdbc
589
659
  when nil, 0x100..0xffff; 'text'
590
660
  when 0x10000..0xffffff; 'mediumtext'
591
661
  when 0x1000000..0xffffffff; 'longtext'
592
- else raise(ActiveRecordError, "No text type has character length #{limit}")
662
+ else raise ActiveRecord::ActiveRecordError, "No text type has character length #{limit}"
593
663
  end
594
664
  else
595
665
  super
@@ -602,6 +672,7 @@ module ArJdbc
602
672
  end
603
673
 
604
674
  protected
675
+
605
676
  def quoted_columns_for_index(column_names, options = {})
606
677
  length = options[:length] if options.is_a?(Hash)
607
678
 
@@ -2,10 +2,14 @@ module ArJdbc
2
2
  module MySQL
3
3
  module BulkChangeTable
4
4
 
5
+ # @private
6
+ AR41 = ActiveRecord::VERSION::STRING >= '4.1'
7
+
8
+ # @private
9
+ ChangeColumnDefinition = ActiveRecord::ConnectionAdapters::ChangeColumnDefinition if AR41
10
+
5
11
  # @override
6
- def supports_bulk_alter?
7
- true
8
- end
12
+ def supports_bulk_alter?; true end
9
13
 
10
14
  def bulk_change_table(table_name, operations)
11
15
  sqls = operations.map do |command, args|
@@ -30,7 +34,13 @@ module ArJdbc
30
34
  add_column_options!(add_column_sql, options)
31
35
  add_column_position!(add_column_sql, options)
32
36
  add_column_sql
33
- end
37
+ end unless AR41
38
+
39
+ def add_column_sql(table_name, column_name, type, options = {})
40
+ td = create_table_definition table_name, options[:temporary], options[:options]
41
+ cd = td.new_column_definition(column_name, type, options)
42
+ schema_creation.visit_AddColumn cd
43
+ end if AR41
34
44
 
35
45
  def change_column_sql(table_name, column_name, type, options = {})
36
46
  column = column_for(table_name, column_name)
@@ -47,7 +57,22 @@ module ArJdbc
47
57
  add_column_options!(change_column_sql, options)
48
58
  add_column_position!(change_column_sql, options)
49
59
  change_column_sql
50
- end
60
+ end unless AR41
61
+
62
+ def change_column_sql(table_name, column_name, type, options = {})
63
+ column = column_for(table_name, column_name)
64
+
65
+ unless options_include_default?(options)
66
+ options[:default] = column.default
67
+ end
68
+
69
+ unless options.has_key?(:null)
70
+ options[:null] = column.null
71
+ end
72
+
73
+ options[:name] = column.name
74
+ schema_creation.accept ChangeColumnDefinition.new column, type, options
75
+ end if AR41
51
76
 
52
77
  def rename_column_sql(table_name, column_name, new_column_name)
53
78
  options = {}
@@ -64,7 +89,22 @@ module ArJdbc
64
89
  rename_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
65
90
  add_column_options!(rename_column_sql, options)
66
91
  rename_column_sql
67
- end
92
+ end unless AR41
93
+
94
+ def rename_column_sql(table_name, column_name, new_column_name)
95
+ options = { :name => new_column_name }
96
+
97
+ if column = columns(table_name).find { |c| c.name == column_name.to_s }
98
+ options[:default] = column.default
99
+ options[:null] = column.null
100
+ options[:auto_increment] = (column.extra == "auto_increment")
101
+ else
102
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
103
+ end
104
+
105
+ current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
106
+ schema_creation.accept ChangeColumnDefinition.new column, current_type, options
107
+ end if AR41
68
108
 
69
109
  def remove_column_sql(table_name, column_name, type = nil, options = {})
70
110
  "DROP #{quote_column_name(column_name)}"
@@ -84,8 +124,8 @@ module ArJdbc
84
124
  "DROP INDEX #{index_name}"
85
125
  end
86
126
 
87
- def add_timestamps_sql(table_name)
88
- [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)]
127
+ def add_timestamps_sql(table_name, options = {})
128
+ [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
89
129
  end
90
130
 
91
131
  def remove_timestamps_sql(table_name)
@@ -140,6 +140,7 @@ module ArJdbc
140
140
  def table_name_length; IDENTIFIER_LENGTH; end
141
141
  def index_name_length; IDENTIFIER_LENGTH; end
142
142
  def column_name_length; IDENTIFIER_LENGTH; end
143
+ def sequence_name_length; IDENTIFIER_LENGTH end
143
144
 
144
145
  def default_sequence_name(table_name, column = nil)
145
146
  # TODO: remove schema prefix if present (before truncating)
@@ -17,7 +17,7 @@ module ArJdbc
17
17
  def primary=(value)
18
18
  super
19
19
  @type = :integer if value && @sql_type =~ /^NUMBER$/i
20
- end
20
+ end if ::ActiveRecord::VERSION::STRING < '4.2'
21
21
 
22
22
  def type_cast(value)
23
23
  return nil if value.nil?
@@ -988,7 +988,10 @@ module ArJdbc
988
988
  pk, seq = pk_and_sequence_for(new_name)
989
989
  if seq == "#{table_name}_#{pk}_seq"
990
990
  new_seq = "#{new_name}_#{pk}_seq"
991
+ idx = "#{table_name}_pkey"
992
+ new_idx = "#{new_name}_pkey"
991
993
  execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
994
+ execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
992
995
  end
993
996
  rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
994
997
  end