Module: ArJdbc::Derby

Includes:
Util::TableCopier
Defined in:
lib/arjdbc/derby/adapter.rb,
lib/arjdbc/derby/schema_creation.rb

Defined Under Namespace

Modules: Column Classes: SchemaCreation

Constant Summary collapse

ADAPTER_NAME =
'Derby'.freeze
NATIVE_DATABASE_TYPES =
{
  :primary_key => "int GENERATED BY DEFAULT AS identity NOT NULL PRIMARY KEY",
  :string => { :name => "varchar", :limit => 255 }, # 32672
  :text => { :name => "clob" }, # 2,147,483,647
  :char => { :name => "char", :limit => 254 }, # JDBC :limit => 254
  :binary => { :name => "blob" }, # 2,147,483,647
  :float => { :name => "float", :limit => 8 }, # DOUBLE PRECISION
  :real => { :name => "real", :limit => 4 }, # JDBC :limit => 23
  :double => { :name => "double", :limit => 8 }, # JDBC :limit => 52
  :decimal => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
  :numeric => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
  :integer => { :name => "integer", :limit => 4 }, # JDBC :limit => 10
  :smallint => { :name => "smallint", :limit => 2 }, # JDBC :limit => 5
  :bigint => { :name => "bigint", :limit => 8 }, # JDBC :limit => 19
  :date => { :name => "date" },
  :time => { :name => "time" },
  :datetime => { :name => "timestamp" },
  :timestamp => { :name => "timestamp" },
  :xml => { :name => "xml" },
  :boolean => { :name => "smallint", :limit => 1 }, # TODO boolean (since 10.7)
  :object => { :name => "object" },
}

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::TableCopier

#alter_table, #copy_table, #copy_table_contents, #copy_table_indexes, #move_table

Class Method Details

.arel_visitor_type(config = nil) ⇒ Object



97
98
99
# File 'lib/arjdbc/derby/adapter.rb', line 97

def self.arel_visitor_type(config = nil)
  require 'arel/visitors/derby'; ::Arel::Visitors::Derby
end

.column_selectorObject

See Also:

  • ActiveRecord::ConnectionAdapters::JdbcColumn#column_types


24
25
26
# File 'lib/arjdbc/derby/adapter.rb', line 24

def self.column_selector
  [ /derby/i, lambda { |config, column| column.extend(Column) } ]
end

.emulate_booleansObject

Deprecated.

Use #emulate_booleans? instead.



37
# File 'lib/arjdbc/derby/adapter.rb', line 37

def self.emulate_booleans; @@emulate_booleans; end

.emulate_booleans=(emulate) ⇒ Object

See Also:

  • #emulate_booleans?


39
# File 'lib/arjdbc/derby/adapter.rb', line 39

def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end

.emulate_booleans?Boolean

Boolean emulation can be disabled using :

ArJdbc::Derby.emulate_booleans = false

Returns:

  • (Boolean)


35
# File 'lib/arjdbc/derby/adapter.rb', line 35

def self.emulate_booleans?; @@emulate_booleans; end

.jdbc_connection_classObject



19
20
21
# File 'lib/arjdbc/derby/adapter.rb', line 19

def self.jdbc_connection_class
  ::ActiveRecord::ConnectionAdapters::DerbyJdbcConnection
end

Instance Method Details

#adapter_nameObject



103
104
105
# File 'lib/arjdbc/derby/adapter.rb', line 103

def adapter_name
  ADAPTER_NAME
end

#add_column(table_name, column_name, type, options = {}) ⇒ Object



303
304
305
306
307
# File 'lib/arjdbc/derby/adapter.rb', line 303

def add_column(table_name, column_name, type, options = {})
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  add_column_options!(add_column_sql, options)
  execute(add_column_sql)
end

#add_column_options!(sql, options) ⇒ Object



310
311
312
313
314
# File 'lib/arjdbc/derby/adapter.rb', line 310

def add_column_options!(sql, options)
  options.delete(:default) if options.has_key?(:default) && options[:default].nil?
  sql << " DEFAULT #{quote(options.delete(:default))}" if options.has_key?(:default)
  super
end

#add_limit_offset!(sql, options) ⇒ Object

Note:

Only used with (non-AREL) ActiveRecord 2.3.



496
497
498
499
500
# File 'lib/arjdbc/derby/adapter.rb', line 496

def add_limit_offset!(sql, options)
  sql << " OFFSET #{options[:offset]} ROWS" if options[:offset]
  # ROWS/ROW and FIRST/NEXT mean the same
  sql << " FETCH FIRST #{options[:limit]} ROWS ONLY" if options[:limit]
end

#change_column(table_name, column_name, type, options = {}) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/arjdbc/derby/adapter.rb', line 341

def change_column(table_name, column_name, type, options = {})
  # TODO this needs a review since now we're likely to be on >= 10.8

  # Notes about changing in Derby:
  #    http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
  #
  # We support changing columns using the strategy outlined in:
  #    https://issues.apache.org/jira/browse/DERBY-1515
  #
  # This feature has not made it into a formal release and is not in Java 6.
  # We will need to conditionally support this (supposed to arrive for 10.3.0.0).

  # null/not nulling is easy, handle that separately
  if options.include?(:null)
    # This seems to only work with 10.2 of Derby
    if options.delete(:null) == false
      execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} NOT NULL"
    else
      execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} NULL"
    end
  end

  # anything left to do?
  unless options.empty?
    begin
      execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN " <<
              " #{quote_column_name(column_name)} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
    rescue
      transaction do
        temp_new_column_name = "#{column_name}_newtype"
        # 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
        add_column table_name, temp_new_column_name, type, options
        # 2) UPDATE t SET c1_newtype = c1;
        execute "UPDATE #{quote_table_name(table_name)} SET " <<
                " #{quote_column_name(temp_new_column_name)} = " <<
                " CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit])})"
        # 3) ALTER TABLE t DROP COLUMN c1;
        remove_column table_name, column_name
        # 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
        rename_column table_name, temp_new_column_name, column_name
      end
    end
  end
end

#columns_for_distinct(columns, orders) ⇒ Object



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/arjdbc/derby/adapter.rb', line 406

def columns_for_distinct(columns, orders)
  return columns if orders.blank?

  # construct a clean list of column names from the ORDER BY clause,
  # removing any ASC/DESC modifiers
  order_columns = [ orders ]; order_columns.flatten! # AR 3.x vs 4.x
  order_columns.map! do |column|
    column = column.to_sql unless column.is_a?(String) # handle AREL node
    column.split(',').collect! { |s| s.split.first }
  end.flatten!
  order_columns.reject!(&:blank?)
  order_columns = order_columns.zip (0...order_columns.size).to_a
  order_columns = order_columns.map { |s, i| "#{s} AS alias_#{i}" }

  columns = [ columns ]; columns.flatten!
  columns.push( *order_columns ).join(', ')
  # return a DISTINCT clause that's distinct on the columns we want but
  # includes all the required columns for the ORDER BY to work properly
end

#configure_connectionObject



123
124
125
126
127
128
129
130
131
# File 'lib/arjdbc/derby/adapter.rb', line 123

def configure_connection
  # must be done or SELECT...FOR UPDATE won't work how we expect :
  tx_isolation = config[:transaction_isolation] # set false to leave as is
  tx_isolation = :serializable if tx_isolation.nil?
  @connection.transaction_isolation = tx_isolation if tx_isolation
  # if a user name was specified upon connection, the user's name is the
  # default schema for the connection, if a schema with that name exists
  set_schema(config[:schema]) if config.key?(:schema)
end

#create_savepoint(name = current_savepoint_name(true)) ⇒ Object

Ensure the savepoint name is unused before creating it.



184
185
186
187
# File 'lib/arjdbc/derby/adapter.rb', line 184

def create_savepoint(name = current_savepoint_name(true))
  release_savepoint(name) if @connection.marked_savepoint_names.include?(name)
  super(name)
end

#create_schema(schema) ⇒ Object

Creates a new Derby schema.

See Also:



461
462
463
# File 'lib/arjdbc/derby/adapter.rb', line 461

def create_schema(schema)
  execute "CREATE SCHEMA #{schema}", 'Create Schema'
end

#current_schemaString

Returns the current schema name.

Returns:

  • (String)

    the current schema name



447
448
449
450
# File 'lib/arjdbc/derby/adapter.rb', line 447

def current_schema
  @current_schema ||=
    select_value "SELECT CURRENT SCHEMA FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY", 'SCHEMA'
end

#distinct(columns, order_by) ⇒ Object

Note:

This is based on distinct method for the PostgreSQL Adapter.

SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.

Derby requires the ORDER BY columns in the select list for distinct queries, and requires that the ORDER BY include the distinct column.

  distinct("posts.id", "posts.created_at desc")


401
402
403
# File 'lib/arjdbc/derby/adapter.rb', line 401

def distinct(columns, order_by)
  "DISTINCT #{columns_for_distinct(columns, order_by)}"
end

#drop_schema(schema) ⇒ Object

Drops an existing schema, needs to be empty (no DB objects).



466
467
468
# File 'lib/arjdbc/derby/adapter.rb', line 466

def drop_schema(schema)
  execute "DROP SCHEMA #{schema} RESTRICT", 'Drop Schema'
end

#empty_insert_statement_valueObject



268
269
270
# File 'lib/arjdbc/derby/adapter.rb', line 268

def empty_insert_statement_value
  ::Arel::Visitors::Derby::VALUES_DEFAULT # Derby needs to know the columns
end

#execute(sql, name = nil, binds = []) ⇒ Object



503
504
505
506
507
508
509
# File 'lib/arjdbc/derby/adapter.rb', line 503

def execute(sql, name = nil, binds = [])
  sql = to_sql(sql, binds)
  insert = self.class.insert?(sql)
  update = ! insert && ! self.class.select?(sql)
  sql = correct_is_null(sql, insert || update)
  super(sql, name, binds)
end

#index_name_lengthObject



133
134
135
# File 'lib/arjdbc/derby/adapter.rb', line 133

def index_name_length
  128
end

#last_insert_idFixnum

Note:

Check the IDENTITY_VAL_LOCAL function for documentation.

Returns the value of an identity column of the last INSERT statement made over this connection.

Returns:

  • (Fixnum)


515
516
517
# File 'lib/arjdbc/derby/adapter.rb', line 515

def last_insert_id
  @connection.identity_val_local
end

#native_database_typesObject



178
179
180
# File 'lib/arjdbc/derby/adapter.rb', line 178

def native_database_types
  NATIVE_DATABASE_TYPES
end

#primary_keys(table_name) ⇒ Object



427
428
429
# File 'lib/arjdbc/derby/adapter.rb', line 427

def primary_keys(table_name)
  @connection.primary_keys table_name.to_s.upcase
end

#quote(value, column = nil) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/arjdbc/derby/adapter.rb', line 190

def quote(value, column = nil)
  return super if column && ArJdbc::AR42 && column.cast_type.is_a?(ActiveRecord::Type::Serialized)
  return value.quoted_id if value.respond_to?(:quoted_id)
  return value if sql_literal?(value)
  return 'NULL' if value.nil?

  column_type = column && column.type
  if column_type == :string || column_type == :text
    # Derby is not permissive
    # e.g. sending an Integer to a VARCHAR column will fail
    case value
    when BigDecimal then value = value.to_s('F')
    when Numeric then value = value.to_s
    when true, false then value = value.to_s
    when Date, Time then value = quoted_date(value)
    else # on 2.3 attribute serialization needs to_yaml here
      value = value.to_s if ActiveRecord::VERSION::MAJOR >= 3
    end
  end

  case value
  when String, ActiveSupport::Multibyte::Chars
    if column_type == :text
      "CAST('#{quote_string(value)}' AS CLOB)"
    elsif column_type == :binary
      "CAST(X'#{quote_binary(value)}' AS BLOB)"
    elsif column_type == :xml
      "XMLPARSE(DOCUMENT '#{quote_string(value)}' PRESERVE WHITESPACE)"
    elsif column_type == :integer
      value.to_i
    elsif column_type == :float
      value.to_f
    else
      "'#{quote_string(value)}'"
    end
  else
    super
  end
end

#quote_column_name(name) ⇒ Object



485
486
487
# File 'lib/arjdbc/derby/adapter.rb', line 485

def quote_column_name(name)
  %Q{"#{name.to_s.upcase.gsub('"', '""')}"}
end

#quote_table_name_for_assignment(table, attr) ⇒ Object



490
491
492
# File 'lib/arjdbc/derby/adapter.rb', line 490

def quote_table_name_for_assignment(table, attr)
  quote_column_name(attr)
end

#quoted_date(value) ⇒ Object



231
232
233
234
235
236
237
238
239
# File 'lib/arjdbc/derby/adapter.rb', line 231

def quoted_date(value)
  if value.acts_like?(:time) && value.respond_to?(:usec)
    usec = sprintf("%06d", value.usec)
    value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
    "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
  else
    super
  end
end

#remove_column(table_name, *column_names) ⇒ Object Also known as: remove_columns



319
320
321
# File 'lib/arjdbc/derby/adapter.rb', line 319

def remove_column(table_name, column_name, type = nil, options = {})
  do_remove_column(table_name, column_name)
end

#remove_index(table_name, options) ⇒ Object



294
295
296
# File 'lib/arjdbc/derby/adapter.rb', line 294

def remove_index(table_name, options)
  execute "DROP INDEX #{index_name(table_name, options)}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object



387
388
389
390
# File 'lib/arjdbc/derby/adapter.rb', line 387

def rename_column(table_name, column_name, new_column_name)
  execute "RENAME COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} " <<
          " TO #{quote_column_name(new_column_name)}"
end

#rename_table(name, new_name) ⇒ Object



299
300
301
# File 'lib/arjdbc/derby/adapter.rb', line 299

def rename_table(name, new_name)
  execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
end

#reset_column_informationObject



173
174
175
# File 'lib/arjdbc/derby/adapter.rb', line 173

def reset_column_information
  initialize_type_map(type_map)
end

#reset_pk_sequence!(table, pk = nil, sequence = nil) ⇒ Object



279
280
281
282
283
284
285
286
# File 'lib/arjdbc/derby/adapter.rb', line 279

def reset_pk_sequence!(table, pk = nil, sequence = nil)
  klasses = classes_for_table_name(table)
  klass   = klasses.nil? ? nil : klasses.first
  pk      = klass.primary_key unless klass.nil?
  if pk && klass.columns_hash[pk].type == :integer
    reset_sequence!(klass.table_name, pk)
  end
end

#reset_sequence!(table, column, sequence = nil) ⇒ Object

Set the sequence to the max value of the table's column.



274
275
276
277
# File 'lib/arjdbc/derby/adapter.rb', line 274

def reset_sequence!(table, column, sequence = nil)
  mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
  execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
end

#set_schema(schema) ⇒ Object Also known as: current_schema=

Change the current (implicit) Derby schema to be used for this connection.



453
454
455
456
# File 'lib/arjdbc/derby/adapter.rb', line 453

def set_schema(schema)
  @current_schema = nil
  execute "SET SCHEMA #{schema}", 'SCHEMA'
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


437
# File 'lib/arjdbc/derby/adapter.rb', line 437

def supports_ddl_transactions?; true end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


440
# File 'lib/arjdbc/derby/adapter.rb', line 440

def supports_foreign_keys?; true end

#table_definition(*args) ⇒ Object



263
264
265
# File 'lib/arjdbc/derby/adapter.rb', line 263

def table_definition(*args)
  new_table_definition(TableDefinition, *args)
end

#tables(name = nil) ⇒ Object



432
433
434
# File 'lib/arjdbc/derby/adapter.rb', line 432

def tables(name = nil)
  @connection.tables(nil, current_schema)
end

#truncate(table_name, name = nil) ⇒ Object



442
443
444
# File 'lib/arjdbc/derby/adapter.rb', line 442

def truncate(table_name, name = nil)
  execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
end

#type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object

Convert the specified column type to a SQL string.



246
247
248
249
250
251
# File 'lib/arjdbc/derby/adapter.rb', line 246

def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  return super unless NO_LIMIT_TYPES.include?(t = type.to_s.downcase.to_sym)

  native_type = NATIVE_DATABASE_TYPES[t]
  native_type.is_a?(Hash) ? native_type[:name] : native_type
end