Module: ArJdbc::Firebird

Included in:
ActiveRecord::ConnectionAdapters::FirebirdAdapter
Defined in:
lib/arjdbc/firebird/adapter.rb

Defined Under Namespace

Modules: Column

Constant Summary collapse

ADAPTER_NAME =
'Firebird'.freeze
NATIVE_DATABASE_TYPES =
{
  :primary_key => "integer not null primary key",
  :string => { :name => "varchar", :limit => 255 },
  :text => { :name => "blob sub_type text" },
  :integer => { :name => "integer" },
  :float => { :name => "float" },
  :datetime => { :name => "timestamp" },
  :timestamp => { :name => "timestamp" },
  :time => { :name => "time" },
  :date => { :name => "date" },
  :binary => { :name => "blob" },
  :boolean => { :name => 'char', :limit => 1 },
  :numeric => { :name => "numeric" },
  :decimal => { :name => "decimal" },
  :char => { :name => "char" },
}
IDENTIFIER_LENGTH =

usual DB meta-identifier: 31 chars maximum

31
@@update_lob_values =
true

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.column_selectorObject

See Also:

  • ActiveRecord::ConnectionAdapters::JdbcColumn#column_types


28
29
30
# File 'lib/arjdbc/firebird/adapter.rb', line 28

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

.emulate_booleansObject

Deprecated.

Use #emulate_booleans? instead.



76
# File 'lib/arjdbc/firebird/adapter.rb', line 76

def self.emulate_booleans; @@emulate_booleans; end

.emulate_booleans=(emulate) ⇒ Object

See Also:

  • #emulate_booleans?


78
# File 'lib/arjdbc/firebird/adapter.rb', line 78

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

.emulate_booleans?Boolean

Boolean emulation can be disabled using :

ArJdbc::Firebird.emulate_booleans = false

Returns:

  • (Boolean)


74
# File 'lib/arjdbc/firebird/adapter.rb', line 74

def self.emulate_booleans?; @@emulate_booleans; end

.jdbc_connection_classObject



23
24
25
# File 'lib/arjdbc/firebird/adapter.rb', line 23

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

.update_lob_values=(update) ⇒ Object



89
# File 'lib/arjdbc/firebird/adapter.rb', line 89

def self.update_lob_values=(update); @@update_lob_values = update; end

.update_lob_values?Boolean

Updating records with LOB values (binary/text columns) in a separate statement can be disabled using :

ArJdbc::Firebird.update_lob_values = false

Returns:

  • (Boolean)


87
# File 'lib/arjdbc/firebird/adapter.rb', line 87

def self.update_lob_values?; @@update_lob_values; end

Instance Method Details

#adapter_nameObject



100
101
102
# File 'lib/arjdbc/firebird/adapter.rb', line 100

def adapter_name
  ADAPTER_NAME
end

#add_limit_offset!(sql, options) ⇒ Object



237
238
239
240
241
# File 'lib/arjdbc/firebird/adapter.rb', line 237

def add_limit_offset!(sql, options)
  if limit = options[:limit]
    insert_limit_offset!(sql, limit, options[:offset])
  end
end

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



303
304
305
# File 'lib/arjdbc/firebird/adapter.rb', line 303

def change_column(table_name, column_name, type, options = {})
  execute "ALTER TABLE #{table_name} ALTER  #{column_name} TYPE #{type_to_sql(type, options[:limit])}"
end

#clear_cache!Object



165
166
167
168
# File 'lib/arjdbc/firebird/adapter.rb', line 165

def clear_cache!
  super
  reload_type_map
end

#column_name_lengthObject



270
# File 'lib/arjdbc/firebird/adapter.rb', line 270

def column_name_length; IDENTIFIER_LENGTH; end

#create_table(name, options = {}) ⇒ Object



287
288
289
290
# File 'lib/arjdbc/firebird/adapter.rb', line 287

def create_table(name, options = {})
  super(name, options)
  execute "CREATE GENERATOR #{default_sequence_name(name)}"
end

#default_sequence_name(table_name, column = nil) ⇒ Object



272
273
274
275
# File 'lib/arjdbc/firebird/adapter.rb', line 272

def default_sequence_name(table_name, column = nil)
  len = IDENTIFIER_LENGTH - 4
  table_name.to_s.gsub (/(^|\.)([\w$-]{1,#{len}})([\w$-]*)$/), '\1\2_seq'
end

#drop_table(name, options = {}) ⇒ Object



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

def drop_table(name, options = {})
  super(name)
  execute_quietly "DROP GENERATOR #{default_sequence_name(name)}"
end

#ids_in_list_limitObject

Does this adapter restrict the number of IDs you can use in a list. Oracle has a limit of 1000.



228
229
230
# File 'lib/arjdbc/firebird/adapter.rb', line 228

def ids_in_list_limit
  1499
end

#index_name_lengthObject



269
# File 'lib/arjdbc/firebird/adapter.rb', line 269

def index_name_length;  IDENTIFIER_LENGTH; end

#initialize_type_map(m) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/arjdbc/firebird/adapter.rb', line 125

def initialize_type_map(m)
  register_class_with_limit m, %r(binary)i, ActiveRecord::Type::Binary
  register_class_with_limit m, %r(text)i,   ActiveRecord::Type::Text

  register_class_with_limit m, %r(date(?:\(.*?\))?$)i, DateType
  register_class_with_limit m, %r(time(?:\(.*?\))?$)i, ActiveRecord::Type::Time

  register_class_with_limit m, %r(float)i, ActiveRecord::Type::Float
  register_class_with_limit m, %r(int)i,   ActiveRecord::Type::Integer

  m.alias_type %r(blob)i,   'binary'
  m.alias_type %r(clob)i,   'text'
  m.alias_type %r(double)i, 'float'

  m.register_type(%r(decimal)i) do |sql_type|
    scale = extract_scale(sql_type)
    precision = extract_precision(sql_type)
    if scale == 0
      ActiveRecord::Type::Integer.new(precision: precision)
    else
      ActiveRecord::Type::Decimal.new(precision: precision, scale: scale)
    end
  end
  m.alias_type %r(numeric)i, 'decimal'

  register_class_with_limit m, %r(varchar)i, ActiveRecord::Type::String

  m.register_type(%r(^char)i) do |sql_type|
    precision = extract_precision(sql_type)
    if Firebird.emulate_booleans? && precision == 1
      ActiveRecord::Type::Boolean.new
    else
      ActiveRecord::Type::String.new(:precision => precision)
    end
  end

  register_class_with_limit m, %r(datetime)i, ActiveRecord::Type::DateTime
  register_class_with_limit m, %r(timestamp)i, TimestampType
end

#insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) ⇒ Object



232
233
234
235
# File 'lib/arjdbc/firebird/adapter.rb', line 232

def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
  execute(sql, name, binds)
  id_value
end

#insert_limit_offset!(sql, limit, offset) ⇒ Object



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

def insert_limit_offset!(sql, limit, offset)
  lim_off = ''
  lim_off << "FIRST #{limit}"  if limit
  lim_off << " SKIP #{offset}" if offset
  lim_off.strip!

  sql.sub!(SELECT_RE, "\\&#{lim_off} ") unless lim_off.empty?
end

#jdbc_column_classObject



65
# File 'lib/arjdbc/firebird/adapter.rb', line 65

def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::FirebirdColumn end

#native_database_typesObject



121
122
123
# File 'lib/arjdbc/firebird/adapter.rb', line 121

def native_database_types
  NATIVE_DATABASE_TYPES
end

#next_sequence_value(sequence_name) ⇒ Object



283
284
285
# File 'lib/arjdbc/firebird/adapter.rb', line 283

def next_sequence_value(sequence_name)
  select_one("SELECT GEN_ID(#{sequence_name}, 1 ) FROM RDB$DATABASE;")["gen_id"]
end

#prefetch_primary_key?(table_name = nil) ⇒ Boolean

Should primary key values be selected from their corresponding sequence before the insert statement?

Returns:

  • (Boolean)

See Also:



259
260
261
262
263
# File 'lib/arjdbc/firebird/adapter.rb', line 259

def prefetch_primary_key?(table_name = nil)
  return true if table_name.nil?
  primary_keys(table_name.to_s).size == 1
  # columns(table_name).count { |column| column.primary } == 1
end

#quote(value, column = nil) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/arjdbc/firebird/adapter.rb', line 316

def quote(value, column = nil)
  return value.quoted_id if value.respond_to?(:quoted_id)
  return value if sql_literal?(value)

  type = column && column.type

  # BLOBs are updated separately by an after_save trigger.
  if type == :binary || type == :text
    if update_lob_values?
      return value.nil? ? "NULL" : BLOB_VALUE_MARKER
    else
      return "'#{quote_string(value)}'"
    end
  end

  case value
  when String, ActiveSupport::Multibyte::Chars
    value = value.to_s
    if type == :integer
      value.to_i.to_s
    elsif type == :float
      value.to_f.to_s
    else
      "'#{quote_string(value)}'"
    end
  when NilClass then 'NULL'
  when TrueClass then (type == :integer ? '1' : quoted_true)
  when FalseClass then (type == :integer ? '0' : quoted_false)
  when Float, Fixnum, Bignum then value.to_s
  # BigDecimals need to be output in a non-normalized form and quoted.
  when BigDecimal then value.to_s('F')
  when Symbol then "'#{quote_string(value.to_s)}'"
  else
    if type == :time && value.acts_like?(:time)
      return "'#{get_time(value).strftime("%H:%M:%S")}'"
    end
    if type == :date && value.acts_like?(:date)
      return "'#{value.strftime("%Y-%m-%d")}'"
    end
    super
  end
end

#quote_column_name(column_name) ⇒ Object



391
392
393
394
# File 'lib/arjdbc/firebird/adapter.rb', line 391

def quote_column_name(column_name)
  column_name = column_name.to_s
  %Q("#{column_name =~ /[[:upper:]]/ ? column_name : column_name.upcase}")
end

#quote_string(string) ⇒ Object



371
372
373
# File 'lib/arjdbc/firebird/adapter.rb', line 371

def quote_string(string)
  string.gsub(/'/, "''")
end

#quote_table_name_for_assignment(table, attr) ⇒ Object



386
387
388
# File 'lib/arjdbc/firebird/adapter.rb', line 386

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

#quoted_date(value) ⇒ Object



360
361
362
363
364
365
366
367
368
# File 'lib/arjdbc/firebird/adapter.rb', line 360

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

#quoted_falseObject



381
382
383
# File 'lib/arjdbc/firebird/adapter.rb', line 381

def quoted_false
  quote(0)
end

#quoted_trueObject



376
377
378
# File 'lib/arjdbc/firebird/adapter.rb', line 376

def quoted_true
  quote(1)
end

#remove_index(table_name, options) ⇒ Object



311
312
313
# File 'lib/arjdbc/firebird/adapter.rb', line 311

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



307
308
309
# File 'lib/arjdbc/firebird/adapter.rb', line 307

def rename_column(table_name, column_name, new_column_name)
  execute "ALTER TABLE #{table_name} ALTER  #{column_name} TO #{new_column_name}"
end

#rename_table(name, new_name) ⇒ Object



292
293
294
295
296
# File 'lib/arjdbc/firebird/adapter.rb', line 292

def rename_table(name, new_name)
  execute "RENAME #{name} TO #{new_name}"
  name_seq, new_name_seq = default_sequence_name(name), default_sequence_name(new_name)
  execute_quietly "UPDATE RDB$GENERATORS SET RDB$GENERATOR_NAME='#{new_name_seq}' WHERE RDB$GENERATOR_NAME='#{name_seq}'"
end

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

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



278
279
280
281
# File 'lib/arjdbc/firebird/adapter.rb', line 278

def reset_sequence!(table, column, sequence = nil)
  max_id = select_value("SELECT max(#{column}) FROM #{table}")
  execute("ALTER SEQUENCE #{default_sequence_name(table, column)} RESTART WITH #{max_id}")
end

#supports_ddl_transactions?Boolean

Does this adapter support DDL rollbacks in transactions? That is, would CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL, SQL Server, and others support this. MySQL and others do not.

Returns:

  • (Boolean)


222
223
224
# File 'lib/arjdbc/firebird/adapter.rb', line 222

def supports_ddl_transactions?
  false
end

#supports_migrations?Boolean

Does this adapter support migrations?

Returns:

  • (Boolean)


209
210
211
# File 'lib/arjdbc/firebird/adapter.rb', line 209

def supports_migrations?
  true
end

#supports_primary_key?Boolean

Can this adapter determine the primary key for tables not attached to an Active Record class, such as join tables?

Returns:

  • (Boolean)


215
216
217
# File 'lib/arjdbc/firebird/adapter.rb', line 215

def supports_primary_key?
  true
end

#table_alias_lengthObject



267
# File 'lib/arjdbc/firebird/adapter.rb', line 267

def table_alias_length; IDENTIFIER_LENGTH; end

#table_name_lengthObject



268
# File 'lib/arjdbc/firebird/adapter.rb', line 268

def table_name_length;  IDENTIFIER_LENGTH; end

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



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/arjdbc/firebird/adapter.rb', line 187

def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  case type
  when :integer
    case limit
      when nil  then 'integer'
      when 1..2 then 'smallint'
      when 3..4 then 'integer'
      when 5..8 then 'bigint'
      else raise(ActiveRecordError, "No integer type has byte size #{limit}. "<<
                                    "Use a NUMERIC with PRECISION 0 instead.")
    end
  when :float
    if limit.nil? || limit <= 4
      'float'
    else
      'double precision'
    end
  else super
  end
end

#update_lob_values?Boolean

Returns:

  • (Boolean)

See Also:



92
# File 'lib/arjdbc/firebird/adapter.rb', line 92

def update_lob_values?; Firebird.update_lob_values?; end