sequel_oracle_extensions 0.5.5 → 0.6.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.
data/Rakefile CHANGED
@@ -5,14 +5,13 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "sequel_oracle_extensions"
8
- gem.summary = %Q{Oracle MERGE, optimizer hints, an schema extensions for Sequel}
8
+ gem.summary = %Q{Oracle MERGE, optimizer hints, and schema extensions for Sequel}
9
9
  gem.description = %Q{Oracle extensions for Sequel, including MERGE statements, optimizer hints, and schema extensions.}
10
10
  gem.email = "joe@ankhcraft.com"
11
11
  gem.homepage = "http://github.com/joekhoobyar/sequel_oracle_extensions"
12
12
  gem.authors = ["Joe Khoobyar"]
13
- gem.add_dependency "sequel", ">= 3.10.0"
13
+ gem.add_dependency "sequel", ">= 3.25.0"
14
14
  gem.add_development_dependency "rspec", ">= 2.0.0"
15
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
15
  end
17
16
  Jeweler::GemcutterTasks.new
18
17
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.5
1
+ 0.6.0
@@ -6,95 +6,343 @@ module Sequel
6
6
  module Oracle
7
7
  module DatabaseMethods
8
8
 
9
- # Returns the indexes for the given +table+ (or +schema.table+), as an array of hashes.
10
- # By default, it does not return primary keys.
11
- #
12
- # * <tt>:valid</tt> - Only look for indexes that are valid (true) or unusable (false). By default (nil),
13
- # looks for any matching index.
14
- # * <tt>:all</tt> - Returns all indexes, even ones used for primary keys.
15
- def indexes(qualified_table, options={})
9
+ # Specifies index attributes which are considered implicit and, thus, do not require DDL clauses.
10
+ IMPLICIT_INDEX_ATTRIBUTES = { :parallel=>false, :compress=>false, :logging=>true, :visible=>true }
11
+
12
+ # Returns a hash containing expanded table metadata that exposes Oracle-specific table attributes.
13
+ #
14
+ # Basic Attributes:
15
+ # :columns :: a columns subhash derived from a call to the #schema(table,options={}) method
16
+ # :schema_name :: the name of the schema that owns this table
17
+ #
18
+ # Extended Attributes: (NOTE: some of the following attributes may be nil with older OCI clients)
19
+ # :index_only :: is this an index-organized table?
20
+ # :clustered :: is this a clustered table?
21
+ # :partitioned :: is this a partitioned table?
22
+ # :temporary :: is this a global temporary table?
23
+ # :typed :: is this a ... typed table? ( not sure what that means :-/ )
24
+ #
25
+ def table_metadata(table,options={})
26
+ columns = schema table, options
27
+ attributes = columns.instance_eval{ remove_instance_variable :@features }
28
+ attributes[:columns] = Hash[ columns ]
29
+ attributes
30
+ end
31
+
32
+ # Return a hash containing index information for the table. Hash keys are index name symbols
33
+ # and values are subhashes. The superclass method specifies only two keys :columns and :unique.
34
+ # This implementation provides additional keys in the subhash that expose Oracle-specific index attributes.
35
+ #
36
+ # By default, this method does not return the primary key index.
37
+ # Options:
38
+ # :valid :: Filter by status: true => only VALID indexes, false => only UNUSABLE indexes
39
+ # :all :: Return all indexes, including the primary key index.
40
+ #
41
+ # Example(s):
42
+ #
43
+ # DB.indexes(:people)
44
+ # # { :person_gender=>{
45
+ # # :unique=>false,
46
+ # # :valid=>true,
47
+ # # :db_type=>'BITMAP',
48
+ # # :tablespace=>:users,
49
+ # # :partitioned=>false,
50
+ # # :visible=>true,
51
+ # # :compress=>false,
52
+ # # :columns=>[:gender]
53
+ # # },
54
+ # # :person_name=>{
55
+ # # :unique=>false,
56
+ # # :valid=>true,
57
+ # # :db_type=>'NORMAL',
58
+ # # :tablespace=>:users,
59
+ # # :partitioned=>false,
60
+ # # :visible=>true,
61
+ # # :compress=>false,
62
+ # # :columns=>[:last_name, :first_name]
63
+ # # } }
64
+ #
65
+ # # NOTE: Passing :all=>true so we can get the primary key index.
66
+ # DB.indexes(:employees, :all=>true)
67
+ # # { :employee_pk=>{
68
+ # # :unique=>true,
69
+ # # :valid=>true,
70
+ # # :db_type=>'NORMAL',
71
+ # # :tablespace=>:users,
72
+ # # :partitioned=>false,
73
+ # # :visible=>true,
74
+ # # :compress=>false,
75
+ # # :columns=>[:id]
76
+ # # },
77
+ # # :employee_dept=>{
78
+ # # :unique=>false,
79
+ # # :valid=>true,
80
+ # # :db_type=>'BITMAP',
81
+ # # :type=>:bitmap,
82
+ # # :join=>[:dept_id],
83
+ # # :tablespace=>:users,
84
+ # # :partitioned=>false,
85
+ # # :visible=>true,
86
+ # # :compress=>false,
87
+ # # :columns=>[:departments__id]
88
+ # # } }
89
+ def indexes(table, opts={})
16
90
  ds, result = metadata_dataset, []
17
91
  outm = lambda{|k| ds.send :output_identifier, k}
18
- schema, table = ds.schema_and_table(qualified_table).map{|k| k.to_s.send(ds.identifier_input_method) if k}
92
+ schema, table = ds.schema_and_table(table).map{|k| k.to_s.send(ds.identifier_input_method) if k}
93
+ who = schema.nil? ? 'user' : 'all'
19
94
 
20
95
  # Build the dataset and apply filters for introspection of indexes.
21
- ds = ds.select(:i__index_name, :i__index_type, :i__join_index, :i__partitioned,
22
- :i__status, :i__uniqueness, :i__visibility, :i__compression, :i__tablespace_name,
23
- :ic__column_name).
24
- from(:"all_indexes___i").
25
- join(:"all_ind_columns___ic", [ [:index_owner,:owner], [:index_name,:index_name] ]).
96
+ ds = ds.select(:i__index_name, :i__index_type, :i__join_index, :i__partitioned, :i__status,
97
+ :i__uniqueness, :i__visibility, :i__compression, :i__tablespace_name,
98
+ :i__logging, :i__degree, :i__instances, :ic__column_name).
99
+ from(:"#{who}_indexes___i").
100
+ join(:"#{who}_ind_columns___ic", [ [:index_name,:index_name] ]).
26
101
  where(:i__table_name=>table, :i__dropped=>'NO').
27
102
  order(:status.desc, :index_name, :ic__column_position)
28
- ds = ds.where :i__owner => schema unless schema.nil?
29
- ds = ds.where :i__status => (options[:valid] ? 'VALID' : 'UNUSABLE') unless options[:valid].nil?
30
- unless options[:all]
31
- pk = from(:all_constraints.as(:c)).where(:c__constraint_type=>'P').
32
- where(:c__index_name=>:i__index_name, :c__owner=>:i__owner)
103
+ ds = ds.where :i__owner => schema, :c__index_owner => schema unless schema.nil?
104
+ ds = ds.where :i__status => (opts[:valid] ? 'VALID' : 'UNUSABLE') unless opts[:valid].nil?
105
+ unless opts[:all]
106
+ pk = from(:"#{who}_constraints".as(:c)).where(:c__constraint_type=>'P').
107
+ where(:c__index_name => :i__index_name)
108
+ pk = pk.where :c__owner => schema unless schema.nil?
33
109
  ds = ds.where ~pk.exists
34
110
  end
35
111
 
36
- # Return the table constraints as an array of hashes, including a column list.
37
- hash = Hash.new do |h,k|
38
- result.push :index_name=>outm[k], :table_name=>outm[table], :columns=>[]
39
- h[k] = result.last
40
- end
41
- ds.each do |row|
42
- ref = hash[row[:index_name]]
43
- ref[:index_type] = row[:index_type]
44
- ref[:join_index] = row[:join_index]=='YES'
45
- ref[:partitioned] = row[:partitioned]=='YES'
46
- ref[:valid] = row[:status]=='VALID'
47
- ref[:uniqueness] = row[:uniqueness]=='UNIQUE'
48
- ref[:visible] = row[:visibility]=='VISIBLE'
49
- ref[:compression] = row[:compression]!='DISABLED'
50
- ref[:tablespace] = row[:tablespace_name]
51
- ref[:columns] << outm[row[:column_name]]
52
- end
53
- result
112
+ # Collect the indexes as a hash of subhashes, including a column list.
113
+ # As a followup, collect any additional metadata about the indexes (such as bitmap join columns).
114
+ hash, join_indexes = {}, []
115
+ p ds.sql
116
+ ds.each do |row|
117
+ key = :"#{outm[row[:index_name]]}"
118
+ unless subhash = hash[key]
119
+ subhash = hash[key] = {
120
+ :columns=>[], :unique=>(row[:uniqueness]=='UNIQUE'), :logging=>(row[:logging]=='YES'),
121
+ :db_type=>row[:index_type], :valid=>(row[:status]=='VALID'),
122
+ :parallel=>(row[:degree]!='1' || row[:instances]!='1'),
123
+ :tablespace=>:"#{outm[row[:tablespace_name]]}", :partitioned=>(row[:partitioned]=='YES'),
124
+ :visible=>(row[:visibility]=='VISIBLE'), :compress=>(row[:compression]!='DISABLED')
125
+ }
126
+ case subhash[:db_type]; when 'BITMAP','NORMAL'
127
+ subhash[:type] = :"#{subhash[:db_type].downcase}"
128
+ end
129
+ if row[:join_index]=='YES'
130
+ join_indexes << row[:index_name]
131
+ subhash[:join] = []
132
+ end
133
+ end
134
+ subhash[:columns] << :"#{outm[row[:column_name]]}"
135
+ end
136
+ ds = metadata_dataset.from(:"#{who}_join_ind_columns").where(:index_name=>join_indexes)
137
+ ds = ds.where :index_owner => schema unless schema.nil?
138
+ ds.each do |row|
139
+ subhash = hash[:"#{outm[row[:index_name]]}"]
140
+ ref_column = :"#{outm[row[:outer_table_column]]}"
141
+ pos = subhash[:columns].index ref_column
142
+ subhash[:columns][pos] = :"#{outm[row[:outer_table_name]]}__#{ref_column}"
143
+ subhash[:join][pos] = :"#{outm[row[:inner_table_column]]}"
144
+ end
145
+ hash
54
146
  end
55
147
 
56
- # Returns the primary key for the given +table+ (or +schema.table+), as a hash.
57
- #
58
- # * <tt>:enabled</tt> - Only look for keys that are enabled (true) or disabled (false). By default (nil),
59
- # looks for any matching key.
60
- # * <tt>:all</tt> - Return an array of matching keys, instead of the first matching key.
61
- #
62
- def primary_key(qualified_table, options={})
63
- result = table_constraints qualified_table, 'P', options
64
- options[:all] ? result : result.first
148
+ # Returns a hash containing primary key information for the table, or nil if the table has no primary key.
149
+ # Options:
150
+ # :enabled :: Filter by status: true => only ENABLED primary key, false => only DISABLED primary key
151
+ # :validated :: Filter by validation: true => only VALIDATED primary key, false => only NOT VALIDATED primary key
152
+ #
153
+ # Example:
154
+ #
155
+ # DB.primary_key(:people)
156
+ # # { :person_id=>{
157
+ # # :rely=>false,
158
+ # # :enabled=>true,
159
+ # # :validated=>true,
160
+ # # :using_index=>:person_pk,
161
+ # # :columns=>[:id]
162
+ # # } }
163
+ def primary_key(table, options={})
164
+ result = table_constraints table, 'P', options
165
+ return unless result and not result.empty?
166
+ result.values.first.tap{|pk| pk[:name] = result.keys.first }
65
167
  end
66
168
 
67
- # Returns unique constraints defined on the given +table+ (or +schema.table+), as an array of hashes.
68
- #
69
- # * <tt>:enabled</tt> - Only look for keys that are enabled (true) or disabled (false). By default (nil),
70
- # looks for all matching keys.
71
- def unique_keys(qualified_table, options={})
72
- table_constraints qualified_table, 'U', options
169
+ # Return a hash containing unique constraint information for the table. Hash keys are constraint name symbols
170
+ # and values are subhashes. Primary key constraints are _not_ returned by this method.
171
+ # Options:
172
+ # :enabled :: Filter by status: true => only ENABLED unique keys, false => only DISABLED unique keys
173
+ # :validated :: Filter by validation: true => only VALIDATED unique keys, false => only NOT VALIDATED unique keys
174
+ #
175
+ # Example:
176
+ #
177
+ # DB.unique_keys(:people)
178
+ # # { :person_ssn=>{
179
+ # # :rely=>false,
180
+ # # :enabled=>true,
181
+ # # :validated=>true,
182
+ # # :using_index=>:person_ssn_index,
183
+ # # :columns=>[:ssn]
184
+ # # },
185
+ # # :person_dlnum=>{
186
+ # # :rely=>true,
187
+ # # :enabled=>false,
188
+ # # :validated=>false,
189
+ # # :using_index=>nil,
190
+ # # :columns=>[:drivers_license_state, :drivers_license_number]
191
+ # # } }
192
+ def unique_keys(table, options={})
193
+ table_constraints table, 'U', options
73
194
  end
74
195
 
75
- # Returns foreign keys defined on the given +table+ (or +schema.table+), as an array of hashes.
76
- #
77
- # * <tt>:enabled</tt> - Only look for keys that are enabled (true) or disabled (false). By default (nil),
78
- # looks for all matching keys.
79
- def foreign_keys(qualified_table, options={})
80
- table_constraints qualified_table, 'R', options
196
+ # Return a hash containing foreign key information for the table. Hash keys are constraint name symbols
197
+ # and values are subhashes.
198
+ # Options:
199
+ # :enabled :: Filter by status: true => only ENABLED foreign keys, false => only DISABLED foreign keys
200
+ # :validated :: Filter by validation: true => only VALIDATED foreign keys, false => only NOT VALIDATED foreign keys
201
+ #
202
+ # Example:
203
+ #
204
+ # DB.foreign_keys(:employees)
205
+ # # { :employee_manager_fk=>{
206
+ # # :rely=>false,
207
+ # # :enabled=>true,
208
+ # # :validated=>true,
209
+ # # :columns=>[:manager_id],
210
+ # # :ref_constraint=>:manager_pk,
211
+ # # :ref_table=>:managers
212
+ # # },
213
+ # # :employee_department_fk=>{
214
+ # # :rely=>false,
215
+ # # :enabled=>true,
216
+ # # :validated=>true,
217
+ # # :columns=>[:department_id],
218
+ # # :ref_constraint=>:department_pk,
219
+ # # :ref_table=>:departments
220
+ # # } }
221
+ def foreign_keys(table, options={})
222
+ table_constraints table, 'R', options
81
223
  end
82
224
 
83
- # Returns foreign keys that refer to the given +table+ (or +schema.table+), as an array of hashes.
84
- #
85
- # * <tt>:enabled</tt> - Only look for keys that are enabled (true) or disabled (false). By default (nil),
86
- # looks for all matching keys.
87
- def references(qualified_table, options={})
88
- table_constraints qualified_table, 'R', options.merge(:table_name_column=>:t__table_name)
225
+ # Return a hash containing foreign key information for keys that _refer_ to this table. Hash keys are constraint name symbols
226
+ # and values are subhashes. Foreign keys for this table are _not_ returned by this method (unless they are self-referential).
227
+ # Options:
228
+ # :enabled :: Filter by status: true => only ENABLED foreign keys, false => only DISABLED foreign keys
229
+ # :validated :: Filter by validation: true => only VALIDATED foreign keys, false => only NOT VALIDATED foreign keys
230
+ #
231
+ # Example:
232
+ #
233
+ # DB.references(:employees)
234
+ # # { :assignment_employee_fk=>{
235
+ # # :rely=>false,
236
+ # # :enabled=>true,
237
+ # # :validated=>true,
238
+ # # :columns=>[:employee_id],
239
+ # # :ref_constraint=>:employee_pk,
240
+ # # :table=>:assignments
241
+ # # },
242
+ # # :bonus_recipient_fk=>{
243
+ # # :rely=>false,
244
+ # # :enabled=>true,
245
+ # # :validated=>true,
246
+ # # :columns=>[:recipient_id],
247
+ # # :ref_constraint=>:employee_pk,
248
+ # # :table=>:bonuses
249
+ # # } }
250
+ def references(table, options={})
251
+ table_constraints table, 'R', options.merge(:table_name_column=>:t__table_name)
252
+ end
253
+
254
+ private
255
+
256
+ # Overridden because Oracle has slightly different syntax.
257
+ def alter_table_sql(table, op)
258
+ alter_table_op = case op[:op]
259
+ when :add_column
260
+ "ADD #{column_definition_sql(op)}"
261
+ else
262
+ return super(table, op)
263
+ end
264
+ "ALTER TABLE #{quote_schema_table(table)} #{alter_table_op}"
265
+ end
266
+
267
+ # Overridden because Oracle has a 30 character maximum identifier length.
268
+ def default_index_name(table_name, columns)
269
+ schema, table = schema_and_table(table_name)
270
+ ds = DB[:all_indexes].where(:table_name=>table,:dropped=>'NO')
271
+ ds = ds.where :owner=>schema unless schema.nil?
272
+ "#{table[0,25]}_ix%2.2d" % [ds.count + 1]
273
+ end
274
+
275
+ # SQL DDL statement for creating an index for the table with the given name
276
+ # and index specifications.
277
+ def index_definition_sql(table_name, index)
278
+ raise Error, "Partial indexes are not supported for this database" if index[:where]
279
+
280
+ # Basic index creation DDL.
281
+ sql = ["CREATE"]
282
+ case index[:type]
283
+ when :bitmap
284
+ raise Error, "Bitmap indexes cannot be unique" if index[:unique]
285
+ sql << 'BITMAP'
286
+ when NilClass, :normal
287
+ sql << 'UNIQUE' if index[:unique]
288
+ else
289
+ raise Error, "Index type #{index[:type].inspect} is not supported for this database"
290
+ end
291
+ index_name = index[:name] || default_index_name(table_name, index[:columns])
292
+ qualified_table_name = quote_schema_table table_name
293
+ sql << "INDEX #{quote_identifier(index_name)} ON #{qualified_table_name}"
294
+
295
+ # Index columns and join indexes.
296
+ index_join, index_columns = *index.values_at(:join,:columns)
297
+ sql << literal(index_columns)
298
+ if index_join
299
+ raise Error, "Join clauses are only supported for bitmap indexes" if index[:type]!=:bitmap
300
+ sql << "FROM #{qualified_table_name},"
301
+ sql << index_columns.map{|k| quote_identifier schema_and_table(k).first }.uniq.join(', ')
302
+
303
+ # TODO: Document this short-hand syntax: {:columns=>[:ref_table__ref_column], :join=>[:fk_column]}
304
+ if Array===index_join and index_join.length==index_columns.length and index_join.all?{|k| Symbol===k}
305
+ index_join = Hash[ index_join.map{|k| :"#{table_name}__#{k}" }.zip(index_columns) ]
306
+ end
307
+
308
+ sql << "WHERE #{filter_expr(index_join)}"
309
+ end
310
+
311
+ # Index attributes and options.
312
+ sql << 'LOCAL' if index[:partitioned]
313
+ sql << flag_option_sql(index, :parallel)
314
+ sql << flag_option_sql(index, :logging)
315
+ sql << "TABLESPACE #{quote_identifier(index[:tablespace])}" if index[:tablespace]
316
+ sql << flag_option_sql(index, :visible, 'INVISIBLE')
317
+ sql << compress_option_sql(index)
318
+ sql << index[:options] if String === index[:options]
319
+ sql << 'UNUSABLE' if FalseClass === index[:valid]
320
+ sql.compact.join ' '
321
+ end
322
+
323
+ # SQL DDL clause for specifying on/off flags
324
+ def flag_option_sql(attrs, key, off="NO#{key}".upcase, on=key.to_s.upcase, implicit=IMPLICIT_INDEX_ATTRIBUTES[key])
325
+ case attrs[key]
326
+ when NilClass, implicit
327
+ when TrueClass then on
328
+ when FalseClass then off
329
+ else raise Error, "Unsupported or invalid #{key} option"
330
+ end
89
331
  end
90
332
 
91
- private
92
-
333
+ # SQL DDL clause for specifying compression in a table or index.
334
+ def compress_option_sql(attrs)
335
+ case value=attrs[:compress]
336
+ when Fixnum, Integer then "COMPRESS(#{value})"
337
+ else flag_option_sql attrs, :compress
338
+ end
339
+ end
340
+
93
341
  # Internal helper method for introspection of table constraints.
94
- def table_constraints(qualified_table, constraint_type, options={})
342
+ def table_constraints(table, constraint_type, options={})
95
343
  ds, result = metadata_dataset, []
96
344
  outm = lambda{|k| ds.send :output_identifier, k}
97
- schema, table = ds.schema_and_table(qualified_table).map{|k| k.to_s.send(ds.identifier_input_method) if k}
345
+ schema, table = ds.schema_and_table(table).map{|k| k.to_s.send(ds.identifier_input_method) if k}
98
346
  x_cons = schema.nil? ? 'user_cons' : 'all_cons'
99
347
 
100
348
  # Build the dataset and apply filters for introspection of constraints.
@@ -113,31 +361,92 @@ module Sequel
113
361
  else
114
362
  ds = ds.select_more(:c__index_name)
115
363
  end
116
- ds = yield ds, table if block_given?
364
+ ds = ds.limit(1) if constraint_type == 'P'
117
365
 
118
- # Return the table constraints as an array of hashes, including a column list.
119
- hash = Hash.new do |h,k|
120
- result.push :constraint_name=>outm[k], :constraint_type=>constraint_type, :columns=>[]
121
- h[k] = result.last
122
- end
123
- ds.each do |row|
124
- ref = hash[row[:constraint_name]]
125
- ref[:table_name] = outm[row[:table_name]]
126
- ref[:rely] = row[:rely]=='RELY'
127
- ref[:enabled] = row[:status]=='ENABLED'
128
- ref[:validated] = row[:validated]=='VALIDATED'
129
- ref[:columns] << outm[row[:column_name]]
130
-
131
- if row.include? :r_constraint_name
132
- ref[:r_constraint_name] = outm[row[:r_constraint_name]]
133
- ref[:r_table_name] = outm[row[:r_table_name]]
366
+ # Return the table constraints as a hash of subhashes, including a column list.
367
+ hash = {}
368
+ ds.each do |row|
369
+ key = :"#{outm[row[:constraint_name]]}"
370
+ unless subhash = hash[key]
371
+ subhash = hash[key] = {
372
+ :rely=>(row[:rely]=='RELY'), :enabled=>(row[:status]=='ENABLED'),
373
+ :validated=>(row[:validated]=='VALIDATED'), :columns=>[]
374
+ }
375
+ if row.include? :r_constraint_name
376
+ subhash[:ref_constraint] = :"#{outm[row[:r_constraint_name]]}"
377
+ if options[:table_name_column]==:t__table_name
378
+ then subhash[:table] = :"#{outm[row[:table_name]]}"
379
+ else subhash[:ref_table] = :"#{outm[row[:r_table_name]]}"
380
+ end
381
+ elsif row.include? :index_name
382
+ subhash[:using_index] = :"#{outm[row[:index_name]]}"
383
+ end
134
384
  end
135
- if row[:index_name]
136
- ref[:index_name] = outm[row[:index_name]]
137
- end
138
- end
139
- result
385
+ subhash[:columns] << :"#{outm[row[:column_name]]}"
386
+ end
387
+ hash
140
388
  end
389
+ end
390
+
391
+ # Methods that override existing functionality on Sequel::Oracle::Database.
392
+ module DatabaseExtensions
393
+
394
+ private
395
+
396
+ # Implemented in order to override existing functionality on Sequel::Oracle::Database.
397
+ def self.append_features(base)
398
+ instance_methods(false).each do |k|
399
+ base.send :remove_method, k if base.instance_method(k).owner == base
400
+ end
401
+ super
402
+ end
403
+
404
+ public
405
+
406
+ # Overridden to collect additional table-level information from the metadata.
407
+ #
408
+ # See Sequel::Oracle::Database#schema_parse_table for the original implementation.
409
+ def schema_parse_table(table, opts={})
410
+ ds = dataset
411
+ ds.identifier_output_method = :downcase
412
+ schema_and_table = "#{"#{quote_identifier(opts[:schema])}." if opts[:schema]}#{quote_identifier(table)}"
413
+ table_schema = []
414
+ metadata = transaction(opts){|conn| conn.describe_table(schema_and_table)}
415
+ metadata.columns.each do |column|
416
+ table_schema << [
417
+ column.name.downcase.to_sym,
418
+ {
419
+ :type => column.data_type,
420
+ :db_type => column.type_string.split(' ')[0],
421
+ :type_string => column.type_string,
422
+ :charset_form => column.charset_form,
423
+ :char_used => column.char_used?,
424
+ :char_size => column.char_size,
425
+ :data_size => column.data_size,
426
+ :precision => column.precision,
427
+ :scale => column.scale,
428
+ :fsprecision => column.fsprecision,
429
+ :lfprecision => column.lfprecision,
430
+ :allow_null => column.nullable?
431
+ }
432
+ ]
433
+ end
434
+ table_schema.instance_variable_set :@features, {
435
+ :owner => :"#{metadata.obj_schema.downcase}",
436
+ :clustered => (metadata.clustered? rescue nil),
437
+ :temporary => (metadata.is_temporary? rescue nil),
438
+ :partitioned => (metadata.is_temporary? rescue nil),
439
+ :typed => (metadata.is_typed? rescue nil),
440
+ :index_only => (metadata.index_only? rescue nil)
441
+ }
442
+ table_schema
443
+ end
141
444
  end
142
445
  end
143
446
  end
447
+
448
+ Sequel.require 'adapters/oracle' unless defined? ::Sequel::Oracle::Database
449
+ ::Sequel::Oracle::Database.class_eval do
450
+ #remove_method :schema_parse_table
451
+ include ::Sequel::Oracle::DatabaseExtensions
452
+ end
@@ -1,56 +1,62 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{sequel_oracle_extensions}
8
- s.version = "0.5.5"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = [%q{Joe Khoobyar}]
12
- s.date = %q{2011-08-19}
13
- s.description = %q{Oracle extensions for Sequel, including MERGE statements, optimizer hints, and schema extensions.}
14
- s.email = %q{joe@ankhcraft.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".rspec",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "lib/sequel/oracle_extensions.rb",
27
- "lib/sequel/oracle_extensions/hints.rb",
28
- "lib/sequel/oracle_extensions/merge.rb",
29
- "lib/sequel/oracle_extensions/schemata.rb",
30
- "lib/sequel_oracle_extensions.rb",
31
- "sequel_oracle_extensions.gemspec",
32
- "spec/sequel/oracle_extensions/hints_spec.rb",
33
- "spec/sequel/oracle_extensions/merge_spec.rb",
34
- "spec/spec_helper.rb"
35
- ]
36
- s.homepage = %q{http://github.com/joekhoobyar/sequel_oracle_extensions}
37
- s.require_paths = [%q{lib}]
38
- s.rubygems_version = %q{1.8.8}
39
- s.summary = %q{Oracle MERGE, optimizer hints, an schema extensions for Sequel}
40
-
41
- if s.respond_to? :specification_version then
42
- s.specification_version = 3
43
-
44
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
- s.add_runtime_dependency(%q<sequel>, [">= 3.10.0"])
46
- s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
47
- else
48
- s.add_dependency(%q<sequel>, [">= 3.10.0"])
49
- s.add_dependency(%q<rspec>, [">= 2.0.0"])
50
- end
51
- else
52
- s.add_dependency(%q<sequel>, [">= 3.10.0"])
53
- s.add_dependency(%q<rspec>, [">= 2.0.0"])
54
- end
55
- end
56
-
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sequel_oracle_extensions}
8
+ s.version = "0.6.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Joe Khoobyar"]
12
+ s.date = %q{2011-08-24}
13
+ s.description = %q{Oracle extensions for Sequel, including MERGE statements, optimizer hints, and schema extensions.}
14
+ s.email = %q{joe@ankhcraft.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/sequel/oracle_extensions.rb",
27
+ "lib/sequel/oracle_extensions/hints.rb",
28
+ "lib/sequel/oracle_extensions/merge.rb",
29
+ "lib/sequel/oracle_extensions/schemata.rb",
30
+ "lib/sequel_oracle_extensions.rb",
31
+ "sequel_oracle_extensions.gemspec",
32
+ "spec/sequel/oracle_extensions/hints_spec.rb",
33
+ "spec/sequel/oracle_extensions/merge_spec.rb",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/joekhoobyar/sequel_oracle_extensions}
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.7}
39
+ s.summary = %q{Oracle MERGE, optimizer hints, and schema extensions for Sequel}
40
+ s.test_files = [
41
+ "spec/sequel/oracle_extensions/hints_spec.rb",
42
+ "spec/sequel/oracle_extensions/merge_spec.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<sequel>, [">= 3.25.0"])
52
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
53
+ else
54
+ s.add_dependency(%q<sequel>, [">= 3.25.0"])
55
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<sequel>, [">= 3.25.0"])
59
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
60
+ end
61
+ end
62
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel_oracle_extensions
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
5
- prerelease:
4
+ hash: 7
5
+ prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 5
10
- version: 0.5.5
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joe Khoobyar
@@ -15,7 +15,8 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-19 00:00:00 Z
18
+ date: 2011-08-24 00:00:00 -04:00
19
+ default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: sequel
@@ -25,12 +26,12 @@ dependencies:
25
26
  requirements:
26
27
  - - ">="
27
28
  - !ruby/object:Gem::Version
28
- hash: 47
29
+ hash: 99
29
30
  segments:
30
31
  - 3
31
- - 10
32
+ - 25
32
33
  - 0
33
- version: 3.10.0
34
+ version: 3.25.0
34
35
  type: :runtime
35
36
  version_requirements: *id001
36
37
  - !ruby/object:Gem::Dependency
@@ -74,6 +75,7 @@ files:
74
75
  - spec/sequel/oracle_extensions/hints_spec.rb
75
76
  - spec/sequel/oracle_extensions/merge_spec.rb
76
77
  - spec/spec_helper.rb
78
+ has_rdoc: true
77
79
  homepage: http://github.com/joekhoobyar/sequel_oracle_extensions
78
80
  licenses: []
79
81
 
@@ -103,9 +105,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
105
  requirements: []
104
106
 
105
107
  rubyforge_project:
106
- rubygems_version: 1.8.8
108
+ rubygems_version: 1.3.7
107
109
  signing_key:
108
110
  specification_version: 3
109
- summary: Oracle MERGE, optimizer hints, an schema extensions for Sequel
110
- test_files: []
111
-
111
+ summary: Oracle MERGE, optimizer hints, and schema extensions for Sequel
112
+ test_files:
113
+ - spec/sequel/oracle_extensions/hints_spec.rb
114
+ - spec/sequel/oracle_extensions/merge_spec.rb
115
+ - spec/spec_helper.rb