fb_adapter 0.5.5
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.
- data/fb_adapter.gemspec +24 -0
- data/lib/active_record/connection_adapters/fb_adapter.rb +446 -0
- metadata +54 -0
data/fb_adapter.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/env ruby
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
|
|
4
|
+
spec = Gem::Specification.new do |s|
|
|
5
|
+
s.author = "Brent Rowland"
|
|
6
|
+
s.name = "fb_adapter"
|
|
7
|
+
s.version = "0.5.5"
|
|
8
|
+
s.date = "2008-02-27"
|
|
9
|
+
s.summary = "ActiveRecord Firebird Adapter"
|
|
10
|
+
s.requirements = "Firebird library fb"
|
|
11
|
+
s.require_path = 'lib'
|
|
12
|
+
s.email = "rowland@rowlandresearch.com"
|
|
13
|
+
s.homepage = "http://www.rowlandresearch.com/ruby/"
|
|
14
|
+
s.rubyforge_project = "fblib"
|
|
15
|
+
s.has_rdoc = false
|
|
16
|
+
# s.extra_rdoc_files = ['README']
|
|
17
|
+
# s.rdoc_options << '--title' << 'Fb -- ActiveRecord Firebird Adapter' << '--main' << 'README' << '-x' << 'test'
|
|
18
|
+
s.files = ['fb_adapter.gemspec'] + Dir.glob('lib/active_record/connection_adapters/*')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if __FILE__ == $0
|
|
22
|
+
Gem.manage_gems
|
|
23
|
+
Gem::Builder.new(spec).build
|
|
24
|
+
end
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# Author: Ken Kunz <kennethkunz@gmail.com>
|
|
2
|
+
# Converted from FireRuby to Fb extension by Brent Rowland <rowland@rowlandresearch.com>
|
|
3
|
+
|
|
4
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
5
|
+
require 'base64'
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
class << Base
|
|
9
|
+
def fb_connection(config) # :nodoc:
|
|
10
|
+
require_library_or_gem 'fb'
|
|
11
|
+
config = config.symbolize_keys.merge(:downcase_names => true)
|
|
12
|
+
unless config.has_key?(:database)
|
|
13
|
+
raise ArgumentError, "No database specified. Missing argument: database."
|
|
14
|
+
end
|
|
15
|
+
config[:database] = File.expand_path(config[:database]) if config[:host] =~ /localhost/i
|
|
16
|
+
config[:database] = "#{config[:host]}:#{config[:database]}" if config[:host]
|
|
17
|
+
db = Fb::Database.new(config)
|
|
18
|
+
begin
|
|
19
|
+
connection = db.connect
|
|
20
|
+
rescue
|
|
21
|
+
require 'pp'; pp config
|
|
22
|
+
connection = config[:create] ? db.create.connect : (raise ConnectionNotEstablished, "No Firebird connections established.")
|
|
23
|
+
end
|
|
24
|
+
ConnectionAdapters::FbAdapter.new(connection, logger, config)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module ConnectionAdapters
|
|
29
|
+
class FbColumn < Column # :nodoc:
|
|
30
|
+
def initialize(name, domain, type, sub_type, length, precision, scale, default_source, null_flag)
|
|
31
|
+
#puts "*** #{type} ~~~ #{sub_type}"
|
|
32
|
+
@firebird_type = Fb::SqlType.from_code(type, sub_type || 0)
|
|
33
|
+
super(name.downcase, nil, @firebird_type, !null_flag)
|
|
34
|
+
@default = parse_default(default_source) if default_source
|
|
35
|
+
@limit = (@firebird_type == 'BLOB') ? 10 * 1024 * 1024 : length
|
|
36
|
+
@domain, @sub_type, @precision, @scale = domain, sub_type, precision, scale
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def type
|
|
40
|
+
if @domain =~ /BOOLEAN/
|
|
41
|
+
:boolean
|
|
42
|
+
elsif @type == :binary and @sub_type == 1
|
|
43
|
+
:text
|
|
44
|
+
else
|
|
45
|
+
@type
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Submits a _CAST_ query to the database, casting the default value to the specified SQL type.
|
|
50
|
+
# This enables Firebird to provide an actual value when context variables are used as column
|
|
51
|
+
# defaults (such as CURRENT_TIMESTAMP).
|
|
52
|
+
def default
|
|
53
|
+
if @default
|
|
54
|
+
sql = "SELECT CAST(#{@default} AS #{column_def}) FROM RDB$DATABASE"
|
|
55
|
+
connection = ActiveRecord::Base.active_connections.values.detect { |conn| conn && conn.adapter_name == 'Fb' }
|
|
56
|
+
if connection
|
|
57
|
+
type_cast connection.select_one(sql)['cast']
|
|
58
|
+
else
|
|
59
|
+
raise ConnectionNotEstablished, "No Firebird connections established."
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.value_to_boolean(value)
|
|
65
|
+
%W(#{FbAdapter.boolean_domain[:true]} true t 1).include? value.to_s.downcase
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
def parse_default(default_source)
|
|
70
|
+
default_source =~ /^\s*DEFAULT\s+(.*)\s*$/i
|
|
71
|
+
return $1 unless $1.upcase == "NULL"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def column_def
|
|
75
|
+
case @firebird_type
|
|
76
|
+
when 'CHAR', 'VARCHAR' then "#{@firebird_type}(#{@limit})"
|
|
77
|
+
when 'NUMERIC', 'DECIMAL' then "#{@firebird_type}(#{@precision},#{@scale.abs})"
|
|
78
|
+
#when 'DOUBLE' then "DOUBLE PRECISION"
|
|
79
|
+
else @firebird_type
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def simplified_type(field_type)
|
|
84
|
+
if field_type == 'TIMESTAMP'
|
|
85
|
+
:datetime
|
|
86
|
+
else
|
|
87
|
+
super
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The Fb adapter relies on the Fb extension.
|
|
93
|
+
#
|
|
94
|
+
# == Usage Notes
|
|
95
|
+
#
|
|
96
|
+
# === Sequence (Generator) Names
|
|
97
|
+
# The Fb adapter supports the same approach adopted for the Oracle
|
|
98
|
+
# adapter. See ActiveRecord::Base#set_sequence_name for more details.
|
|
99
|
+
#
|
|
100
|
+
# Note that in general there is no need to create a <tt>BEFORE INSERT</tt>
|
|
101
|
+
# trigger corresponding to a Firebird sequence generator when using
|
|
102
|
+
# ActiveRecord. In other words, you don't have to try to make Firebird
|
|
103
|
+
# simulate an <tt>AUTO_INCREMENT</tt> or +IDENTITY+ column. When saving a
|
|
104
|
+
# new record, ActiveRecord pre-fetches the next sequence value for the table
|
|
105
|
+
# and explicitly includes it in the +INSERT+ statement. (Pre-fetching the
|
|
106
|
+
# next primary key value is the only reliable method for the Fb
|
|
107
|
+
# adapter to report back the +id+ after a successful insert.)
|
|
108
|
+
#
|
|
109
|
+
# === BOOLEAN Domain
|
|
110
|
+
# Firebird 1.5 does not provide a native +BOOLEAN+ type. But you can easily
|
|
111
|
+
# define a +BOOLEAN+ _domain_ for this purpose, e.g.:
|
|
112
|
+
#
|
|
113
|
+
# CREATE DOMAIN D_BOOLEAN AS SMALLINT CHECK (VALUE IN (0, 1));
|
|
114
|
+
#
|
|
115
|
+
# When the Fb adapter encounters a column that is based on a domain
|
|
116
|
+
# that includes "BOOLEAN" in the domain name, it will attempt to treat
|
|
117
|
+
# the column as a +BOOLEAN+.
|
|
118
|
+
#
|
|
119
|
+
# By default, the Fb adapter will assume that the BOOLEAN domain is
|
|
120
|
+
# defined as above. This can be modified if needed. For example, if you
|
|
121
|
+
# have a legacy schema with the following +BOOLEAN+ domain defined:
|
|
122
|
+
#
|
|
123
|
+
# CREATE DOMAIN BOOLEAN AS CHAR(1) CHECK (VALUE IN ('T', 'F'));
|
|
124
|
+
#
|
|
125
|
+
# ...you can add the following line to your <tt>environment.rb</tt> file:
|
|
126
|
+
#
|
|
127
|
+
# ActiveRecord::ConnectionAdapters::Fb.boolean_domain = { :true => 'T', :false => 'F' }
|
|
128
|
+
#
|
|
129
|
+
# === Column Name Case Semantics
|
|
130
|
+
# Firebird and ActiveRecord have somewhat conflicting case semantics for
|
|
131
|
+
# column names.
|
|
132
|
+
#
|
|
133
|
+
# [*Firebird*]
|
|
134
|
+
# The standard practice is to use unquoted column names, which can be
|
|
135
|
+
# thought of as case-insensitive. (In fact, Firebird converts them to
|
|
136
|
+
# uppercase.) Quoted column names (not typically used) are case-sensitive.
|
|
137
|
+
# [*ActiveRecord*]
|
|
138
|
+
# Attribute accessors corresponding to column names are case-sensitive.
|
|
139
|
+
# The defaults for primary key and inheritance columns are lowercase, and
|
|
140
|
+
# in general, people use lowercase attribute names.
|
|
141
|
+
#
|
|
142
|
+
# In order to map between the differing semantics in a way that conforms
|
|
143
|
+
# to common usage for both Firebird and ActiveRecord, uppercase column names
|
|
144
|
+
# in Firebird are converted to lowercase attribute names in ActiveRecord,
|
|
145
|
+
# and vice-versa. Mixed-case column names retain their case in both
|
|
146
|
+
# directions. Lowercase (quoted) Firebird column names are not supported.
|
|
147
|
+
# This is similar to the solutions adopted by other adapters.
|
|
148
|
+
#
|
|
149
|
+
# In general, the best approach is to use unquoted (case-insensitive) column
|
|
150
|
+
# names in your Firebird DDL (or if you must quote, use uppercase column
|
|
151
|
+
# names). These will correspond to lowercase attributes in ActiveRecord.
|
|
152
|
+
#
|
|
153
|
+
# For example, a Firebird table based on the following DDL:
|
|
154
|
+
#
|
|
155
|
+
# CREATE TABLE products (
|
|
156
|
+
# id BIGINT NOT NULL PRIMARY KEY,
|
|
157
|
+
# "TYPE" VARCHAR(50),
|
|
158
|
+
# name VARCHAR(255) );
|
|
159
|
+
#
|
|
160
|
+
# ...will correspond to an ActiveRecord model class called +Product+ with
|
|
161
|
+
# the following attributes: +id+, +type+, +name+.
|
|
162
|
+
#
|
|
163
|
+
# ==== Quoting <tt>"TYPE"</tt> and other Firebird reserved words:
|
|
164
|
+
# In ActiveRecord, the default inheritance column name is +type+. The word
|
|
165
|
+
# _type_ is a Firebird reserved word, so it must be quoted in any Firebird
|
|
166
|
+
# SQL statements. Because of the case mapping described above, you should
|
|
167
|
+
# always reference this column using quoted-uppercase syntax
|
|
168
|
+
# (<tt>"TYPE"</tt>) within Firebird DDL or other SQL statements (as in the
|
|
169
|
+
# example above). This holds true for any other Firebird reserved words used
|
|
170
|
+
# as column names as well.
|
|
171
|
+
#
|
|
172
|
+
# === Migrations
|
|
173
|
+
# The Fb adapter does not currently support Migrations.
|
|
174
|
+
#
|
|
175
|
+
# == Connection Options
|
|
176
|
+
# The following options are supported by the Fb adapter.
|
|
177
|
+
#
|
|
178
|
+
# <tt>:database</tt>::
|
|
179
|
+
# <i>Required option.</i> Specifies one of: (i) a Firebird database alias;
|
|
180
|
+
# (ii) the full path of a database file; _or_ (iii) a full Firebird
|
|
181
|
+
# connection string. <i>Do not specify <tt>:host</tt>, <tt>:service</tt>
|
|
182
|
+
# or <tt>:port</tt> as separate options when using a full connection
|
|
183
|
+
# string.</i>
|
|
184
|
+
# <tt>:username</tt>::
|
|
185
|
+
# Specifies the database user. Defaults to 'sysdba'.
|
|
186
|
+
# <tt>:password</tt>::
|
|
187
|
+
# Specifies the database password. Defaults to 'masterkey'.
|
|
188
|
+
# <tt>:charset</tt>::
|
|
189
|
+
# Specifies the character set to be used by the connection. Refer to the
|
|
190
|
+
# Firebird documentation for valid options.
|
|
191
|
+
class FbAdapter < AbstractAdapter
|
|
192
|
+
@@boolean_domain = { :true => 1, :false => 0 }
|
|
193
|
+
cattr_accessor :boolean_domain
|
|
194
|
+
|
|
195
|
+
def initialize(connection, logger, connection_params=nil)
|
|
196
|
+
super(connection, logger)
|
|
197
|
+
@connection_params = connection_params
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def adapter_name # :nodoc:
|
|
201
|
+
'Fb'
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Returns true for Fb adapter (since Firebird requires primary key
|
|
205
|
+
# values to be pre-fetched before insert). See also #next_sequence_value.
|
|
206
|
+
def prefetch_primary_key?(table_name = nil)
|
|
207
|
+
true
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def default_sequence_name(table_name, primary_key) # :nodoc:
|
|
211
|
+
"#{table_name}_seq"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# QUOTING ==================================================
|
|
216
|
+
|
|
217
|
+
def quote(value, column = nil) # :nodoc:
|
|
218
|
+
case value
|
|
219
|
+
when String
|
|
220
|
+
"@#{Base64.encode64(value).chop}@"
|
|
221
|
+
when Float, Fixnum, Bignum then quote_number(value)
|
|
222
|
+
when Date then quote_date(value)
|
|
223
|
+
when Time, DateTime then quote_timestamp(value)
|
|
224
|
+
when NilClass then "NULL"
|
|
225
|
+
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
|
|
226
|
+
when FalseClass then (column && column.type == :integer ? '0' : quoted_false)
|
|
227
|
+
else quote_object(value)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def quote_number(value)
|
|
232
|
+
# "@#{Base64.encode64(value.to_s).chop}@"
|
|
233
|
+
value.to_s
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def quote_date(value)
|
|
237
|
+
"@#{Base64.encode64(value.strftime('%Y-%m-%d')).chop}@"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def quote_timestamp(value)
|
|
241
|
+
"@#{Base64.encode64(value.strftime('%Y-%m-%d %H:%M:%S')).chop}@"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def quote_string(string) # :nodoc:
|
|
245
|
+
string.gsub(/'/, "''")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def quote_object(obj)
|
|
249
|
+
return obj.respond_to?(:quoted_id) ? obj.quoted_id : "@#{Base64.encode64(obj.to_yaml).chop}@"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def quote_column_name(column_name) # :nodoc:
|
|
253
|
+
%Q("#{ar_to_fb_case(column_name.to_s)}")
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def quoted_true # :nodoc:
|
|
257
|
+
quote(boolean_domain[:true])
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def quoted_false # :nodoc:
|
|
261
|
+
quote(boolean_domain[:false])
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# CONNECTION MANAGEMENT ====================================
|
|
266
|
+
|
|
267
|
+
def active?
|
|
268
|
+
@connection.open?
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def disconnect!
|
|
272
|
+
@connection.close rescue nil
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def reconnect!
|
|
276
|
+
disconnect!
|
|
277
|
+
@connection = Fb::Database.connect(@connection_params)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# DATABASE STATEMENTS ======================================
|
|
281
|
+
|
|
282
|
+
def translate(sql)
|
|
283
|
+
sql.gsub!(/\bIN\s+\(NULL\)/i, 'IS NULL')
|
|
284
|
+
sql.sub!(/\bWHERE\s.*$/im) do |m|
|
|
285
|
+
m.gsub(/\s=\s*NULL\b/i, ' IS NULL')
|
|
286
|
+
end
|
|
287
|
+
sql.gsub!(/\sIN\s+\([^\)]*\)/mi) do |m|
|
|
288
|
+
m.gsub(/\(([^\)]*)\)/m) { |n| n.gsub(/\@(.*?)\@/m) { |n| "'#{quote_string(Base64.decode64(n[1..-1]))}'" } }
|
|
289
|
+
end
|
|
290
|
+
args = []
|
|
291
|
+
sql.gsub!(/\@(.*?)\@/m) { |m| args << Base64.decode64(m[1..-1]); '?' }
|
|
292
|
+
yield(sql, args) if block_given?
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def expand(sql, args)
|
|
296
|
+
sql + ', ' + args * ', '
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def log(sql, args, name, &block)
|
|
300
|
+
super(expand(sql, args), name, &block)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def select_all(sql, name = nil, format = :hash) # :nodoc:
|
|
304
|
+
translate(sql) do |sql, args|
|
|
305
|
+
log(sql, args, name) do
|
|
306
|
+
@connection.query(format, sql, *args)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def select_one(sql, name = nil, format = :hash) # :nodoc:
|
|
312
|
+
translate(sql) do |sql, args|
|
|
313
|
+
log(sql, args, name) do
|
|
314
|
+
@connection.query(format, sql, *args).first
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def execute(sql, name = nil, &block) # :nodoc:
|
|
320
|
+
translate(sql) do |sql, args|
|
|
321
|
+
log(sql, args, name) do
|
|
322
|
+
@connection.execute(sql, *args, &block)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) # :nodoc:
|
|
328
|
+
execute(sql, name)
|
|
329
|
+
id_value
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
alias_method :update, :execute
|
|
333
|
+
alias_method :delete, :execute
|
|
334
|
+
|
|
335
|
+
def begin_db_transaction() # :nodoc:
|
|
336
|
+
@transaction = @connection.transaction('READ COMMITTED')
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def commit_db_transaction() # :nodoc:
|
|
340
|
+
@transaction = @connection.commit
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def rollback_db_transaction() # :nodoc:
|
|
344
|
+
@transaction = @connection.rollback
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def add_lock!(sql, options) # :nodoc:
|
|
348
|
+
sql
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def add_limit_offset!(sql, options) # :nodoc:
|
|
352
|
+
if options[:limit]
|
|
353
|
+
limit_string = "FIRST #{options[:limit]}"
|
|
354
|
+
limit_string << " SKIP #{options[:offset]}" if options[:offset]
|
|
355
|
+
sql.sub!(/\A(\s*SELECT\s)/i, '\&' + limit_string + ' ')
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Returns the next sequence value from a sequence generator. Not generally
|
|
360
|
+
# called directly; used by ActiveRecord to get the next primary key value
|
|
361
|
+
# when inserting a new database record (see #prefetch_primary_key?).
|
|
362
|
+
def next_sequence_value(sequence_name)
|
|
363
|
+
select_one("SELECT GEN_ID(#{sequence_name}, 1) FROM RDB$DATABASE", nil, :array).first
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# SCHEMA STATEMENTS ========================================
|
|
367
|
+
|
|
368
|
+
def columns(table_name, name = nil) # :nodoc:
|
|
369
|
+
sql = <<-END_SQL
|
|
370
|
+
SELECT r.rdb$field_name, r.rdb$field_source, f.rdb$field_type, f.rdb$field_sub_type,
|
|
371
|
+
f.rdb$field_length, f.rdb$field_precision, f.rdb$field_scale,
|
|
372
|
+
COALESCE(r.rdb$default_source, f.rdb$default_source) rdb$default_source,
|
|
373
|
+
COALESCE(r.rdb$null_flag, f.rdb$null_flag) rdb$null_flag
|
|
374
|
+
FROM rdb$relation_fields r
|
|
375
|
+
JOIN rdb$fields f ON r.rdb$field_source = f.rdb$field_name
|
|
376
|
+
WHERE r.rdb$relation_name = '#{table_name.to_s.upcase}'
|
|
377
|
+
ORDER BY r.rdb$field_position
|
|
378
|
+
END_SQL
|
|
379
|
+
select_all(sql, name, :array).collect do |field|
|
|
380
|
+
field_values = field.collect do |value|
|
|
381
|
+
case value
|
|
382
|
+
when String then value.rstrip
|
|
383
|
+
else value
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
FbColumn.new(*field_values)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def tables(name = nil)
|
|
391
|
+
@connection.table_names.map {|t| t.downcase }
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def indexes(table_name, name = nil) #:nodoc:
|
|
395
|
+
result = @connection.indexes.values.select {|ix| ix.table_name == table_name && ix.index_name !~ /^rdb\$/ }
|
|
396
|
+
indexes = result.map {|ix| IndexDefinition.new(table_name, ix.index_name, ix.unique, ix.columns) }
|
|
397
|
+
indexes
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def table_alias_length
|
|
401
|
+
255
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def rename_column(table_name, column_name, new_column_name)
|
|
405
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} TO #{new_column_name}"
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def remove_index(table_name, options = {})
|
|
409
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def supports_migrations?
|
|
413
|
+
false
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def native_database_types
|
|
417
|
+
{
|
|
418
|
+
:primary_key => "integer not null primary key",
|
|
419
|
+
:string => { :name => "varchar", :limit => 255 },
|
|
420
|
+
:text => { :name => "blob sub_type text" },
|
|
421
|
+
:integer => { :name => "integer" },
|
|
422
|
+
:float => { :name => "float" },
|
|
423
|
+
:datetime => { :name => "timestamp" },
|
|
424
|
+
:timestamp => { :name => "timestamp" },
|
|
425
|
+
:time => { :name => "time" },
|
|
426
|
+
:date => { :name => "date" },
|
|
427
|
+
:binary => { :name => "blob" },
|
|
428
|
+
:boolean => { :name => "integer" }
|
|
429
|
+
}
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
private
|
|
433
|
+
# Maps uppercase Firebird column names to lowercase for ActiveRecord;
|
|
434
|
+
# mixed-case columns retain their original case.
|
|
435
|
+
def fb_to_ar_case(column_name)
|
|
436
|
+
column_name =~ /[[:lower:]]/ ? column_name : column_name.downcase
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# Maps lowercase ActiveRecord column names to uppercase for Fierbird;
|
|
440
|
+
# mixed-case columns retain their original case.
|
|
441
|
+
def ar_to_fb_case(column_name)
|
|
442
|
+
column_name =~ /[[:upper:]]/ ? column_name : column_name.upcase
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fb_adapter
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.5.5
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Brent Rowland
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2008-02-27 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description:
|
|
17
|
+
email: rowland@rowlandresearch.com
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files: []
|
|
23
|
+
|
|
24
|
+
files:
|
|
25
|
+
- fb_adapter.gemspec
|
|
26
|
+
- lib/active_record/connection_adapters/fb_adapter.rb
|
|
27
|
+
has_rdoc: false
|
|
28
|
+
homepage: http://www.rowlandresearch.com/ruby/
|
|
29
|
+
post_install_message:
|
|
30
|
+
rdoc_options: []
|
|
31
|
+
|
|
32
|
+
require_paths:
|
|
33
|
+
- lib
|
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: "0"
|
|
39
|
+
version:
|
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: "0"
|
|
45
|
+
version:
|
|
46
|
+
requirements:
|
|
47
|
+
- Firebird library fb
|
|
48
|
+
rubyforge_project: fblib
|
|
49
|
+
rubygems_version: 1.0.1
|
|
50
|
+
signing_key:
|
|
51
|
+
specification_version: 2
|
|
52
|
+
summary: ActiveRecord Firebird Adapter
|
|
53
|
+
test_files: []
|
|
54
|
+
|