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 +2 -3
- data/VERSION +1 -1
- data/lib/sequel/oracle_extensions/schemata.rb +398 -89
- data/sequel_oracle_extensions.gemspec +62 -56
- metadata +17 -13
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,
|
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.
|
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.
|
1
|
+
0.6.0
|
@@ -6,95 +6,343 @@ module Sequel
|
|
6
6
|
module Oracle
|
7
7
|
module DatabaseMethods
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
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(
|
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
|
-
:
|
23
|
-
|
24
|
-
from(:"
|
25
|
-
join(:"
|
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 => (
|
30
|
-
unless
|
31
|
-
pk = from(:
|
32
|
-
where(:c__index_name
|
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
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
57
|
-
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
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(
|
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(
|
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 =
|
364
|
+
ds = ds.limit(1) if constraint_type == 'P'
|
117
365
|
|
118
|
-
# Return the table constraints as
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
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
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = %q{sequel_oracle_extensions}
|
8
|
-
s.version = "0.
|
9
|
-
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-08-
|
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 = [
|
38
|
-
s.rubygems_version = %q{1.
|
39
|
-
s.summary = %q{Oracle MERGE, optimizer hints,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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:
|
5
|
-
prerelease:
|
4
|
+
hash: 7
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
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-
|
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:
|
29
|
+
hash: 99
|
29
30
|
segments:
|
30
31
|
- 3
|
31
|
-
-
|
32
|
+
- 25
|
32
33
|
- 0
|
33
|
-
version: 3.
|
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.
|
108
|
+
rubygems_version: 1.3.7
|
107
109
|
signing_key:
|
108
110
|
specification_version: 3
|
109
|
-
summary: Oracle MERGE, optimizer hints,
|
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
|