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.



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

def self.emulate_booleans; @@emulate_booleans; end

.emulate_booleans=(emulate) ⇒ Object

See Also:

  • #emulate_booleans?


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

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)


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

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



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

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)


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

def self.update_lob_values?; @@update_lob_values; end

Instance Method Details

#adapter_nameObject



79
80
81
# File 'lib/arjdbc/firebird/adapter.rb', line 79

def adapter_name
  ADAPTER_NAME
end

#add_limit_offset!(sql, options) ⇒ Object



216
217
218
219
220
# File 'lib/arjdbc/firebird/adapter.rb', line 216

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



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

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



144
145
146
147
# File 'lib/arjdbc/firebird/adapter.rb', line 144

def clear_cache!
  super
  reload_type_map
end

#column_name_lengthObject



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

def column_name_length; IDENTIFIER_LENGTH; end

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



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

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

#default_sequence_name(table_name, column = nil) ⇒ Object



251
252
253
254
# File 'lib/arjdbc/firebird/adapter.rb', line 251

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



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

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.



207
208
209
# File 'lib/arjdbc/firebird/adapter.rb', line 207

def ids_in_list_limit
  1499
end

#index_name_lengthObject



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

def index_name_length;  IDENTIFIER_LENGTH; end

#initialize_type_map(m) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/arjdbc/firebird/adapter.rb', line 104

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



211
212
213
214
# File 'lib/arjdbc/firebird/adapter.rb', line 211

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



225
226
227
228
229
230
231
232
# File 'lib/arjdbc/firebird/adapter.rb', line 225

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



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

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

#native_database_typesObject



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

def native_database_types
  NATIVE_DATABASE_TYPES
end

#next_sequence_value(sequence_name) ⇒ Object



262
263
264
# File 'lib/arjdbc/firebird/adapter.rb', line 262

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:



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

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



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/arjdbc/firebird/adapter.rb', line 295

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



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

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



350
351
352
# File 'lib/arjdbc/firebird/adapter.rb', line 350

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

#quote_table_name_for_assignment(table, attr) ⇒ Object



365
366
367
# File 'lib/arjdbc/firebird/adapter.rb', line 365

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

#quoted_date(value) ⇒ Object



339
340
341
342
343
344
345
346
347
# File 'lib/arjdbc/firebird/adapter.rb', line 339

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



360
361
362
# File 'lib/arjdbc/firebird/adapter.rb', line 360

def quoted_false
  quote(0)
end

#quoted_trueObject



355
356
357
# File 'lib/arjdbc/firebird/adapter.rb', line 355

def quoted_true
  quote(1)
end

#remove_index(table_name, options) ⇒ Object



290
291
292
# File 'lib/arjdbc/firebird/adapter.rb', line 290

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



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

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



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

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.



257
258
259
260
# File 'lib/arjdbc/firebird/adapter.rb', line 257

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)


201
202
203
# File 'lib/arjdbc/firebird/adapter.rb', line 201

def supports_ddl_transactions?
  false
end

#supports_migrations?Boolean

Does this adapter support migrations?

Returns:

  • (Boolean)


188
189
190
# File 'lib/arjdbc/firebird/adapter.rb', line 188

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)


194
195
196
# File 'lib/arjdbc/firebird/adapter.rb', line 194

def supports_primary_key?
  true
end

#table_alias_lengthObject



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

def table_alias_length; IDENTIFIER_LENGTH; end

#table_name_lengthObject



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

def table_name_length;  IDENTIFIER_LENGTH; end

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



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/arjdbc/firebird/adapter.rb', line 166

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:



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

def update_lob_values?; Firebird.update_lob_values?; end