activerecord-informix-adapter 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+