drysql 0.2.1 → 0.2.2

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.
@@ -17,13 +17,17 @@ class Module #:nodoc:
17
17
  class #{class_id} < ActiveRecord::Base
18
18
  end
19
19
  end_class_def
20
- if ActiveRecord::Base.table_exists?(class_id)
21
- eval(class_def, TOPLEVEL_BINDING)
22
- ActiveRecord::Base.logger.info("DRYSQL >> GENERATED CLASS: #{class_id} < ActiveRecord::Base")
23
- else
24
- ActiveRecord::Base.logger.error("DRYSQL >> No matching table could be found for class: #{class_id}")
25
- raise NameError
26
- end
20
+ begin
21
+ if ActiveRecord::Base.table_exists?(class_id)
22
+ eval(class_def, TOPLEVEL_BINDING)
23
+ ActiveRecord::Base.logger.info("DRYSQL >> GENERATED CLASS: #{class_id} < ActiveRecord::Base")
24
+ else
25
+ ActiveRecord::Base.logger.error("DRYSQL >> No matching table could be found for class: #{class_id}")
26
+ raise NameError
27
+ end
28
+ rescue ActiveRecord::ConnectionNotEstablished
29
+ throw "Unable to search for matching table for class #{class_id}: no database connection has been established"
30
+ end
27
31
  end
28
32
  const_get(class_id)
29
33
  end
@@ -8,8 +8,8 @@ require 'connection_adapters/mysql_adapter'
8
8
  require 'connection_adapters/postgresql_adapter'
9
9
  require 'connection_adapters/sqlserver_adapter'
10
10
  require 'connection_adapters/oracle_adapter'
11
- if defined?(ActiveRecord::ConnectionAdapters::IBM_DB2Adapter)
12
- require 'connection_adapters/ibm_db2_adapter'
11
+ if defined?(ActiveRecord::ConnectionAdapters::IBM_DBAdapter)
12
+ require 'connection_adapters/ibm_db_adapter'
13
13
  end
14
14
  require 'connection_adapters/abstract/schema_definitions'
15
15
  require 'associations'
@@ -73,27 +73,32 @@ module ActiveRecord
73
73
  # I believe there is value in validating our PK, FK, and counter columns
74
74
  def generate_validations
75
75
  unless @validations
76
- columns.each do |column|
77
-
78
- if !(column.null || column.default_specified? || column.generated?)
79
- self.validates_nullability_of column.name
80
- logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_nullability_of #{column.name}")
76
+ columns.each do |column|
77
+ # Columns are considered nullable if any of the following are true:
78
+ #
79
+ # 1) Column does not have a NOT NULL constraint
80
+ # 2) Column has a default value specified
81
+ # 3) Column is generated
82
+ # (DrySQL makes the assumption that if a column is a PK and of type integer, then it is generated)
83
+ if !(column.is_nullable? || (column.name.upcase == self.primary_key.upcase && column.type == :integer))
84
+ self.validates_nullability_of column.name
85
+ logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_nullability_of :#{column.name}")
81
86
  end
82
87
 
83
- if column.type == :integer
84
- self.validates_numericality_of column.name, :allow_nil => true, :only_integer => true
85
- logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_numericality_of #{column.name}, :allow_nil=>true, :only_integer=>true")
86
- elsif column.number?
87
- self.validates_numericality_of column.name, :allow_nil => true
88
- logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_numericality_of #{column.name}, :allow_nil=>true")
89
- elsif column.text? && column.limit
90
- self.validates_length_of column.name, :allow_nil => true, :maximum => column.limit
91
- logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_length_of #{column.name}, :allow_nil=>true, :maximum=>#{column.limit}")
92
- elsif column.type == :boolean
93
- self.validates_inclusion_of column.name, :in => [true, false], :allow_nil =>true, :message => ActiveRecord::Errors.default_error_messages[:inclusion]
94
- logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_inclusion_of #{column.name}, :in=>[true, false], \
95
- :allow_nil=>true, :message=>ActiveRecord::Errors.default_error_messages[:inclusion]")
96
- end
88
+ if column.type == :integer
89
+ self.validates_numericality_of column.name, :allow_nil => true, :only_integer => true
90
+ logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_numericality_of :#{column.name}, :allow_nil=>true, :only_integer=>true")
91
+ elsif column.number?
92
+ self.validates_numericality_of column.name, :allow_nil => true
93
+ logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_numericality_of :#{column.name}, :allow_nil=>true")
94
+ elsif column.text? && column.limit
95
+ self.validates_length_of column.name, :allow_nil => true, :maximum => column.limit
96
+ logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_length_of :#{column.name}, :allow_nil=>true, :maximum=>#{column.limit}")
97
+ elsif column.type == :boolean
98
+ self.validates_inclusion_of column.name, :in => [true, false], :allow_nil =>true, :message => ActiveRecord::Errors.default_error_messages[:inclusion]
99
+ logger.info("DRYSQL >> GENERATED VALIDATION: #{self.name} validates_inclusion_of :#{column.name}, :in=>[true, false], \
100
+ :allow_nil=>true, :message=>ActiveRecord::Errors.default_error_messages[:inclusion]")
101
+ end
97
102
  end
98
103
  end
99
104
  @validations=true
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: drysql
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.1
7
- date: 2007-02-08 00:00:00 -05:00
6
+ version: 0.2.2
7
+ date: 2007-11-04 00:00:00 -05:00
8
8
  summary: Dynamic, Reflective, Invisible Object-Relational Mapping for Ruby
9
9
  require_paths:
10
10
  - lib
@@ -28,18 +28,18 @@ cert_chain:
28
28
  authors:
29
29
  - Bryan Evans
30
30
  files:
31
- - lib/associations.rb
32
- - lib/base.rb
31
+ - lib/validations.rb
33
32
  - lib/dependencies.rb
33
+ - lib/associations.rb
34
34
  - lib/drysql.rb
35
- - lib/validations.rb
35
+ - lib/base.rb
36
36
  - lib/helpers/string.rb
37
- - lib/connection_adapters/abstract_adapter.rb
38
- - lib/connection_adapters/ibm_db2_adapter.rb
37
+ - lib/connection_adapters/postgresql_adapter.rb
39
38
  - lib/connection_adapters/mysql_adapter.rb
40
39
  - lib/connection_adapters/oracle_adapter.rb
41
- - lib/connection_adapters/postgresql_adapter.rb
42
40
  - lib/connection_adapters/sqlserver_adapter.rb
41
+ - lib/connection_adapters/abstract_adapter.rb
42
+ - lib/connection_adapters/ibm_db_adapter.rb
43
43
  - lib/connection_adapters/abstract/schema_definitions.rb
44
44
  - README
45
45
  test_files: []
@@ -62,5 +62,5 @@ dependencies:
62
62
  requirements:
63
63
  - - ">="
64
64
  - !ruby/object:Gem::Version
65
- version: 1.14.4
65
+ version: 1.15.1
66
66
  version:
@@ -1,432 +0,0 @@
1
- # Most of this code is borrowed from IBM's rails adapter,
2
- # which is authored by Antonio Cangiano
3
- #
4
- # I have made modifications to the IBM adapter code to support DB2 iSeries
5
- # as well as to add features for DrySQL on DB2 LUW
6
-
7
- module ActiveRecord
8
-
9
- # These extensions in ActiveRecord::Base are for iSeries support
10
- class Base
11
-
12
- class << self
13
-
14
- alias_method :ibm_find_one, :find_one
15
- # Finds a record based on the +id+ value. The column associated with the primary key
16
- # can be of a numeric type however DB2 doesn't allow quoted numeric values (e.g WHERE id = '10').
17
- # Therefore this overrides the default method to check for the column type,
18
- # and leaves the value in the query unquoted in cases of numeric columns
19
- def find_one(id, options)
20
- # If the adapter in use is the IBM DB2 Adapter
21
- if connection.kind_of?(ConnectionAdapters::IBM_DB2Adapter)
22
- if !connection.iseries then return ibm_find_one(id, options) end
23
-
24
- conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
25
- # Retrieves the sql type of the column associated to the primary key
26
- cstmt = connection.execute("SELECT coltype FROM SYSCOLUMNS WHERE \
27
- table_name ='#{table_name.upcase}' AND column_name ='#{primary_key.upcase}'")
28
- DB2::fetch_row(cstmt)
29
- primary_key_type = DB2::result(cstmt, 0)
30
-
31
- # Frees the results set associated with the statement
32
- DB2::free_result(cstmt)
33
-
34
- # If the column is a numeric type
35
- if primary_key_type =~ /int|double|real|decimal|numeric/i
36
- # Assign the unquoted id value to san_id
37
- san_id = sanitize_numeric(id)
38
- else
39
- # The column is not numeric, so +sanitize+ it
40
- san_id = sanitize(id)
41
- end
42
-
43
- # Adds the options based on the san_id value
44
- options.update :conditions => "#{table_name}.#{primary_key} = #{san_id}#{conditions}"
45
-
46
- if result = find_initial(options)
47
- result
48
- else
49
- raise RecordNotFound, "Couldn't find #{name} with ID=#{id}#{conditions}"
50
- end
51
- else
52
- # You're not using the IBM DB2 Adapter therefore the default method is recalled
53
- default_find_one(id, options)
54
- end
55
- end
56
-
57
-
58
- alias_method :ibm_find_some, :find_some
59
- # Finds a record based on a list of +ids+. The primary key column type could be numeric,
60
- # and DB2 doesn't allow quoted numeric values. Therefore this version of the method
61
- # checks for the data type and if it's a numeric type the value in the query is unquoted.
62
- # If the column datatype is not numeric, the value is properly quoted/sanitized
63
- def find_some(ids, options)
64
- # If the adapter in use is the IBM DB2 Adapter
65
- if connection.kind_of?(ConnectionAdapters::IBM_DB2Adapter)
66
- if !connection.iseries then return ibm_find_some(ids, options) end
67
-
68
- conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
69
- # Retrieves the sql type of the column associated to the primary key
70
- cstmt = connection.execute("SELECT typename FROM SYSCOLUMNS WHERE \
71
- table_name ='#{table_name.upcase}' AND column_name ='#{primary_key.upcase}'")
72
- DB2::fetch_row(cstmt)
73
- primary_key_type = DB2::result(cstmt, 0)
74
-
75
- # Frees the results set associated with the statement
76
- DB2::free_result(cstmt)
77
-
78
- # If the column is a numeric type
79
- if primary_key_type =~ /int|double|real|decimal|numeric/i
80
- # Generates a comma separated list of ids
81
- ids_list = ids.map {|id| sanitize_numeric(id) }.join(',')
82
- else
83
- # Generates a comma separated list of quoted/sanitized ids
84
- ids_list = ids.map { |id| sanitize(id) }.join(',')
85
- end
86
-
87
- # Adds the options to the query, based on the generated +ids_list+
88
- options.update :conditions => "#{table_name}.#{primary_key} IN (#{ids_list})#{conditions}"
89
-
90
- result = find_every(options)
91
-
92
- if result.size == ids.size
93
- result
94
- else
95
- raise RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids_list})#{conditions}"
96
- end
97
- else
98
- # You're not using the IBM DB2 Adapter therefore the default method is recalled
99
- default_find_some(ids, options)
100
- end
101
- end
102
- end # class << self
103
- end # class Base
104
-
105
-
106
- module ConnectionAdapters
107
-
108
- class IBM_DB2Column < Column
109
- attr_accessor :generated, :default_specified
110
-
111
- def initialize(name, default, generated, sql_type = nil, null = true)
112
- @name, @type, @null = name, simplified_type(sql_type), null
113
- @text = [:string, :text, :binary].include? @type
114
- @sql_type = sql_type
115
- # have to do this one separately because type_cast depends on #type
116
- if !(default.nil? || default.blank?) then @default_specified = true end
117
- @default = type_cast(default)
118
- # Extracts the limit if it's a :string or :text type
119
- @limit = extract_limit(sql_type) if !sql_type.nil? && @text
120
- @primary = nil
121
- @number = [:float, :integer].include? @type
122
- @generated = generated
123
- end
124
-
125
- def default_specified?
126
- @default_specified
127
- end
128
-
129
- def generated?
130
- !(generated.nil? || generated.blank?)
131
- end
132
- end
133
-
134
-
135
- class IBM_DB2Constraint < AbstractTableConstraint
136
-
137
- attr_reader :update_rule, :delete_rule, :referenced_constraint_name
138
-
139
- ISERIES_PRIMARY_KEY_TYPE = "P"
140
- ISERIES_FOREIGN_KEY_TYPE = "F"
141
- ISERIES_UNIQUE_KEY_TYPE = "U"
142
- ISERIES_CHECK_CONSTRAINT_TYPE = "C"
143
-
144
- def initialize(constraint_schema, constraint_name, constraint_type, table_name, column_name,
145
- referenced_constraint_name, referenced_table_name, referenced_column_name, delete_rule)
146
- @constraint_schema = constraint_schema
147
- @constraint_name = constraint_name
148
- @table_name = table_name
149
- @constraint_type = constraint_type
150
- if !column_name.nil? then @column_name = Set.new [column_name.downcase] end
151
- @referenced_table_name = referenced_table_name
152
- @referenced_constraint_name = referenced_constraint_name
153
- @delete_rule = delete_rule
154
- if !referenced_column_name.nil? then @referenced_column_name = referenced_column_name.downcase end
155
- end
156
-
157
- def primary_key?
158
- constraint_type == PRIMARY_KEY_TYPE || constraint_type == ISERIES_PRIMARY_KEY_TYPE
159
- end
160
-
161
- def foreign_key?
162
- constraint_type == FOREIGN_KEY_TYPE || constraint_type == ISERIES_FOREIGN_KEY_TYPE
163
- end
164
-
165
- def component_of_unique_key?
166
- constraint_type == UNIQUE_KEY_TYPE || constraint_type == ISERIES_UNIQUE_KEY_TYPE
167
- end
168
-
169
- def is_member_of_composite?
170
- @column_name.size > 1
171
- end
172
-
173
- def is_foreign_constraint?(table_name)
174
- @table_name.upcase != table_name.upcase
175
- end
176
-
177
- end
178
-
179
-
180
- class IBM_DB2Adapter < AbstractAdapter
181
- attr_reader :iseries
182
-
183
- alias :base_initialize :initialize
184
- def initialize(connection, logger, config)
185
- if (config[:platform] == "iseries")
186
- @iseries = true
187
- logger.info("DRYSQL >> iSeries platform detected")
188
- end
189
- base_initialize(connection, logger, config)
190
- end
191
-
192
-
193
- alias :base_columns :columns
194
- # Returns an array of Column objects for the table specified by +table_name+
195
- # This method re-definition is valid only for iSeries
196
- def columns(table_name, name = nil)
197
- # to_s required because it may be a symbol.
198
- table_name = table_name.to_s.upcase
199
- # Checks if a blank table name has been given.
200
- # If so it returns an empty array
201
- return [] if table_name.strip.empty?
202
- # +columns+ will contain the resulting array
203
- columns = []
204
- if @iseries
205
- sql = "SELECT column_name, dftvalue as column_default, coltype as type, length, nulls, generated FROM SYSCOLUMNS WHERE TBNAME = '#{table_name}' AND DBNAME = '#{@schema.upcase}' ORDER BY colno"
206
- else
207
- sql = "SELECT colname as column_name, default as column_default, typename as type, length, nulls, generated FROM SYSCAT.COLUMNS WHERE TABNAME = '#{table_name}' AND TABSCHEMA = '#{@schema.upcase}' ORDER BY colno"
208
- end
209
- # Statement required to access all the columns information
210
- stmt = execute(sql, name)
211
- # Fetches all the columns and assigns them to col.
212
- # +col+ is an hash with keys/value pairs for a column
213
- while col = DB2::fetch_assoc(stmt)
214
- column_name = col["column_name"].downcase
215
- # Assigns the column default value.
216
- column_default_value = col["column_default"]
217
- # If there is no default value, it assigns NIL
218
- column_default_value = nil if (column_default_value && column_default_value.upcase == 'NULL')
219
- # Removes single quotes from the default value
220
- column_default_value.gsub!(/^'(.*)'$/, '\1') unless column_default_value.nil?
221
- # Assigns the column type
222
- column_type = col["type"].downcase
223
- # Assigns the field length (size) for the column
224
- column_length = col["length"]
225
- # The initializer of the class Column, requires the +column_length+ to be declared between brackets after
226
- # the datatype(e.g VARCHAR(50)) for :string and :text types. If it's a "for bit data" field it does a subsitution in place, if not
227
- # it appends the (column_length) string on the supported data types
228
- unless column_length.nil? || column_length == '' || column_type.sub!(/ \(\) for bit data/i,"(#{column_length}) FOR BIT DATA") || !column_type =~ /char|lob|graphic/i
229
- column_type << "(#{column_length})"
230
- end
231
- # col["NULLABLE"] is 1 if the field is nullable, 0 if not.
232
- column_nullable = col["nulls"] == 'Y' ? true : false
233
- generated = col["generated"]
234
- # Pushes into the array the *IBM_DB2Column* object, created by passing to the initializer
235
- # +column_name+, +default_value+, +column_type+ and +column_nullable+.
236
- columns << IBM_DB2Column.new(column_name, column_default_value, generated, column_type, column_nullable)
237
- end
238
- # Returns the columns array
239
- columns
240
- end
241
-
242
- alias :base_indexes :indexes
243
- # Returns an array of indexes for the given table, skipping the primary key.
244
- # The current implementation accesses SYSINDEXES and QSYS2.SYSKEYS.
245
- # This method is valid only for iSeries
246
- def indexes(table_name, name = nil)
247
- if !@iseries then return base_indexes(table_name, name) end
248
-
249
- # to_s required because +table_name+ may be a symbol.
250
- table_name = table_name.to_s
251
- # Checks if a blank table name has been given.
252
- # If so it returns an empty array of columns.
253
- return [] if table_name.strip.empty?
254
- # +indexes+ will contain the resulting array
255
- indexes = []
256
- # Query used to retrieve all the indexes from the given table
257
- sql = "select * from ((SELECT index_name, is_unique FROM SYSINDEXES WHERE table_name = '#{table_name.upcase}' AND table_schema = '#{@schema.upcase}') \
258
- as IND inner join (select index_name, column_name from QSYS2.SYSKEYS where index_schema='#{@schema.upcase}') as KEYS on (IND.index_name=KEYS.index_name))"
259
- stmt = execute(sql, name)
260
- klass = instance_eval(ActiveRecord::Base.class_name(table_name))
261
- primary_key = klass.primary_key
262
- index_hash = {}
263
- # Fetches all the records available
264
- while table_index = DB2::fetch_assoc(stmt)
265
- # Gets the lowercased index name
266
- index_name = table_index["index_name"].downcase
267
- # Is the index a primary key?
268
- unless index_name.upcase == primary_key.upcase
269
- # Is the index unique?
270
- index_unique = table_index["is_unique"] == 'U'
271
- if index_hash[index_name].nil?
272
- index_hash[index_name] = [index_unique, [column_name]]
273
- else
274
- index_hash[index_name][1] << column_name
275
- end
276
- end
277
- end
278
- # Creates IndexDefinition objects and adds them to the indexes array
279
- index_hash.keys.each do |key|
280
- current_index = index_hash[key]
281
- indexes << IndexDefinition.new(table_name, key, current_index[0], current_index[1])
282
- end
283
-
284
- # Returns the indexes array
285
- return indexes
286
- # Ensures to free the resources associated with the statement
287
- ensure
288
- DB2::free_result(stmt) if stmt
289
- end
290
-
291
-
292
- # DrySQL queries the current schema's System Catalog Views, which contain metadata
293
- # only for those constraints that are defined in the current schema.
294
- #
295
- # If you have inter-schema referential constraints, and I'm not sure why you would or whether
296
- # DB2 even supports this, DrySQL will not detect them and will raise an error.
297
- def constraints(table_name, name = nil)#:nodoc:
298
- constraints = []
299
- if @iseries
300
- return iseries_constraints(table_name, name)
301
- else
302
- sql = "select CST.tabschema, CST.constname, CST.tabname, CST.type, COL.colname, \
303
- REF.constname as foreign_constraint_name, REF.tabname as foreign_table_name, \
304
- REF.refkeyname, REF.reftabname, REF.deleterule, REF.fk_colnames as foreign_columns, \
305
- REF.pk_colnames as referenced_columns from \
306
- ((select * from SYSCAT.TABCONST where tabname='#{table_name}') as CST \
307
- inner join (select colname, constname from SYSCAT.KEYCOLUSE where tabname='#{table_name}') \
308
- as COL on (CST.constname=COL.constname)) left outer join SYSCAT.REFERENCES REF on \
309
- (CST.constname=REF.refkeyname or CST.constname=REF.constname)"
310
- end
311
- results = execute(sql, name)
312
- constraint_name_hash = {}
313
-
314
- # Note that column names in constraint objects are downcased in order to
315
- # be comparable with the column names produced by IBM_DB2Adapter.columns
316
- while row = DB2::fetch_assoc(results)
317
- constraint_name = row['constname']
318
- foreign_constraint_name = row['foreign_constraint_name']
319
-
320
- # Process constraints local to this table
321
- if !constraint_name_hash.has_key?(constraint_name)
322
- current_constraint = IBM_DB2Constraint.new(row['tabschema'], constraint_name, row['type'],
323
- row['tabname'], row['colname'], row['refkeyname'], row['reftabname'],
324
- row['referenced_columns'], row['deleterule'])
325
- constraints << current_constraint
326
- constraint_name_hash[constraint_name] = current_constraint
327
- # This key is a composite
328
- else
329
- current_constraint = constraint_name_hash[constraint_name]
330
- # Unique Keys are currently the only type of composite keys supported
331
- if current_constraint.component_of_unique_key?
332
- current_constraint.column_name.add(row['colname'])
333
- end
334
- end
335
-
336
- # Process constraints that reference this table's local constraints
337
- if !foreign_constraint_name.nil? && !constraint_name_hash.has_key?(foreign_constraint_name)
338
- current_foreign_constraint = IBM_DB2Constraint.new(row['tabschema'], foreign_constraint_name, IBM_DB2Constraint::FOREIGN_KEY_TYPE,
339
- row['foreign_table_name'], row['foreign_columns'], constraint_name, row['tabname'], row['colname'],
340
- row['deleterule'])
341
- constraints << current_foreign_constraint
342
- constraint_name_hash[foreign_constraint_name] = current_foreign_constraint
343
- # Composite FKs are currently not supported
344
- # else
345
- # constraint_name_hash[foreign_constraint_name].column_name.add(row['foreign_column_name'])
346
- end
347
- end
348
- constraints
349
- end
350
-
351
- # This method retrieves constraint information from the iSeries
352
- # information schema views, which DB2 generates automatically
353
- # for a schema when it (the schema) is created.
354
- #
355
- # Note that the old-style iSeries "libraries" that some people consider to
356
- # by synonymous with "schemas" do not get the benefit of the information
357
- # schema views (or journaling, for that matter). DrySQL will not
358
- # play nicely with iSeries libraries unless you create the information
359
- # schema views.
360
- def iseries_constraints(table_name, name = nil)#:nodoc:
361
- constraints = []
362
- sql = "select CST.constraint_schema, CST.constraint_name, CST.table_name, CST.constraint_type, COL.column_name, \
363
- REF.constraint_name as foreign_constraint_name, REF.unique_constraint_name as referenced_constraint_name, \
364
- REF.delete_rule, COLREF.table_name as foreign_table_name, COLREF.column_name as foreign_column_name from \
365
- ((select * from SYSCST where table_name='#{table_name}') as CST \
366
- inner join (select column_name, constraint_name from SYSCSTCOL where table_name='#{table_name}') \
367
- as COL on (CST.constraint_name=COL.constraint_name) left outer join SYSREFCST REF on \
368
- (CST.constraint_name=REF.unique_constraint_name or CST.constraint_name=REF.constraint_name) \
369
- left join SYSCSTCOL AS COLREF on (NOT COLREF.table_name='#{table_name}' AND \
370
- (REF.unique_constraint_name=COLREF.constraint_name or REF.constraint_name=COLREF.constraint_name)))"
371
- results = execute(sql, name)
372
- constraint_name_hash = {}
373
-
374
- # Note that column names in constraint objects are downcased in order to
375
- # be comparable with the column names produced by IBM_DB2Adapter.columns
376
- while row = DB2::fetch_assoc(results)
377
- constraint_name = row['constraint_name']
378
- foreign_constraint_name = row['foreign_constraint_name']
379
-
380
- # Process constraints local to this table
381
- if !constraint_name_hash.has_key?(constraint_name)
382
- current_constraint = IBM_DB2Constraint.new(row['constraint_schema'], constraint_name, row['constraint_type'],
383
- row['table_name'], row['column_name'], row['referenced_constraint_name'], row['foreign_table_name'],
384
- row['foreign_column_name'], row['delete_rule'])
385
- constraints << current_constraint
386
- constraint_name_hash[constraint_name] = current_constraint
387
- # This key is a composite
388
- else
389
- current_constraint = constraint_name_hash[constraint_name]
390
- # Unique Keys are currently the only type of composite keys supported
391
- if current_constraint.component_of_unique_key?
392
- current_constraint.column_name.add(row['column_name'])
393
- end
394
- end
395
-
396
- # Process constraints that reference this table's local constraints
397
- if !foreign_constraint_name.nil? && !constraint_name_hash.has_key?(foreign_constraint_name)
398
- current_foreign_constraint = IBM_DB2Constraint.new(row['constraint_schema'], constraint_name, IBM_DB2Constraint::FOREIGN_KEY_TYPE,
399
- row['foreign_table_name'], row['foreign_column_name'], foreign_constraint_name, row['table_name'], row['column_name'],
400
- row['delete_rule'])
401
- constraints << current_foreign_constraint
402
- constraint_name_hash[foreign_constraint_name] = current_foreign_constraint
403
- # Composite FKs are currently not supported
404
- # else
405
- # constraint_name_hash[foreign_constraint_name].column_name.add(row['foreign_column_name'])
406
- end
407
- end
408
- constraints
409
- end
410
-
411
-
412
- alias :base_last_generated_id :last_generated_id
413
- # Private methods that returns the last automatically generated ID
414
- # on the given +@connection+. This method is required by the +insert+ method
415
- # This method is valid only for iSeries
416
- def last_generated_id
417
- if !@iseries then return base_last_generated_id end
418
-
419
- # Queries the db to obtain the last ID that was automatically generated
420
- stmt = execute("SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1")
421
- # Fetches the only record available (containing the last id)
422
- DB2::fetch_row(stmt)
423
- # Retrieves and returns the result of the query with the last id.
424
- DB2::result(stmt,0)
425
- end
426
- private :last_generated_id
427
-
428
- end
429
-
430
- end
431
-
432
- end