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
+