activerecord-informix-adapter 1.1.1
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,296 @@
|
|
1
|
+
# Copyright (c) 2006-2010, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions
|
6
|
+
# are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer.
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
# notice, this list of conditions and the following disclaimer in the
|
12
|
+
# documentation and/or other materials provided with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
17
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
20
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
23
|
+
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
24
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
25
|
+
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
29
|
+
|
30
|
+
module ActiveRecord
|
31
|
+
class Base
|
32
|
+
def self.informix_connection(config) #:nodoc:
|
33
|
+
require 'informix' unless self.class.const_defined?(:Informix)
|
34
|
+
require 'stringio'
|
35
|
+
|
36
|
+
config = config.symbolize_keys
|
37
|
+
|
38
|
+
database = config[:database].to_s
|
39
|
+
username = config[:username]
|
40
|
+
password = config[:password]
|
41
|
+
db = Informix.connect(database, username, password)
|
42
|
+
ConnectionAdapters::InformixAdapter.new(db, logger)
|
43
|
+
end
|
44
|
+
|
45
|
+
after_save :write_lobs
|
46
|
+
private
|
47
|
+
def write_lobs
|
48
|
+
return if !connection.is_a?(ConnectionAdapters::InformixAdapter)
|
49
|
+
self.class.columns.each do |c|
|
50
|
+
value = self[c.name]
|
51
|
+
next if ![:text, :binary].include? c.type || value.nil? || value == ''
|
52
|
+
connection.raw_connection.execute(<<-end_sql, StringIO.new(value))
|
53
|
+
UPDATE #{self.class.table_name} SET #{c.name} = ?
|
54
|
+
WHERE #{self.class.primary_key} = #{quote_value(id)}
|
55
|
+
end_sql
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end # class Base
|
59
|
+
|
60
|
+
module ConnectionAdapters
|
61
|
+
class InformixColumn < Column
|
62
|
+
def initialize(column)
|
63
|
+
sql_type = make_type(column[:stype], column[:length],
|
64
|
+
column[:precision], column[:scale])
|
65
|
+
super(column[:name], column[:default], sql_type, column[:nullable])
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
IFX_TYPES_SUBSET = %w(CHAR CHARACTER CHARACTER\ VARYING DECIMAL FLOAT
|
70
|
+
LIST LVARCHAR MONEY MULTISET NCHAR NUMERIC
|
71
|
+
NVARCHAR SERIAL SERIAL8 VARCHAR).freeze
|
72
|
+
|
73
|
+
def make_type(type, limit, prec, scale)
|
74
|
+
type.sub!(/money/i, 'DECIMAL')
|
75
|
+
if IFX_TYPES_SUBSET.include? type.upcase
|
76
|
+
if prec == 0
|
77
|
+
"#{type}(#{limit})"
|
78
|
+
else
|
79
|
+
"#{type}(#{prec},#{scale})"
|
80
|
+
end
|
81
|
+
elsif type =~ /datetime/i
|
82
|
+
type = "time" if prec == 6
|
83
|
+
type
|
84
|
+
elsif type =~ /byte/i
|
85
|
+
"binary"
|
86
|
+
else
|
87
|
+
type
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def simplified_type(sql_type)
|
92
|
+
if sql_type =~ /serial/i
|
93
|
+
:primary_key
|
94
|
+
else
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# This adapter requires Ruby/Informix
|
101
|
+
# http://ruby-informix.rubyforge.org
|
102
|
+
#
|
103
|
+
# Options:
|
104
|
+
#
|
105
|
+
# * <tt>:database</tt> -- Defaults to nothing.
|
106
|
+
# * <tt>:username</tt> -- Defaults to nothing.
|
107
|
+
# * <tt>:password</tt> -- Defaults to nothing.
|
108
|
+
|
109
|
+
class InformixAdapter < AbstractAdapter
|
110
|
+
def initialize(db, logger)
|
111
|
+
super
|
112
|
+
@ifx_version = db.version.major.to_i
|
113
|
+
end
|
114
|
+
|
115
|
+
def native_database_types
|
116
|
+
{
|
117
|
+
:primary_key => "serial primary key",
|
118
|
+
:string => { :name => "varchar", :limit => 255 },
|
119
|
+
:text => { :name => "text" },
|
120
|
+
:integer => { :name => "integer" },
|
121
|
+
:float => { :name => "float" },
|
122
|
+
:decimal => { :name => "decimal" },
|
123
|
+
:datetime => { :name => "datetime year to second" },
|
124
|
+
:timestamp => { :name => "datetime year to second" },
|
125
|
+
:time => { :name => "datetime hour to second" },
|
126
|
+
:date => { :name => "date" },
|
127
|
+
:binary => { :name => "byte"},
|
128
|
+
:boolean => { :name => "boolean"}
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def adapter_name
|
133
|
+
'Informix'
|
134
|
+
end
|
135
|
+
|
136
|
+
def prefetch_primary_key?(table_name = nil)
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
def supports_migrations? #:nodoc:
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def default_sequence_name(table, column) #:nodoc:
|
145
|
+
"#{table}_seq"
|
146
|
+
end
|
147
|
+
|
148
|
+
# DATABASE STATEMENTS =====================================
|
149
|
+
def select_all(sql, name = nil)
|
150
|
+
select(sql, name)
|
151
|
+
end
|
152
|
+
|
153
|
+
def select_one(sql, name = nil)
|
154
|
+
add_limit!(sql, :limit => 1)
|
155
|
+
result = select(sql, name)
|
156
|
+
result.first if result
|
157
|
+
end
|
158
|
+
|
159
|
+
def execute(sql, name = nil)
|
160
|
+
log(sql, name) { @connection.immediate(sql) }
|
161
|
+
end
|
162
|
+
|
163
|
+
def prepare(sql, name = nil)
|
164
|
+
log(sql, name) { @connection.prepare(sql) }
|
165
|
+
end
|
166
|
+
|
167
|
+
def insert(sql, name= nil, pk= nil, id_value= nil, sequence_name = nil)
|
168
|
+
execute(sql)
|
169
|
+
id_value
|
170
|
+
end
|
171
|
+
|
172
|
+
alias_method :update, :execute
|
173
|
+
alias_method :delete, :execute
|
174
|
+
|
175
|
+
def begin_db_transaction
|
176
|
+
execute("begin work")
|
177
|
+
end
|
178
|
+
|
179
|
+
def commit_db_transaction
|
180
|
+
@connection.commit
|
181
|
+
end
|
182
|
+
|
183
|
+
def rollback_db_transaction
|
184
|
+
@connection.rollback
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_limit_offset!(sql, options)
|
188
|
+
if options[:limit]
|
189
|
+
limit = "FIRST #{options[:limit]}"
|
190
|
+
# SKIP available only in IDS >= 10
|
191
|
+
offset = @ifx_version >= 10 && options[:offset]? "SKIP #{options[:offset]}": ""
|
192
|
+
sql.sub!(/^select /i,"SELECT #{offset} #{limit} ")
|
193
|
+
end
|
194
|
+
sql
|
195
|
+
end
|
196
|
+
|
197
|
+
def next_sequence_value(sequence_name)
|
198
|
+
select_one("select #{sequence_name}.nextval id from systables where tabid=1")['id']
|
199
|
+
end
|
200
|
+
|
201
|
+
# QUOTING ===========================================
|
202
|
+
def quote_string(string)
|
203
|
+
string.gsub(/\'/, "''")
|
204
|
+
end
|
205
|
+
|
206
|
+
def quote(value, column = nil)
|
207
|
+
if column && [:binary, :text].include?(column.type)
|
208
|
+
return "NULL"
|
209
|
+
end
|
210
|
+
if column && column.type == :date
|
211
|
+
return "'#{value.mon}/#{value.day}/#{value.year}'"
|
212
|
+
end
|
213
|
+
super
|
214
|
+
end
|
215
|
+
|
216
|
+
# SCHEMA STATEMENTS =====================================
|
217
|
+
def tables(name = nil)
|
218
|
+
@connection.cursor(<<-end_sql) do |cur|
|
219
|
+
SELECT tabname FROM systables WHERE tabid > 99 AND tabtype != 'Q'
|
220
|
+
end_sql
|
221
|
+
cur.open.fetch_all.flatten
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def columns(table_name, name = nil)
|
226
|
+
@connection.columns(table_name).map {|col| InformixColumn.new(col) }
|
227
|
+
end
|
228
|
+
|
229
|
+
# MIGRATION =========================================
|
230
|
+
def recreate_database(name)
|
231
|
+
drop_database(name)
|
232
|
+
create_database(name)
|
233
|
+
end
|
234
|
+
|
235
|
+
def drop_database(name)
|
236
|
+
execute("drop database #{name}")
|
237
|
+
end
|
238
|
+
|
239
|
+
def create_database(name)
|
240
|
+
execute("create database #{name}")
|
241
|
+
end
|
242
|
+
|
243
|
+
# XXX
|
244
|
+
def indexes(table_name, name = nil)
|
245
|
+
indexes = []
|
246
|
+
end
|
247
|
+
|
248
|
+
def create_table(name, options = {})
|
249
|
+
super(name, options)
|
250
|
+
execute("CREATE SEQUENCE #{name}_seq")
|
251
|
+
end
|
252
|
+
|
253
|
+
def rename_table(name, new_name)
|
254
|
+
execute("RENAME TABLE #{name} TO #{new_name}")
|
255
|
+
execute("RENAME SEQUENCE #{name}_seq TO #{new_name}_seq")
|
256
|
+
end
|
257
|
+
|
258
|
+
def drop_table(name)
|
259
|
+
super(name)
|
260
|
+
execute("DROP SEQUENCE #{name}_seq")
|
261
|
+
end
|
262
|
+
|
263
|
+
def rename_column(table, column, new_column_name)
|
264
|
+
execute("RENAME COLUMN #{table}.#{column} TO #{new_column_name}")
|
265
|
+
end
|
266
|
+
|
267
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
268
|
+
sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
|
269
|
+
add_column_options!(sql, options)
|
270
|
+
execute(sql)
|
271
|
+
end
|
272
|
+
|
273
|
+
def remove_index(table_name, options = {})
|
274
|
+
execute("DROP INDEX #{index_name(table_name, options)}")
|
275
|
+
end
|
276
|
+
|
277
|
+
# XXX
|
278
|
+
def structure_dump
|
279
|
+
super
|
280
|
+
end
|
281
|
+
|
282
|
+
def structure_drop
|
283
|
+
super
|
284
|
+
end
|
285
|
+
|
286
|
+
private
|
287
|
+
def select(sql, name = nil)
|
288
|
+
sql.gsub!(/=\s*null/i, 'IS NULL')
|
289
|
+
c = log(sql, name) { @connection.cursor(sql) }
|
290
|
+
rows = c.open.fetch_hash_all
|
291
|
+
c.free
|
292
|
+
rows
|
293
|
+
end
|
294
|
+
end #class InformixAdapter < AbstractAdapter
|
295
|
+
end #module ConnectionAdapters
|
296
|
+
end #module ActiveRecord
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activerecord-informix-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerardo Santana Gomez Garrido
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-03 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.15.4.7707
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ruby-informix
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.3
|
34
|
+
version:
|
35
|
+
description: Active Record adapter for connecting to an IBM Informix database
|
36
|
+
email: gerardo.santana@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/active_record/connection_adapters/informix_adapter.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://rails-informix.rubyforge.org/
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project: rails-informix
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Informix adapter for Active Record
|
73
|
+
test_files: []
|
74
|
+
|