activerecord-interbase-adapter 0.1.0
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.
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
## replace the validates_uniqueness_of method because we have to use UPPER and it uses LOWER.
|
3
|
+
|
4
|
+
ActiveRecord::Validations::ClassMethods.class_eval do
|
5
|
+
alias_method :old_validates_uniqueness_of, :validates_uniqueness_of
|
6
|
+
|
7
|
+
def validates_uniqueness_of(*attr_names)
|
8
|
+
configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true }
|
9
|
+
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
10
|
+
|
11
|
+
validates_each(attr_names,configuration) do |record, attr_name, value|
|
12
|
+
if value.nil? || (configuration[:case_sensitive] || !columns_hash[attr_name.to_s].text?)
|
13
|
+
condition_sql = "#{record.class.table_name}.#{attr_name} #{attribute_condition(value)}"
|
14
|
+
condition_params = [value]
|
15
|
+
else
|
16
|
+
condition_sql = "UPPER(#{record.class.table_name}.#{attr_name}) #{attribute_condition(value)}"
|
17
|
+
condition_params = [value.upcase]
|
18
|
+
end
|
19
|
+
if scope = configuration[:scope]
|
20
|
+
Array(scope).map do |scope_item|
|
21
|
+
scope_value = record.send(scope_item)
|
22
|
+
condition_sql << " AND #{record.class.table_name}.#{scope_item} #{attribute_condition(scope_value)}"
|
23
|
+
condition_params << scope_value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
unless record.new_record?
|
27
|
+
condition_sql << " AND #{record.class.table_name}.#{record.class.primary_key} <> ?"
|
28
|
+
condition_params << record.send(:id)
|
29
|
+
end
|
30
|
+
if record.class.find(:first, :conditions => [condition_sql, *condition_params])
|
31
|
+
record.errors.add(attr_name, configuration[:message])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,857 @@
|
|
1
|
+
# Original Firebird code by Ken Kunz <kennethkunz@gmail.com>,
|
2
|
+
# Extensive InterBase modifications by Richard Vowles - Blue Train Software, www.bluetrainsoftware.com
|
3
|
+
# roles functionality added - tested and works
|
4
|
+
#
|
5
|
+
# Updating for Rails 2.0.2
|
6
|
+
|
7
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
8
|
+
require 'active_record/connection_adapters/ibrails_case_fix'
|
9
|
+
require_library_or_gem 'ibruby'
|
10
|
+
|
11
|
+
include IBRuby
|
12
|
+
|
13
|
+
module IBRuby # :nodoc: all
|
14
|
+
class Database
|
15
|
+
|
16
|
+
def self.db_string_for(config)
|
17
|
+
unless config.has_key?(:database)
|
18
|
+
raise ArgumentError, "No database specified. Missing argument: database."
|
19
|
+
end
|
20
|
+
host_string = config.values_at(:host, :service, :port).compact.first(2).join("/") if config[:host]
|
21
|
+
[host_string, config[:database]].join(":")
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.new_from_config(config)
|
25
|
+
db = new db_string_for(config)
|
26
|
+
db.character_set = config[:charset]
|
27
|
+
return db
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.new_from_params(database, host, port, service)
|
31
|
+
db_string = ""
|
32
|
+
if host
|
33
|
+
db_string << host
|
34
|
+
db_string << "/#{service || port}" if service || port
|
35
|
+
db_string << ":"
|
36
|
+
end
|
37
|
+
db_string << database
|
38
|
+
new(db_string)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ActiveRecord
|
44
|
+
class << Base
|
45
|
+
def interbase_connection(config) # :nodoc:
|
46
|
+
unless defined? IBRuby::InterBaseColumn
|
47
|
+
raise AdapterNotFound,
|
48
|
+
'The InterBase adapter requires IBRuby version 0.5.4 or greater; you appear ' <<
|
49
|
+
'to be running an older version -- please update IBRuby (gem install ibruby).'
|
50
|
+
end
|
51
|
+
|
52
|
+
config = config.symbolize_keys
|
53
|
+
|
54
|
+
unless config.has_key?(:database)
|
55
|
+
raise ArgumentError, "No database specified. Missing argument: database."
|
56
|
+
end
|
57
|
+
|
58
|
+
options = config[:charset] ? { IBRuby::Connection::CHARACTER_SET => config[:charset] } : {}
|
59
|
+
options[IBRuby::Connection::ROLE] = config[:role] if config[:role]
|
60
|
+
|
61
|
+
# need to add :role to options
|
62
|
+
connection_params = [config[:username], config[:password], options]
|
63
|
+
db = IBRuby::Database.new( config[:database] )
|
64
|
+
begin
|
65
|
+
connection = db.connect(*connection_params)
|
66
|
+
rescue IBRuby::IBRubyException
|
67
|
+
if config.has_key?(:create_when_missing)
|
68
|
+
IBRuby::Database.create( config[:database], config[:username], config[:password], 4096, config[:charset] )
|
69
|
+
connection = db.connect(*connection_params)
|
70
|
+
else
|
71
|
+
raise
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
ConnectionAdapters::InterBaseAdapter.new(connection, logger, connection_params)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module ConnectionAdapters
|
80
|
+
class InterBaseTableDefinition < TableDefinition
|
81
|
+
attr_reader :pk_field
|
82
|
+
|
83
|
+
def primary_key(name)
|
84
|
+
col_count = @columns ? @columns.size : 0
|
85
|
+
|
86
|
+
column(name, :integer, {:null => false} )
|
87
|
+
|
88
|
+
if col_count != @columns.size # a column got added
|
89
|
+
@pk_field = @columns.last
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class InterBaseColumn < Column # :nodoc:
|
95
|
+
VARCHAR_MAX_LENGTH = 32_765
|
96
|
+
BLOB_MAX_LENGTH = 32_767 # because activerecord has no parameterized inserts/updates!!!!!
|
97
|
+
DEFAULT_STRING_LENGTH = 252 # to allow :string fields to be indexes
|
98
|
+
attr_reader :interBaseColumn
|
99
|
+
|
100
|
+
def initialize(interBaseColumn)
|
101
|
+
@interBaseColumn = interBaseColumn
|
102
|
+
|
103
|
+
@name = InterBaseAdapter.ib_to_ar_case(interBaseColumn.name.downcase)
|
104
|
+
@sql_type = interBaseColumn.to_s
|
105
|
+
@null = !interBaseColumn.not_null
|
106
|
+
@limit = !interBaseColumn.type == IBRuby::InterBaseColumn::BLOB ? BLOB_MAX_LENGTH : interBaseColumn.length
|
107
|
+
@precision = interBaseColumn.precision
|
108
|
+
@scale = interBaseColumn.scale
|
109
|
+
@type = simplified_type(@sql_type)
|
110
|
+
|
111
|
+
@default = typecast_default
|
112
|
+
|
113
|
+
@primary = nil
|
114
|
+
end #def initialize
|
115
|
+
|
116
|
+
def default
|
117
|
+
if !@interBaseColumn.default.nil?
|
118
|
+
if ( [:timestamp, :time, :date].detect() {|val| @type == val } ) &&
|
119
|
+
( @interBaseColumn.default.to_s =~ /^current_/i )
|
120
|
+
request_db_value( @interBaseColumn.default )
|
121
|
+
else
|
122
|
+
@default
|
123
|
+
end
|
124
|
+
else
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
end # def default
|
128
|
+
|
129
|
+
def type_cast(value)
|
130
|
+
retVal = super
|
131
|
+
#puts "type_cast #{@name}:#{@interbase_type} = #{value} ==> #{retVal}"
|
132
|
+
retVal
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
# Submits a _CAST_ query to the database, casting the default value to the specified SQL type.
|
137
|
+
# This enables InterBase to provide an actual value when context variables are used as column
|
138
|
+
# defaults (such as CURRENT_TIMESTAMP).
|
139
|
+
def request_db_value( value )
|
140
|
+
connection = ActiveRecord::Base.active_connections.values.detect { |conn| conn && conn.adapter_name == 'InterBase' }
|
141
|
+
|
142
|
+
if connection
|
143
|
+
type_cast InterBaseMetaFunctions.db_type_cast( conn, value, @sql_type )
|
144
|
+
else
|
145
|
+
raise ConnectionNotEstablished, "No InterBase connections established."
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def typecast_default
|
150
|
+
def_val = nil
|
151
|
+
#puts "interbase default: #{@interBaseColumn.default} name is #{@name}:#{@type}"
|
152
|
+
|
153
|
+
if !@interBaseColumn.default.nil?
|
154
|
+
case @type
|
155
|
+
when :boolean
|
156
|
+
def_val = ( @interBaseColumn.default.to_s.casecmp( 'true' ) == 0)
|
157
|
+
when :string, :text
|
158
|
+
def_val = @interBaseColumn.default.to_s
|
159
|
+
when :integer
|
160
|
+
def_val = @interBaseColumn.default.to_s.to_i
|
161
|
+
when :float
|
162
|
+
def_val = @interBaseColumn.default.to_s.to_f
|
163
|
+
when :text
|
164
|
+
def_val = @interBaseColumn.default.to_s
|
165
|
+
when :timestamp, :time, :date
|
166
|
+
if @interBaseColumn.default =~ /^current_/i
|
167
|
+
def_val = nil
|
168
|
+
else
|
169
|
+
def_val = type_cast(@interBaseColumn.default)
|
170
|
+
end
|
171
|
+
else
|
172
|
+
if ((@interBaseColumn.type == IBRuby::InterBaseColumn::BLOB) && (@interBaseColumn.sub_type == 1 ) )
|
173
|
+
def_val = @interBaseColumn.default.to_s
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#puts "default is #{def_val.class}:#{def_val}"
|
179
|
+
def_val
|
180
|
+
end
|
181
|
+
|
182
|
+
def simplified_type(field_type)
|
183
|
+
case interBaseColumn.type
|
184
|
+
when IBRuby::InterBaseColumn::INTEGER, IBRuby::InterBaseColumn::INT64, IBRuby::InterBaseColumn::SMALLINT
|
185
|
+
:integer
|
186
|
+
when IBRuby::InterBaseColumn::FLOAT, IBRuby::InterBaseColumn::DOUBLE
|
187
|
+
:float
|
188
|
+
when IBRuby::InterBaseColumn::DECIMAL, IBRuby::InterBaseColumn::NUMERIC
|
189
|
+
interBaseColumn.scale == 0 ? :integer : :decimal
|
190
|
+
when IBRuby::InterBaseColumn::TIMESTAMP
|
191
|
+
:timestamp
|
192
|
+
when IBRuby::InterBaseColumn::TIME
|
193
|
+
:time
|
194
|
+
when IBRuby::InterBaseColumn::DATE
|
195
|
+
:date
|
196
|
+
when IBRuby::InterBaseColumn::BLOB
|
197
|
+
interBaseColumn.sub_type == 1 ? :text : :binary
|
198
|
+
when IBRuby::InterBaseColumn::CHAR, IBRuby::InterBaseColumn::VARCHAR
|
199
|
+
:string
|
200
|
+
when IBRuby::InterBaseColumn::BOOLEAN
|
201
|
+
:boolean
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# The InterBase adapter relies on the IBRuby[http://rubyforge.org/projects/ibruby/]
|
207
|
+
# extension, version 0.5.1 or later (available as a gem or from
|
208
|
+
# RubyForge[http://rubyforge.org/projects/ibruby/]). IBRuby works with
|
209
|
+
# InterBase 7.1, 7.5 and 2007 on Linux, Solaris and Win32 platforms.
|
210
|
+
#
|
211
|
+
# == Usage Notes
|
212
|
+
#
|
213
|
+
# === Sequence (Generator) Names
|
214
|
+
# The InterBase adapter supports the same approach adopted for the Oracle & Firebird
|
215
|
+
# adapters. See ActiveRecord::Base#set_sequence_name for more details.
|
216
|
+
#
|
217
|
+
# Note that in general there is no need to create a <tt>BEFORE INSERT</tt>
|
218
|
+
# trigger corresponding to a InterBase sequence generator when using
|
219
|
+
# ActiveRecord. In other words, you don't have to try to make InterBase
|
220
|
+
# simulate an <tt>AUTO_INCREMENT</tt> or +IDENTITY+ column. When saving a
|
221
|
+
# new record, ActiveRecord pre-fetches the next sequence value for the table
|
222
|
+
# and explicitly includes it in the +INSERT+ statement. (Pre-fetching the
|
223
|
+
# next primary key value is the only reliable method for the InterBase
|
224
|
+
# adapter to report back the +id+ after a successful insert.)
|
225
|
+
#
|
226
|
+
# === BLOB Elements
|
227
|
+
# The InterBase adapter currently provides only limited support for +BLOB+
|
228
|
+
# columns. You cannot currently retrieve or insert a +BLOB+ as an IO stream.
|
229
|
+
# When selecting a +BLOB+, the entire element is converted into a String.
|
230
|
+
# When inserting or updating a +BLOB+, the entire value is included in-line
|
231
|
+
# in the SQL statement, limiting you to values <= 32KB in size.
|
232
|
+
#
|
233
|
+
# === Column Name Case Semantics
|
234
|
+
# InterBase and ActiveRecord have somewhat conflicting case semantics for
|
235
|
+
# column names.
|
236
|
+
#
|
237
|
+
# [*InterBase*]
|
238
|
+
# The standard practice is to use unquoted column names, which can be
|
239
|
+
# thought of as case-insensitive. (In fact, InterBase converts them to
|
240
|
+
# uppercase.) Quoted column names (not typically used) are case-sensitive.
|
241
|
+
# [*ActiveRecord*]
|
242
|
+
# Attribute accessors corresponding to column names are case-sensitive.
|
243
|
+
# The defaults for primary key and inheritance columns are lowercase, and
|
244
|
+
# in general, people use lowercase attribute names.
|
245
|
+
#
|
246
|
+
# In order to map between the differing semantics in a way that conforms
|
247
|
+
# to common usage for both InterBase and ActiveRecord, uppercase column names
|
248
|
+
# in InterBase are converted to lowercase attribute names in ActiveRecord,
|
249
|
+
# and vice-versa. Mixed-case column names retain their case in both
|
250
|
+
# directions. Lowercase (quoted) InterBase column names are not supported.
|
251
|
+
# This is similar to the solutions adopted by other adapters.
|
252
|
+
#
|
253
|
+
# In general, the best approach is to use unqouted (case-insensitive) column
|
254
|
+
# names in your InterBase DDL (or if you must quote, use uppercase column
|
255
|
+
# names). These will correspond to lowercase attributes in ActiveRecord.
|
256
|
+
#
|
257
|
+
# For example, a InterBase table based on the following DDL:
|
258
|
+
#
|
259
|
+
# CREATE TABLE products (
|
260
|
+
# id INTEGER NOT NULL PRIMARY KEY,
|
261
|
+
# "type" VARCHAR(50),
|
262
|
+
# name VARCHAR(255) );
|
263
|
+
#
|
264
|
+
# ...will correspond to an ActiveRecord model class called +Product+ with
|
265
|
+
# the following attributes: +id+, +type+, +name+.
|
266
|
+
#
|
267
|
+
# ==== Quoting <tt>"TYPE"</tt> and other InterBase reserved words:
|
268
|
+
# In ActiveRecord, the default inheritance column name is +type+. The word
|
269
|
+
# _type_ is a InterBase reserved word, so it must be quoted in any InterBase
|
270
|
+
# SQL statements. Because of the case mapping described above, you should
|
271
|
+
# always reference this column using quoted-lowercase syntax
|
272
|
+
# (<tt>"type"</tt>) within InterBase DDL or other SQL statements (as in the
|
273
|
+
# example above). This holds true for any other InterBase reserved words used
|
274
|
+
# as column names as well as this driver keeps a list of all reserved words and will
|
275
|
+
# ensure they are not mapped to upper case and they are always used quoted in the database.
|
276
|
+
#
|
277
|
+
# === Migrations
|
278
|
+
# The InterBase adapter does support Migrations.
|
279
|
+
#
|
280
|
+
#
|
281
|
+
# === SQL
|
282
|
+
# ActiveRecord has as part of its test suite syntax which is not strictly compliant with the SQL standard
|
283
|
+
# i.e. field IN (NULL). NULL is not valid in the IN clause, and where this particular part of SQL has appeared
|
284
|
+
# I change it to field IS NULL instead using Ruby's pattern matching
|
285
|
+
#
|
286
|
+
# The same is true of = NULL in the WHERE clause, this is also not SQL standard and in those cases, I break the
|
287
|
+
# SQL statement up into the before WHERE and after WHERE and replace all = NULL after the WHERE with IS NULL. This
|
288
|
+
# is clearly time consuming on the SQL so I really wish they wouldn't do it.
|
289
|
+
#
|
290
|
+
# == Connection Options
|
291
|
+
# The following options are supported by the InterBase adapter. None of the
|
292
|
+
# options have default values.
|
293
|
+
#
|
294
|
+
# <tt>:database</tt>::
|
295
|
+
# <i>Required option.</i> Specifies one of: (i) a InterBase database alias;
|
296
|
+
# (ii) the full path of a database file; _or_ (iii) a full InterBase
|
297
|
+
# connection string. <i>Do not specify <tt>:host</tt>, <tt>:service</tt>
|
298
|
+
# or <tt>:port</tt> as separate options when using a full connection
|
299
|
+
# string.</i>
|
300
|
+
# <tt>:host</tt>::
|
301
|
+
# Set to <tt>"remote.host.name"</tt> for remote database connections.
|
302
|
+
# May be omitted for local connections if a full database path is
|
303
|
+
# specified for <tt>:database</tt>. Some platforms require a value of
|
304
|
+
# <tt>"localhost"</tt> for local connections when using a InterBase
|
305
|
+
# database _alias_.
|
306
|
+
# <tt>:service</tt>::
|
307
|
+
# Specifies a service name for the connection. Only used if <tt>:host</tt>
|
308
|
+
# is provided. Required when connecting to a non-standard service.
|
309
|
+
# <tt>:port</tt>::
|
310
|
+
# Specifies the connection port. Only used if <tt>:host</tt> is provided
|
311
|
+
# and <tt>:service</tt> is not. Required when connecting to a non-standard
|
312
|
+
# port and <tt>:service</tt> is not defined.
|
313
|
+
# <tt>:username</tt>::
|
314
|
+
# Specifies the database user. May be omitted or set to +nil+ (together
|
315
|
+
# with <tt>:password</tt>) to use the underlying operating system user
|
316
|
+
# credentials on supported platforms.
|
317
|
+
# <tt>:password</tt>::
|
318
|
+
# Specifies the database password. Must be provided if <tt>:username</tt>
|
319
|
+
# is explicitly specified; should be omitted if OS user credentials are
|
320
|
+
# are being used.
|
321
|
+
# <tt>:charset</tt>::
|
322
|
+
# Specifies the character set to be used by the connection. Refer to
|
323
|
+
# InterBase documentation for valid options.
|
324
|
+
# <tt>:role</tt>:
|
325
|
+
# Specifies the role that the username is using when connecting to the database (if any)
|
326
|
+
|
327
|
+
class InterBaseAdapter < AbstractAdapter
|
328
|
+
|
329
|
+
# class property
|
330
|
+
@@reserved_words_array = [ "ACTION", "AFTER", "ANY", "AT", "BASED", "BEGIN", "BOOLEAN",
|
331
|
+
"CASCADE", "CHARACTER", "ACTIVE", "ALL", "AS", "AUTO", "BASENAME", "BETWEEN", "BUFFER", "CAST",
|
332
|
+
"CHAR_LENGTH", "ADD", "ALTER", "ASC", "AUTODDL", "BASE_NAME", "BLOB", "BY", "CHAR", "CHECK",
|
333
|
+
"ADMIN", "AND", "ASCENDING", "AVG", "BEFORE", "BLOBEDIT", "CACHE", "CHARACTER", "CHECK_POINT_LEN",
|
334
|
+
"CHECK_POINT_LENGTH", "COLLATE", "COLLATION", "COLUMN", "COMMIT", "COMMITTED", "COMPILETIME",
|
335
|
+
"COMPUTED", "CLOSE", "CONDITIONAL", "CONNECT", "CONSTRAINT", "CONTAINING", "CONTINUE", "COUNT",
|
336
|
+
"CREATE", "CSTRING", "CURRENT", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURSOR", "DATABASE",
|
337
|
+
"DATE", "DAY", "DB_KEY", "DEBUG", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELETE", "DESC", "DESCENDING",
|
338
|
+
"DESCRIBE", "DESCRIPTOR", "DISCONNECT", "DISPLAY", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "ECHO",
|
339
|
+
"EDIT", "ELSE", "END", "ENTRY_POINT", "ESCAPE", "EVENT", "EXCEPTION", "EXECUTE", "EXISTS", "EXIT", "EXTERN",
|
340
|
+
"EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FILE", "FILTER", "FLOAT", "FOR", "FOREIGN", "FOUND", "FREE_IT",
|
341
|
+
"FROM", "FULL", "FUNCTION", "GDSCODE", "GENERATOR", "GEN_ID", "GLOBAL", "GOTO", "GRANT", "GROUP", "GROUP_COMMIT_WAIT",
|
342
|
+
"GROUP_COMMIT_WAIT_TIME", "HAVING", "HELP", "HOUR", "IF", "IMMEDIATE", "IN", "INACTIVE", "INDEX", "INDICATOR",
|
343
|
+
"INIT", "INNER", "INPUT", "INPUT_TYPE", "INSERT", "INT", "INTEGER", "INTO", "IS", "ISOLATION", "ISQL", "JOIN",
|
344
|
+
"KEY", "LC_MESSAGES", "LC_TYPE", "LEFT", "LENGTH", "LEV", "LEVEL", "LIKE", "LOGFILE", "LOG_BUFFER_SIZE",
|
345
|
+
"LOG_BUF_SIZE", "LONG", "MANUAL", "MAX", "MAXIMUM", "MAXIMUM_SEGMENT", "MAX_SEGMENT", "MERGE", "MESSAGE", "MIN",
|
346
|
+
"MINIMUM", "MINUTE", "MODULE_NAME", "MONTH", "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NO", "NOAUTO", "NOT", "NULL",
|
347
|
+
"NUMERIC", "NUM_LOG_BUFS", "NUM_LOG_BUFFERS", "OCTET_LENGTH", "OF", "ON", "ONLY", "OPEN", "OPTION", "OR", "ORDER",
|
348
|
+
"OUTER", "OUTPUT", "OUTPUT_TYPE", "OVERFLOW", "PAGE", "PAGELENGTH", "PAGES", "PAGE_SIZE", "PARAMETER", "PASSWORD",
|
349
|
+
"PERCENT", "PLAN", "POSITION", "POST_EVENT", "PRECISION", "PREPARE", "PRESERVE", "PROCEDURE", "PROTECTED", "PRIMARY",
|
350
|
+
"PRIVILEGES", "PUBLIC", "QUIT", "RAW_PARTITIONS", "READ", "REAL", "RECORD_VERSION", "REFERENCES", "RELEASE", "RESERV",
|
351
|
+
"RESERVING", "RESTRICT", "RETAIN", "RETURN", "RETURNING_VALUES", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROWS",
|
352
|
+
"RUNTIME", "SCHEMA", "SECOND", "SEGMENT", "SELECT", "SET", "SHADOW", "SHARED", "SHELL", "SHOW", "SINGULAR", "SIZE",
|
353
|
+
"SMALLINT", "SNAPSHOT", "SOME", "SORT", "SQLCODE", "SQLERROR", "SQLWARNING", "STABILITY", "STARTING", "STARTS", "STATEMENT",
|
354
|
+
"STATIC", "STATISTICS", "SUB_TYPE", "SUM", "SUSPEND", "TABLE", "TEMPORARY", "TERMINATOR", "THEN", "TIES", "TIME", "TIMESTAMP",
|
355
|
+
"TO", "TRANSACTION", "TRANSLATE", "TRANSLATION", "TRIGGER", "TRIM", "TRUE", "TYPE", "UNCOMMITTED", "UNION", "UNIQUE", "UNKNOWN",
|
356
|
+
"UPDATE", "UPPER", "USER", "USING", "VALUE", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERSION", "VIEW", "WAIT", "WEEKDAY",
|
357
|
+
"WHEN", "WHENEVER", "WHERE", "WHILE", "WITH", "WORK", "WRITE", "YEAR", "YEARDAY"
|
358
|
+
]
|
359
|
+
|
360
|
+
## will turn it into a hash for faster access
|
361
|
+
@@reserved_words_hash = {}
|
362
|
+
|
363
|
+
# You can make a column case sensitive by adding it to the list of reserved words. This method builds the fast hash when first accessed.
|
364
|
+
def self.reserved_words
|
365
|
+
if @@reserved_words_hash.size == 0
|
366
|
+
@@reserved_words_array.each() do |value|
|
367
|
+
@@reserved_words_hash[ value ] = true
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
@@reserved_words_hash
|
372
|
+
end
|
373
|
+
|
374
|
+
def initialize(connection, logger, connection_params=nil)
|
375
|
+
super(connection, logger)
|
376
|
+
@connection_params = connection_params
|
377
|
+
end
|
378
|
+
|
379
|
+
def case_insignificant_uses_lower
|
380
|
+
false
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
def adapter_name # :nodoc:
|
385
|
+
'InterBase'
|
386
|
+
end
|
387
|
+
|
388
|
+
# Returns true for InterBase adapter (since InterBase requires primary key
|
389
|
+
# values to be pre-fetched before insert). See also #next_sequence_value.
|
390
|
+
def prefetch_primary_key?(table_name = nil)
|
391
|
+
true
|
392
|
+
end
|
393
|
+
|
394
|
+
def default_sequence_name(table_name, primary_key) # :nodoc:
|
395
|
+
"#{table_name}_seq"
|
396
|
+
end
|
397
|
+
|
398
|
+
|
399
|
+
# QUOTING ==================================================
|
400
|
+
|
401
|
+
def quote(value, column = nil) # :nodoc:
|
402
|
+
if [Time, DateTime].include?(value.class)
|
403
|
+
"CAST('#{value.strftime("%Y-%m-%d %H:%M:%S")}' AS TIMESTAMP)"
|
404
|
+
else
|
405
|
+
super
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def quote_string(string) # :nodoc:
|
410
|
+
string.gsub(/'/, "''")
|
411
|
+
end
|
412
|
+
|
413
|
+
def quote_column_name(column_name) # :nodoc:
|
414
|
+
if InterBaseAdapter.reserved_words[column_name.to_s.upcase]
|
415
|
+
%Q("#{column_name.to_s.downcase}")
|
416
|
+
else
|
417
|
+
InterBaseAdapter.ar_to_ib_case(column_name)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def quoted_true # :nodoc:
|
422
|
+
'true'
|
423
|
+
#true
|
424
|
+
end
|
425
|
+
|
426
|
+
def quoted_false # :nodoc:
|
427
|
+
'false'
|
428
|
+
#false
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
# CONNECTION MANAGEMENT ====================================
|
433
|
+
|
434
|
+
def active?
|
435
|
+
not @connection.closed?
|
436
|
+
end
|
437
|
+
|
438
|
+
def reconnect!
|
439
|
+
@connection.close
|
440
|
+
@connection = @connection.database.connect(*@connection_params)
|
441
|
+
end
|
442
|
+
|
443
|
+
def disconnect!
|
444
|
+
@connection.close
|
445
|
+
end
|
446
|
+
|
447
|
+
# DATABASE STATEMENTS ======================================
|
448
|
+
|
449
|
+
def interbaseSQL( sql )
|
450
|
+
sql = sql.sub( / (IN|in) \(NULL\)/, ' IS NULL' )
|
451
|
+
# anything after the WHERE clause where we find = NULL, we need replace this with IS NULL
|
452
|
+
if ((sql !=~ /~INSERT /) && (sql =~ /= NULL/) )
|
453
|
+
sqlMatch = / WHERE /
|
454
|
+
matched = sqlMatch.match( sql )
|
455
|
+
if !matched.nil? # this of course will break if the = NULL is in a bit of text
|
456
|
+
sql = matched.pre_match << ' WHERE ' << matched.post_match.gsub( /= NULL/, 'IS NULL' )
|
457
|
+
end
|
458
|
+
end
|
459
|
+
#puts "SQL = #{sql}"
|
460
|
+
sql
|
461
|
+
end
|
462
|
+
|
463
|
+
def select_all(sql, name = nil) # :nodoc:
|
464
|
+
select(sql, name)
|
465
|
+
end
|
466
|
+
|
467
|
+
def select_one(sql, name = nil) # :nodoc:
|
468
|
+
if sql !=~ / ROWS /
|
469
|
+
sql << " ROWS 1 TO 1"
|
470
|
+
end
|
471
|
+
result = select(sql, name)
|
472
|
+
result.nil? ? nil : result.first #first element in array
|
473
|
+
end
|
474
|
+
|
475
|
+
def select_value(sql, name = nil)
|
476
|
+
result = select_one(sql, name)
|
477
|
+
|
478
|
+
result.nil? ? nil : result.values.first
|
479
|
+
end
|
480
|
+
|
481
|
+
def execute(sql, name = nil, &block) # :nodoc:
|
482
|
+
sql = interbaseSQL(sql)
|
483
|
+
#~ begin
|
484
|
+
log(sql, name) do
|
485
|
+
if @transaction
|
486
|
+
#puts "within trans: #{sql}"
|
487
|
+
@connection.execute(sql, @transaction, &block)
|
488
|
+
else
|
489
|
+
#puts "immediate: #{sql}"
|
490
|
+
@connection.execute_immediate(sql, &block)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
#~ rescue Exception => boom
|
494
|
+
#~ puts "sql went boom #{boom.message}"
|
495
|
+
#~ nil
|
496
|
+
#~ end
|
497
|
+
end
|
498
|
+
|
499
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) # :nodoc:
|
500
|
+
execute(sql, name)
|
501
|
+
id_value
|
502
|
+
end
|
503
|
+
|
504
|
+
alias_method :update, :execute
|
505
|
+
alias_method :delete, :execute
|
506
|
+
|
507
|
+
def begin_db_transaction() # :nodoc:
|
508
|
+
#puts "begin_transaction"
|
509
|
+
#~ if @transaction.nil? or !transaction.active?
|
510
|
+
#~ if raw_connection.transactions.size > 0
|
511
|
+
#~ @transaction = raw_connection.transactions[0]
|
512
|
+
#~ else
|
513
|
+
@transaction = @connection.start_transaction
|
514
|
+
#~ end
|
515
|
+
#~ end
|
516
|
+
end
|
517
|
+
|
518
|
+
def commit_db_transaction() # :nodoc:
|
519
|
+
#puts "commit transaction"
|
520
|
+
if @total_count
|
521
|
+
@total_count += 1
|
522
|
+
else
|
523
|
+
@total_count = 0
|
524
|
+
end
|
525
|
+
#raise Exception, 'someone called commit?' if @total_count == 1
|
526
|
+
@transaction.commit unless @transaction.nil? or !@transaction.active?
|
527
|
+
ensure
|
528
|
+
@transaction = nil
|
529
|
+
end
|
530
|
+
|
531
|
+
def rollback_db_transaction() # :nodoc:
|
532
|
+
#puts "rollback transaction"
|
533
|
+
@transaction.rollback unless @transaction.nil? or !@transaction.active?
|
534
|
+
ensure
|
535
|
+
@transaction = nil
|
536
|
+
end
|
537
|
+
|
538
|
+
def add_limit_offset!(sql, options) # :nodoc:
|
539
|
+
if options[:limit]
|
540
|
+
limit_string = " ROWS "
|
541
|
+
offset = options[:offset] ? (options[:offset] + 1) : 1
|
542
|
+
if offset.to_i < 1
|
543
|
+
offset = 1
|
544
|
+
end
|
545
|
+
limit_string << offset.to_s
|
546
|
+
limit = offset.to_i + options[:limit].to_i - 1
|
547
|
+
limit_string << " TO #{limit}"
|
548
|
+
#sql.sub!(/\A(\s*SELECT\s)/i, '\&' + limit_string + ' ')
|
549
|
+
sql << limit_string
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
# Returns the next sequence value from a sequence generator. Not generally
|
554
|
+
# called directly; used by ActiveRecord to get the next primary key value
|
555
|
+
# when inserting a new database record (see #prefetch_primary_key?).
|
556
|
+
def next_sequence_value(sequence_name)
|
557
|
+
IBRuby::Generator.new(sequence_name, @connection).next(1)
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
# SCHEMA STATEMENTS ========================================
|
562
|
+
def supports_migrations?
|
563
|
+
true
|
564
|
+
end
|
565
|
+
|
566
|
+
# should really put this in IBRuby but don't want to change it for the release of 3rdRail
|
567
|
+
def recreate_database!
|
568
|
+
sql = "SELECT rdb$character_set_name FROM rdb$database"
|
569
|
+
charset = execute(sql).to_a.first[0]
|
570
|
+
filename = @connection.database.file
|
571
|
+
disconnect!
|
572
|
+
db = IBRuby::Database.new( filename )
|
573
|
+
db.drop(@connection_params[0], @connection_params[1])
|
574
|
+
db = nil
|
575
|
+
if charset.nil?
|
576
|
+
IBRuby::Database.create(@connection.database.file,
|
577
|
+
@connection_params[0], @connection_params[1], 4096)
|
578
|
+
else
|
579
|
+
IBRuby::Database.create(@connection.database.file,
|
580
|
+
@connection_params[0], @connection_params[1], 4096, charset.rstrip)
|
581
|
+
end
|
582
|
+
db = IBRuby::Database.new( filename )
|
583
|
+
@connection = db.connect( @connection_params[0], @connection_params[1], @connection_params[2] )
|
584
|
+
end
|
585
|
+
|
586
|
+
|
587
|
+
# have to create a sequence for each table because of the "prefetching of the primary key"
|
588
|
+
def create_table(name, options = {})
|
589
|
+
# this from super
|
590
|
+
table_definition = InterBaseTableDefinition.new(self)
|
591
|
+
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
|
592
|
+
|
593
|
+
yield table_definition
|
594
|
+
|
595
|
+
if options[:force]
|
596
|
+
drop_table(name) rescue nil
|
597
|
+
end
|
598
|
+
# to here
|
599
|
+
#
|
600
|
+
# now build the proper IB meta structures
|
601
|
+
columns = []
|
602
|
+
|
603
|
+
table_definition.columns.each() do |col|
|
604
|
+
new_col = IBRuby::InterBaseColumn.new( quote_column_name(col.name), name, rails_type_to_native_type[col.type],
|
605
|
+
nil, !col.null.nil? && !col.null, col.limit, col.precision, col.scale, rails_type_to_native_sub_type[col.type],
|
606
|
+
col.default )
|
607
|
+
|
608
|
+
columns << new_col
|
609
|
+
end
|
610
|
+
|
611
|
+
if ( table_definition.pk_field )
|
612
|
+
pk_constraints = [InterBaseConstraint.new(IBRuby::InterBaseConstraint::PRIMARY_KEY,
|
613
|
+
[table_definition.pk_field.name] ) ]
|
614
|
+
end
|
615
|
+
|
616
|
+
table = InterBaseTable.new(name, columns, nil, pk_constraints )
|
617
|
+
|
618
|
+
table.create_table( raw_connection )
|
619
|
+
|
620
|
+
seq_name = name.to_s + "_SEQ"
|
621
|
+
if !IBRuby::Generator.exists?( seq_name, raw_connection )
|
622
|
+
IBRuby::Generator::create(seq_name, @connection)
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
# should drop the indexes as well as any other meta data associated with this table!
|
627
|
+
def drop_table(name)
|
628
|
+
#puts "transactions? #{@transaction.nil?}"
|
629
|
+
InterBaseTable.new(name).drop_table(raw_connection)
|
630
|
+
|
631
|
+
seq_name = name.to_s + "_SEQ"
|
632
|
+
if IBRuby::Generator.exists?( seq_name, raw_connection )
|
633
|
+
IBRuby::Generator.new(seq_name, @connection).drop
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
def rename_column(table_name, column_name, new_column_name)
|
638
|
+
# will break if there is an index based on this column!
|
639
|
+
#
|
640
|
+
col = InterBaseMetaFunctions.table_fields( raw_connection, table_name.to_s, true, quote_column_name(column_name) )
|
641
|
+
col.rename_column( raw_connection, quote_column_name(new_column_name) )
|
642
|
+
end
|
643
|
+
|
644
|
+
def change_column(table_name, column_name, type, options = {})
|
645
|
+
col = InterBaseMetaFunctions.table_fields( raw_connection, table_name.to_s, true, column_name )
|
646
|
+
|
647
|
+
new_col = col.dup
|
648
|
+
|
649
|
+
if !type.nil?
|
650
|
+
new_col.type = rails_type_to_native_type[type]
|
651
|
+
new_col.sub_type = rails_type_to_native_sub_type[type]
|
652
|
+
end
|
653
|
+
|
654
|
+
push_options_into_ib_column( new_col, options )
|
655
|
+
|
656
|
+
if !options[:default].nil?
|
657
|
+
new_col.default = options[:default]
|
658
|
+
end
|
659
|
+
|
660
|
+
col.change_column( raw_connection, new_col )
|
661
|
+
end
|
662
|
+
|
663
|
+
def change_column_default(table_name, column_name, default)
|
664
|
+
change_column( table_name.to_s, column_name, nil, { :default => default } )
|
665
|
+
end
|
666
|
+
|
667
|
+
def native_database_types #:nodoc
|
668
|
+
{
|
669
|
+
:primary_key => "integer not null PRIMARY KEY",
|
670
|
+
:string => { :name => "varchar", :limit => 252 }, # allows default string to be index (index limit 252 in InterBase)
|
671
|
+
:text => { :name => "blob sub_type 1" },
|
672
|
+
:integer => { :name => "integer" },
|
673
|
+
:float => { :name => "double precision" },
|
674
|
+
:decimal => { :name => "decimal" },
|
675
|
+
:datetime => { :name => "timestamp" },
|
676
|
+
:timestamp => { :name => "timestamp" },
|
677
|
+
:time => { :name => "time" },
|
678
|
+
:date => { :name => "date" },
|
679
|
+
:binary => { :name => "blob" },
|
680
|
+
:boolean => { :name => "boolean" }
|
681
|
+
}
|
682
|
+
end
|
683
|
+
|
684
|
+
def rails_type_to_native_type
|
685
|
+
{
|
686
|
+
:string => IBRuby::InterBaseColumn::VARCHAR,
|
687
|
+
:text => IBRuby::InterBaseColumn::BLOB,
|
688
|
+
:integer => IBRuby::InterBaseColumn::INTEGER,
|
689
|
+
:float => IBRuby::InterBaseColumn::DOUBLE,
|
690
|
+
:decimal => IBRuby::InterBaseColumn::DECIMAL,
|
691
|
+
:datetime => IBRuby::InterBaseColumn::TIMESTAMP,
|
692
|
+
:timestamp => IBRuby::InterBaseColumn::TIMESTAMP,
|
693
|
+
:time => IBRuby::InterBaseColumn::TIME,
|
694
|
+
:date => IBRuby::InterBaseColumn::DATE,
|
695
|
+
:binary => IBRuby::InterBaseColumn::BLOB,
|
696
|
+
:boolean => IBRuby::InterBaseColumn::BOOLEAN
|
697
|
+
}
|
698
|
+
end
|
699
|
+
|
700
|
+
def rails_type_to_native_sub_type
|
701
|
+
{
|
702
|
+
:string => 0,
|
703
|
+
:text => 1,
|
704
|
+
:integer => 0,
|
705
|
+
:float => 0,
|
706
|
+
:decimal => 0, # 0 is decimal, 1 is numeric
|
707
|
+
:datetime => 0,
|
708
|
+
:timestamp => 0,
|
709
|
+
:time => 0,
|
710
|
+
:date => 0,
|
711
|
+
:binary => 0,
|
712
|
+
:boolean => 0
|
713
|
+
}
|
714
|
+
end
|
715
|
+
|
716
|
+
|
717
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
718
|
+
return super unless type.to_s == 'integer'
|
719
|
+
|
720
|
+
if limit.nil? || limit == 4
|
721
|
+
'integer'
|
722
|
+
elsif limit < 4
|
723
|
+
'smallint'
|
724
|
+
else
|
725
|
+
'decimal(#{limit},0)'
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
def add_index(table_name, column_name, options = {})
|
730
|
+
column_names = Array(column_name)
|
731
|
+
index_name = index_name(table_name.to_s, :column => column_names)
|
732
|
+
|
733
|
+
if Hash === options # legacy support, since this param was a string
|
734
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
735
|
+
index_name = options[:name] || index_name
|
736
|
+
else
|
737
|
+
index_type = options
|
738
|
+
end
|
739
|
+
|
740
|
+
columns = column_names.collect() { |col| quote_column_name(col) }
|
741
|
+
|
742
|
+
begin
|
743
|
+
index = IBRuby::InterBaseIndex.new( table_name.to_s, index_name, "UNIQUE".casecmp(index_type) == 0, columns )
|
744
|
+
index.create_index( raw_connection )
|
745
|
+
rescue Exception => indexFailed
|
746
|
+
puts "Warning: Index creation failed #{indexFailed.message} - please read up on InterBase Index size limitations in Operations Guide"
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
def add_column(table_name, column_name, type, options = {})
|
751
|
+
new_col = IBRuby::InterBaseColumn.new( quote_column_name(column_name), table_name.to_s,
|
752
|
+
rails_type_to_native_type[type] )
|
753
|
+
|
754
|
+
new_col.sub_type = rails_type_to_native_sub_type[type]
|
755
|
+
|
756
|
+
push_options_into_ib_column( new_col, options )
|
757
|
+
|
758
|
+
if (new_col.type == IBRuby::InterBaseColumn::VARCHAR) && new_col.length.nil?
|
759
|
+
new_col.length = 255;
|
760
|
+
end
|
761
|
+
|
762
|
+
new_col.default = options[:default]
|
763
|
+
|
764
|
+
#puts "#{new_col.name} precision:#{new_col.precision}:#{new_col.scale}"
|
765
|
+
|
766
|
+
# if ( type == :decimal )
|
767
|
+
# new_col.precision = 10 unless new_col.precision?
|
768
|
+
# new_col.scale = 0 unless new_col.scale?
|
769
|
+
# end
|
770
|
+
|
771
|
+
new_col.add_column(raw_connection)
|
772
|
+
end
|
773
|
+
|
774
|
+
# returns an array of IndexDefinitions which include a string array of columns
|
775
|
+
def indexes(table_name, name = nil) #:nodoc:
|
776
|
+
indices = []
|
777
|
+
|
778
|
+
ibIndices = InterBaseMetaFunctions.indices(raw_connection,table_name.to_s)
|
779
|
+
|
780
|
+
# returns array of InterBaseIndex's
|
781
|
+
ibIndices.each() do |ibIndex|
|
782
|
+
index = IndexDefinition.new(InterBaseAdapter.ib_to_ar_case(ibIndex.table),
|
783
|
+
InterBaseAdapter.ib_to_ar_case(ibIndex.name), ibIndex.unique, [])
|
784
|
+
|
785
|
+
ibIndex.columns.each() do |col|
|
786
|
+
index.columns << InterBaseAdapter.ib_to_ar_case(col.name)
|
787
|
+
end
|
788
|
+
|
789
|
+
indices << index
|
790
|
+
end
|
791
|
+
|
792
|
+
indices
|
793
|
+
end
|
794
|
+
|
795
|
+
# returns a string array of tables!
|
796
|
+
def tables
|
797
|
+
table_names = InterBaseMetaFunctions.table_names(raw_connection)
|
798
|
+
table_names.each() { |table_name| table_name.downcase! }
|
799
|
+
end
|
800
|
+
|
801
|
+
def rename_table(name, new_name)
|
802
|
+
table = IBRuby::InterBaseTable.new(name)
|
803
|
+
table.rename_table(raw_connection, new_name )
|
804
|
+
end
|
805
|
+
|
806
|
+
# no table name specified for InterBase
|
807
|
+
def remove_index(table_name, options = {})
|
808
|
+
InterBaseMetaFunctions.remove_index(raw_connection, index_name(table_name.to_s, options) )
|
809
|
+
end
|
810
|
+
|
811
|
+
def columns(table_name, name = nil) # :nodoc:
|
812
|
+
columns = InterBaseMetaFunctions.table_fields(raw_connection,table_name.to_s,true)
|
813
|
+
|
814
|
+
cols = columns.collect() do |field|
|
815
|
+
ConnectionAdapters::InterBaseColumn.new( field )
|
816
|
+
end
|
817
|
+
|
818
|
+
cols
|
819
|
+
end
|
820
|
+
|
821
|
+
protected
|
822
|
+
## returns an array of hashes
|
823
|
+
def select(sql, name = nil)
|
824
|
+
rs = execute(sql, name)
|
825
|
+
results = rs.collect do |row|
|
826
|
+
hashed_row = {}
|
827
|
+
row.each do |column, value|
|
828
|
+
value = value.to_s if IBRuby::Blob === value
|
829
|
+
hashed_row[InterBaseAdapter.ib_to_ar_case(column)] = value
|
830
|
+
end
|
831
|
+
hashed_row
|
832
|
+
end
|
833
|
+
rs.close # otherwise we temporarily and unnecessarily leak result sets, which lock meta-data
|
834
|
+
results
|
835
|
+
end
|
836
|
+
|
837
|
+
# Maps uppercase InterBase column names to lowercase for ActiveRecord;
|
838
|
+
# mixed-case columns retain their original case.
|
839
|
+
def self.ib_to_ar_case(column_name)
|
840
|
+
column_name =~ /[[:lower:]]/ ? column_name : column_name.to_s.downcase
|
841
|
+
end
|
842
|
+
|
843
|
+
# Maps lowercase ActiveRecord column names to uppercase for Fierbird;
|
844
|
+
# mixed-case columns retain their original case.
|
845
|
+
def self.ar_to_ib_case(column_name)
|
846
|
+
column_name =~ /[[:upper:]]/ ? column_name : column_name.to_s.upcase
|
847
|
+
end
|
848
|
+
|
849
|
+
def push_options_into_ib_column( new_col, options )
|
850
|
+
new_col.length = options[:limit].to_i unless options[:limit].nil?
|
851
|
+
new_col.precision = options[:precision].to_i unless options[:precision].nil?
|
852
|
+
new_col.not_null = options[:null] == false unless options[:null].nil?
|
853
|
+
new_col.scale = options[:scale].to_i unless options[:scale].nil?
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
857
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Richard Vowles - Developers Inc Ltd, www.developers-inc.co.nz
|
2
|
+
# Thank you Matthew Bass!
|
3
|
+
# Basic code taken from http://matthewbass.com/2007/03/07/overriding-existing-rake-tasks/
|
4
|
+
#
|
5
|
+
|
6
|
+
Rake::TaskManager.class_eval do
|
7
|
+
def remove_task(task_name)
|
8
|
+
t_name = task_name.to_s
|
9
|
+
@tasks.delete(t_name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def remove_task(task_name)
|
14
|
+
Rake.application.remove_task(task_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
remove_task( "db:structure:dump" )
|
18
|
+
remove_task( "db:test:clone_structure" )
|
19
|
+
remove_task( "db:test:purge" )
|
20
|
+
remove_task( "db:sessions:create" )
|
21
|
+
|
22
|
+
# now replace the tasks from database.rake
|
23
|
+
namespace :db do
|
24
|
+
namespace :structure do
|
25
|
+
desc "Dump the database structure to a SQL file"
|
26
|
+
task :dump => :environment do
|
27
|
+
abcs = ActiveRecord::Base.configurations
|
28
|
+
case abcs[RAILS_ENV]["adapter"]
|
29
|
+
when "interbase"
|
30
|
+
set_firebird_env(abcs[RAILS_ENV])
|
31
|
+
db_string = IBRuby::Database.db_string_for(abcs[RAILS_ENV].symbolize_keys)
|
32
|
+
sh "isql -a #{db_string} > db/#{RAILS_ENV}_structure.sql"
|
33
|
+
else
|
34
|
+
raise "Task not supported by '#{abcs["test"]["adapter"]}'"
|
35
|
+
end
|
36
|
+
|
37
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
38
|
+
File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end #namespace :structure
|
42
|
+
|
43
|
+
namespace :test do
|
44
|
+
desc "Recreate the test databases from the development structure"
|
45
|
+
task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
|
46
|
+
abcs = ActiveRecord::Base.configurations
|
47
|
+
case abcs["test"]["adapter"]
|
48
|
+
when "interbase"
|
49
|
+
set_firebird_env(abcs["test"]) # actually InterBase ones, Firebird being a fork!
|
50
|
+
db_string = IBRuby::Database.db_string_for(abcs["test"].symbolize_keys)
|
51
|
+
begin
|
52
|
+
## outputs an EOF but don't know why
|
53
|
+
sh "isql -i db/#{RAILS_ENV}_structure.sql #{db_string}"
|
54
|
+
rescue
|
55
|
+
|
56
|
+
end
|
57
|
+
else
|
58
|
+
raise "Task not supported by '#{abcs["test"]["adapter"]}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "Empty the test database"
|
63
|
+
task :purge => :environment do
|
64
|
+
abcs = ActiveRecord::Base.configurations
|
65
|
+
case abcs["test"]["adapter"]
|
66
|
+
when "interbase"
|
67
|
+
ActiveRecord::Base.establish_connection(:test)
|
68
|
+
ActiveRecord::Base.connection.recreate_database!
|
69
|
+
else
|
70
|
+
raise "Task not supported by '#{abcs["test"]["adapter"]}'"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end #namespace :test
|
74
|
+
|
75
|
+
namespace :sessions do
|
76
|
+
desc "Creates a sessions table for use with CGI::Session::ActiveRecordStore"
|
77
|
+
task :create => :environment do
|
78
|
+
raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
|
79
|
+
require 'rails_generator'
|
80
|
+
require 'rails_generator/scripts/generate'
|
81
|
+
Rails::Generator::Scripts::Generate.new.run(["session_migration", ENV["MIGRATION"] || "AddSessions"],
|
82
|
+
:source => "#{RAILS_ROOT}/vendor/plugins/ibrails_plugin/db")
|
83
|
+
end
|
84
|
+
end #namespace :sessions
|
85
|
+
end #namespace :database
|
86
|
+
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: activerecord-interbase-adapter
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2008-01-30 00:00:00 +13:00
|
8
|
+
summary: Rails interface library for the InterBase database.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: richard@bluetrainsoftware.com
|
12
|
+
homepage: http://rubyforge.org/projects/activerecord-interbase-adapter/
|
13
|
+
rubyforge_project:
|
14
|
+
description: requires IBRuby
|
15
|
+
autorequire: ibruby
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform:
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Richard Vowles
|
31
|
+
files:
|
32
|
+
- lib/active_record
|
33
|
+
- lib/active_record/connection_adapters
|
34
|
+
- lib/active_record/connection_adapters/ibrails_case_fix.rb
|
35
|
+
- lib/active_record/connection_adapters/interbase_adapter.rb
|
36
|
+
- lib/tasks
|
37
|
+
- lib/tasks/interbase.rake
|
38
|
+
test_files: []
|
39
|
+
|
40
|
+
rdoc_options:
|
41
|
+
- --main
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
executables: []
|
45
|
+
|
46
|
+
extensions: []
|
47
|
+
|
48
|
+
requirements: []
|
49
|
+
|
50
|
+
dependencies: []
|
51
|
+
|