activerecord-oracle_enhanced-adapter 1.6.9 → 1.7.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +10 -11
- data/History.md +126 -14
- data/README.md +9 -6
- data/RUNNING_TESTS.md +1 -1
- data/Rakefile +1 -16
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +15 -52
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +8 -22
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +53 -45
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +6 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +23 -62
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +46 -56
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +35 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +34 -21
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +36 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +174 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +17 -8
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +17 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +160 -178
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +42 -94
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +50 -54
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +15 -11
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +197 -301
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -2
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +25 -0
- data/lib/active_record/oracle_enhanced/type/raw.rb +14 -2
- data/lib/active_record/oracle_enhanced/type/string.rb +28 -0
- data/lib/active_record/oracle_enhanced/type/text.rb +32 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +12 -17
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +113 -135
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +51 -59
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -41
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +6 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +281 -233
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +7 -7
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +10 -10
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +22 -22
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +36 -37
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +86 -46
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +194 -294
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +53 -39
- data/spec/spec_helper.rb +0 -6
- metadata +42 -143
- data/.travis.yml +0 -39
- data/.travis/oracle/download.sh +0 -14
- data/.travis/oracle/install.sh +0 -31
- data/.travis/setup_accounts.sh +0 -9
- data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +0 -40
- data/lib/active_record/oracle_enhanced/type/timestamp.rb +0 -11
- data/spec/spec_config.yaml.template +0 -11
- data/spec/support/alter_system_user_password.sql +0 -2
- data/spec/support/create_oracle_enhanced_users.sql +0 -31
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhanced
|
4
|
+
module OCIQuoting
|
5
|
+
def _type_cast(value)
|
6
|
+
case value
|
7
|
+
when ActiveModel::Type::Binary::Data
|
8
|
+
lob_value = value == '' ? ' ' : value
|
9
|
+
bind_type = OCI8::BLOB
|
10
|
+
ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
|
11
|
+
ora_value.size = 0 if value == ''
|
12
|
+
ora_value
|
13
|
+
when ActiveRecord::OracleEnhanced::Type::Text::Data
|
14
|
+
lob_value = value.to_s == '' ? ' ' : value.to_s
|
15
|
+
bind_type = OCI8::CLOB
|
16
|
+
ora_value = bind_type.new(@connection.raw_oci_connection, lob_value)
|
17
|
+
ora_value.size = 0 if value.to_s == ''
|
18
|
+
ora_value
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ActiveRecord
|
29
|
+
module ConnectionAdapters
|
30
|
+
module OracleEnhanced
|
31
|
+
module Quoting
|
32
|
+
prepend OCIQuoting
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -152,7 +152,7 @@ module ActiveRecord #:nodoc:
|
|
152
152
|
if partial_writes?
|
153
153
|
# Serialized attributes should always be written in case they've been
|
154
154
|
# changed in place.
|
155
|
-
update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.
|
155
|
+
update_using_custom_method(changed | (attributes.keys & self.class.columns.select {|column| column.is_a?(Type::Serialized)}))
|
156
156
|
else
|
157
157
|
update_using_custom_method(attribute_names)
|
158
158
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhanced
|
4
|
+
module Quoting
|
5
|
+
# QUOTING ==================================================
|
6
|
+
#
|
7
|
+
# see: abstract/quoting.rb
|
8
|
+
|
9
|
+
def quote_column_name(name) #:nodoc:
|
10
|
+
name = name.to_s
|
11
|
+
@quoted_column_names[name] ||= begin
|
12
|
+
# if only valid lowercase column characters in name
|
13
|
+
if name =~ /\A[a-z][a-z_0-9\$#]*\Z/
|
14
|
+
"\"#{name.upcase}\""
|
15
|
+
else
|
16
|
+
# remove double quotes which cannot be used inside quoted identifier
|
17
|
+
"\"#{name.gsub('"', '')}\""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This method is used in add_index to identify either column name (which is quoted)
|
23
|
+
# or function based index (in which case function expression is not quoted)
|
24
|
+
def quote_column_name_or_expression(name) #:nodoc:
|
25
|
+
name = name.to_s
|
26
|
+
case name
|
27
|
+
# if only valid lowercase column characters in name
|
28
|
+
when /^[a-z][a-z_0-9\$#]*$/
|
29
|
+
"\"#{name.upcase}\""
|
30
|
+
when /^[a-z][a-z_0-9\$#\-]*$/i
|
31
|
+
"\"#{name}\""
|
32
|
+
# if other characters present then assume that it is expression
|
33
|
+
# which should not be quoted
|
34
|
+
else
|
35
|
+
name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Used only for quoting database links as the naming rules for links
|
40
|
+
# differ from the rules for column names. Specifically, link names may
|
41
|
+
# include periods.
|
42
|
+
def quote_database_link(name)
|
43
|
+
case name
|
44
|
+
when NONQUOTED_DATABASE_LINK
|
45
|
+
%Q("#{name.upcase}")
|
46
|
+
else
|
47
|
+
name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Names must be from 1 to 30 bytes long with these exceptions:
|
52
|
+
# * Names of databases are limited to 8 bytes.
|
53
|
+
# * Names of database links can be as long as 128 bytes.
|
54
|
+
#
|
55
|
+
# Nonquoted identifiers cannot be Oracle Database reserved words
|
56
|
+
#
|
57
|
+
# Nonquoted identifiers must begin with an alphabetic character from
|
58
|
+
# your database character set
|
59
|
+
#
|
60
|
+
# Nonquoted identifiers can contain only alphanumeric characters from
|
61
|
+
# your database character set and the underscore (_), dollar sign ($),
|
62
|
+
# and pound sign (#). Database links can also contain periods (.) and
|
63
|
+
# "at" signs (@). Oracle strongly discourages you from using $ and # in
|
64
|
+
# nonquoted identifiers.
|
65
|
+
NONQUOTED_OBJECT_NAME = /[A-Za-z][A-z0-9$#]{0,29}/
|
66
|
+
NONQUOTED_DATABASE_LINK = /[A-Za-z][A-z0-9$#\.@]{0,127}/
|
67
|
+
VALID_TABLE_NAME = /\A(?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}(?:@#{NONQUOTED_DATABASE_LINK})?\Z/
|
68
|
+
|
69
|
+
# unescaped table name should start with letter and
|
70
|
+
# contain letters, digits, _, $ or #
|
71
|
+
# can be prefixed with schema name
|
72
|
+
# CamelCase table names should be quoted
|
73
|
+
def self.valid_table_name?(name) #:nodoc:
|
74
|
+
name = name.to_s
|
75
|
+
name =~ VALID_TABLE_NAME && !(name =~ /[A-Z]/ && name =~ /[a-z]/) ? true : false
|
76
|
+
end
|
77
|
+
|
78
|
+
def quote_table_name(name) #:nodoc:
|
79
|
+
name, link = name.to_s.split('@')
|
80
|
+
@quoted_table_names[name] ||= [name.split('.').map{|n| quote_column_name(n)}.join('.'), quote_database_link(link)].compact.join('@')
|
81
|
+
end
|
82
|
+
|
83
|
+
def quote_string(s) #:nodoc:
|
84
|
+
s.gsub(/'/, "''")
|
85
|
+
end
|
86
|
+
|
87
|
+
def quote(value, column = nil) #:nodoc:
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
def _quote(value) #:nodoc:
|
92
|
+
case value
|
93
|
+
when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data then
|
94
|
+
"N" << "'#{quote_string(value.to_s)}'"
|
95
|
+
when ActiveModel::Type::Binary::Data then
|
96
|
+
%Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()}
|
97
|
+
when ActiveRecord::OracleEnhanced::Type::Text::Data then
|
98
|
+
%Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'clob' }()}
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def quoted_true #:nodoc:
|
105
|
+
return "'#{self.class.boolean_to_string(true)}'" if emulate_booleans_from_strings
|
106
|
+
"1"
|
107
|
+
end
|
108
|
+
|
109
|
+
def quoted_false #:nodoc:
|
110
|
+
return "'#{self.class.boolean_to_string(false)}'" if emulate_booleans_from_strings
|
111
|
+
"0"
|
112
|
+
end
|
113
|
+
|
114
|
+
def quote_date_with_to_date(value) #:nodoc:
|
115
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
116
|
+
`quote_date_with_to_date` will be deprecated in future version of Oracle enhanced adapter.
|
117
|
+
Also this method should not be called directly. Let Abstract adapter `_quote` method handle it.
|
118
|
+
MSG
|
119
|
+
# should support that composite_primary_keys gem will pass date as string
|
120
|
+
value = quoted_date(value) if value.acts_like?(:date) || value.acts_like?(:time)
|
121
|
+
"TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
|
122
|
+
end
|
123
|
+
|
124
|
+
def quote_timestamp_with_to_timestamp(value) #:nodoc:
|
125
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
126
|
+
`quote_timestamp_with_to_timestamp` will be deprecated in future version of Oracle enhanced adapter.
|
127
|
+
Also this method should not be called directly. Let Abstract adapter `_quote` method handle it.
|
128
|
+
MSG
|
129
|
+
# add up to 9 digits of fractional seconds to inserted time
|
130
|
+
value = "#{quoted_date(value)}:#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
|
131
|
+
"TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS:FF6')"
|
132
|
+
end
|
133
|
+
|
134
|
+
# Cast a +value+ to a type that the database understands.
|
135
|
+
def type_cast(value, column = nil)
|
136
|
+
super
|
137
|
+
end
|
138
|
+
|
139
|
+
def _type_cast(value)
|
140
|
+
case value
|
141
|
+
when true, false
|
142
|
+
#if emulate_booleans_from_strings || column && column.type == :string
|
143
|
+
if emulate_booleans_from_strings
|
144
|
+
self.class.boolean_to_string(value)
|
145
|
+
else
|
146
|
+
value ? 1 : 0
|
147
|
+
end
|
148
|
+
when Date, Time
|
149
|
+
if value.acts_like?(:time)
|
150
|
+
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
151
|
+
value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
|
152
|
+
else
|
153
|
+
value
|
154
|
+
end
|
155
|
+
when ActiveRecord::OracleEnhanced::Type::NationalCharacterString::Data
|
156
|
+
value.to_s
|
157
|
+
else
|
158
|
+
super
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# if MRI or YARV
|
167
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
|
168
|
+
require 'active_record/connection_adapters/oracle_enhanced/oci_quoting'
|
169
|
+
# if JRuby
|
170
|
+
elsif RUBY_ENGINE == 'jruby'
|
171
|
+
require 'active_record/connection_adapters/oracle_enhanced/jdbc_quoting'
|
172
|
+
else
|
173
|
+
raise "Unsupported Ruby engine #{RUBY_ENGINE}"
|
174
|
+
end
|
@@ -19,21 +19,27 @@ module ActiveRecord
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def visit_TableDefinition(o)
|
22
|
-
create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE "
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
create_sql = "CREATE#{' GLOBAL TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
|
23
|
+
statements = o.columns.map { |c| accept c }
|
24
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
25
|
+
|
26
|
+
if supports_foreign_keys?
|
27
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
28
|
+
end
|
29
|
+
|
30
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
26
31
|
|
27
32
|
unless o.temporary
|
28
33
|
@lob_tablespaces.each do |lob_column, tablespace|
|
29
34
|
create_sql << " LOB (#{quote_column_name(lob_column)}) STORE AS (TABLESPACE #{tablespace}) \n"
|
30
35
|
end if defined?(@lob_tablespaces)
|
31
|
-
create_sql << " ORGANIZATION #{o.
|
32
|
-
if (tablespace = o.
|
36
|
+
create_sql << " ORGANIZATION #{o.organization}" if o.organization
|
37
|
+
if (tablespace = o.tablespace || default_tablespace_for(:table))
|
33
38
|
create_sql << " TABLESPACE #{tablespace}"
|
34
39
|
end
|
35
40
|
end
|
36
|
-
create_sql
|
41
|
+
add_table_options!(create_sql, table_options(o))
|
42
|
+
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
37
43
|
create_sql
|
38
44
|
end
|
39
45
|
|
@@ -50,7 +56,7 @@ module ActiveRecord
|
|
50
56
|
if type == :text
|
51
57
|
sql << " DEFAULT #{@conn.quote(options[:default])}"
|
52
58
|
else
|
53
|
-
sql << " DEFAULT #{
|
59
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}"
|
54
60
|
end
|
55
61
|
end
|
56
62
|
# must explicitly add NULL or NOT NULL to allow change_column to work on migrations
|
@@ -63,6 +69,9 @@ module ActiveRecord
|
|
63
69
|
if options[:as].present?
|
64
70
|
sql << " AS (#{options[:as]})"
|
65
71
|
end
|
72
|
+
if options[:primary_key] == true
|
73
|
+
sql << " PRIMARY KEY"
|
74
|
+
end
|
66
75
|
end
|
67
76
|
|
68
77
|
def action_sql(action, dependency)
|
@@ -26,25 +26,26 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
|
29
|
-
attr_accessor :
|
29
|
+
attr_accessor :parameters, :statement_parameters, :tablespace
|
30
30
|
|
31
|
-
def initialize(table, name, unique, type, parameters, statement_parameters, tablespace
|
32
|
-
@table = table
|
33
|
-
@name = name
|
34
|
-
@unique = unique
|
35
|
-
@type = type
|
31
|
+
def initialize(table, name, unique, columns, lengths, orders, where, type, using, parameters, statement_parameters, tablespace)
|
36
32
|
@parameters = parameters
|
37
33
|
@statement_parameters = statement_parameters
|
38
34
|
@tablespace = tablespace
|
39
|
-
|
40
|
-
super(table, name, unique, columns, nil, nil, nil, nil)
|
35
|
+
super(table, name, unique, columns, lengths, orders, where, type, using)
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
44
|
-
class
|
39
|
+
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
|
40
|
+
|
41
|
+
end
|
45
42
|
|
46
|
-
|
47
|
-
|
43
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
44
|
+
attr_accessor :tablespace, :organization
|
45
|
+
def initialize(name, temporary = false, options = nil, as = nil, tablespace = nil, organization = nil, comment: nil)
|
46
|
+
@tablespace = tablespace
|
47
|
+
@organization = organization
|
48
|
+
super(name, temporary, options, as, comment: comment)
|
48
49
|
end
|
49
50
|
|
50
51
|
def virtual(* args)
|
@@ -69,6 +70,11 @@ module ActiveRecord
|
|
69
70
|
super(name, type, options)
|
70
71
|
end
|
71
72
|
|
73
|
+
private
|
74
|
+
def create_column_definition(name, type)
|
75
|
+
OracleEnhanced::ColumnDefinition.new name, type
|
76
|
+
end
|
77
|
+
|
72
78
|
end
|
73
79
|
|
74
80
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
@@ -1,225 +1,207 @@
|
|
1
1
|
module ActiveRecord #:nodoc:
|
2
2
|
module ConnectionAdapters #:nodoc:
|
3
|
-
module
|
3
|
+
module OracleEnhanced #:nodoc:
|
4
|
+
module SchemaDumper #:nodoc:
|
4
5
|
|
5
|
-
|
6
|
-
base.class_eval do
|
7
|
-
private
|
8
|
-
alias_method_chain :tables, :oracle_enhanced
|
9
|
-
alias_method_chain :indexes, :oracle_enhanced
|
10
|
-
alias_method_chain :foreign_keys, :oracle_enhanced
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
6
|
+
private
|
15
7
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
8
|
+
def tables(stream)
|
9
|
+
# do not include materialized views in schema dump - they should be created separately after schema creation
|
10
|
+
sorted_tables = (@connection.data_sources - @connection.materialized_views).sort
|
11
|
+
sorted_tables.each do |tbl|
|
12
|
+
# add table prefix or suffix for schema_migrations
|
13
|
+
next if ignored? tbl
|
14
|
+
# change table name inspect method
|
15
|
+
tbl.extend TableInspect
|
16
|
+
table(tbl, stream)
|
17
|
+
# add primary key trigger if table has it
|
18
|
+
primary_key_trigger(tbl, stream)
|
19
|
+
end
|
20
|
+
# following table definitions
|
21
|
+
# add foreign keys if table has them
|
22
|
+
sorted_tables.each do |tbl|
|
23
|
+
next if ignored? tbl
|
24
|
+
foreign_keys(tbl, stream)
|
23
25
|
end
|
24
|
-
end
|
25
|
-
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
# do not include materialized views in schema dump - they should be created separately after schema creation
|
30
|
-
sorted_tables = (@connection.tables - @connection.materialized_views).sort
|
31
|
-
sorted_tables.each do |tbl|
|
32
|
-
# add table prefix or suffix for schema_migrations
|
33
|
-
next if ignore_table? tbl
|
34
|
-
# change table name inspect method
|
35
|
-
tbl.extend TableInspect
|
36
|
-
oracle_enhanced_table(tbl, stream)
|
37
|
-
# add primary key trigger if table has it
|
38
|
-
primary_key_trigger(tbl, stream)
|
39
|
-
end
|
40
|
-
# following table definitions
|
41
|
-
# add foreign keys if table has them
|
42
|
-
sorted_tables.each do |tbl|
|
43
|
-
next if ignore_table? tbl
|
44
|
-
foreign_keys(tbl, stream)
|
27
|
+
# add synonyms in local schema
|
28
|
+
synonyms(stream)
|
45
29
|
end
|
46
30
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
stream.print " add_primary_key_trigger #{table_name.inspect}"
|
55
|
-
stream.print ", primary_key: \"#{pk}\"" if pk != 'id'
|
56
|
-
stream.print "\n\n"
|
31
|
+
def primary_key_trigger(table_name, stream)
|
32
|
+
if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
|
33
|
+
pk, _pk_seq = @connection.pk_and_sequence_for(table_name)
|
34
|
+
stream.print " add_primary_key_trigger #{table_name.inspect}"
|
35
|
+
stream.print ", primary_key: \"#{pk}\"" if pk != 'id'
|
36
|
+
stream.print "\n\n"
|
37
|
+
end
|
57
38
|
end
|
58
|
-
end
|
59
39
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, force: true"
|
73
|
-
stream.puts
|
40
|
+
def synonyms(stream)
|
41
|
+
if @connection.respond_to?(:synonyms)
|
42
|
+
syns = @connection.synonyms
|
43
|
+
syns.each do |syn|
|
44
|
+
next if ignored? syn.name
|
45
|
+
table_name = syn.table_name
|
46
|
+
table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
|
47
|
+
table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
|
48
|
+
stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, force: true"
|
49
|
+
stream.puts
|
50
|
+
end
|
51
|
+
stream.puts unless syns.empty?
|
74
52
|
end
|
75
|
-
stream.puts unless syns.empty?
|
76
53
|
end
|
77
|
-
end
|
78
54
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
if (indexes = @connection.indexes(table)).any?
|
87
|
-
add_index_statements = indexes.map do |index|
|
88
|
-
case index.type
|
89
|
-
when nil
|
90
|
-
# use table.inspect as it will remove prefix and suffix
|
91
|
-
statement_parts = [ ('add_index ' + table.inspect) ]
|
92
|
-
statement_parts << index.columns.inspect
|
93
|
-
statement_parts << ('name: ' + index.name.inspect)
|
94
|
-
statement_parts << 'unique: true' if index.unique
|
95
|
-
statement_parts << 'tablespace: ' + index.tablespace.inspect if index.tablespace
|
96
|
-
when 'CTXSYS.CONTEXT'
|
97
|
-
if index.statement_parameters
|
98
|
-
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
99
|
-
statement_parts << index.statement_parameters
|
100
|
-
else
|
101
|
-
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
55
|
+
def indexes(table, stream)
|
56
|
+
if (indexes = @connection.indexes(table)).any?
|
57
|
+
add_index_statements = indexes.map do |index|
|
58
|
+
case index.type
|
59
|
+
when nil
|
60
|
+
# use table.inspect as it will remove prefix and suffix
|
61
|
+
statement_parts = [ ('add_index ' + table.inspect) ]
|
102
62
|
statement_parts << index.columns.inspect
|
103
63
|
statement_parts << ('name: ' + index.name.inspect)
|
64
|
+
statement_parts << 'unique: true' if index.unique
|
65
|
+
statement_parts << 'tablespace: ' + index.tablespace.inspect if index.tablespace
|
66
|
+
when 'CTXSYS.CONTEXT'
|
67
|
+
if index.statement_parameters
|
68
|
+
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
69
|
+
statement_parts << index.statement_parameters
|
70
|
+
else
|
71
|
+
statement_parts = [ ('add_context_index ' + table.inspect) ]
|
72
|
+
statement_parts << index.columns.inspect
|
73
|
+
statement_parts << ('name: ' + index.name.inspect)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
# unrecognized index type
|
77
|
+
statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
|
104
78
|
end
|
105
|
-
|
106
|
-
# unrecognized index type
|
107
|
-
statement_parts = ["# unrecognized index #{index.name.inspect} with type #{index.type.inspect}"]
|
79
|
+
' ' + statement_parts.join(', ')
|
108
80
|
end
|
109
|
-
' ' + statement_parts.join(', ')
|
110
|
-
end
|
111
81
|
|
112
|
-
|
113
|
-
|
82
|
+
stream.puts add_index_statements.sort.join("\n")
|
83
|
+
stream.puts
|
84
|
+
end
|
114
85
|
end
|
115
|
-
end
|
116
86
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
87
|
+
def table(table, stream)
|
88
|
+
columns = @connection.columns(table)
|
89
|
+
begin
|
90
|
+
tbl = StringIO.new
|
121
91
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
92
|
+
# first dump primary key column
|
93
|
+
if @connection.respond_to?(:primary_keys)
|
94
|
+
pk = @connection.primary_keys(table)
|
95
|
+
pk = pk.first unless pk.size > 1
|
96
|
+
else
|
97
|
+
pk = @connection.primary_key(table)
|
98
|
+
end
|
128
99
|
|
129
|
-
|
100
|
+
tbl.print " create_table #{table.inspect}"
|
130
101
|
|
131
|
-
|
132
|
-
|
102
|
+
# addition to make temporary option work
|
103
|
+
tbl.print ", temporary: true" if @connection.temporary_table?(table)
|
133
104
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
105
|
+
table_comments = @connection.table_comment(table)
|
106
|
+
unless table_comments.nil?
|
107
|
+
tbl.print ", comment: #{table_comments.inspect}"
|
108
|
+
end
|
138
109
|
|
139
|
-
|
140
|
-
|
141
|
-
tbl.print
|
110
|
+
case pk
|
111
|
+
when String
|
112
|
+
tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id'
|
113
|
+
pkcol = columns.detect { |c| c.name == pk }
|
114
|
+
pkcolspec = @connection.column_spec_for_primary_key(pkcol)
|
115
|
+
if pkcolspec.present?
|
116
|
+
pkcolspec.each do |key, value|
|
117
|
+
tbl.print ", #{key}: #{value}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
when Array
|
121
|
+
tbl.print ", primary_key: #{pk.inspect}"
|
122
|
+
else
|
123
|
+
tbl.print ", id: false"
|
142
124
|
end
|
143
|
-
else
|
144
|
-
tbl.print ", id: false"
|
145
|
-
end
|
146
|
-
tbl.print ", force: :cascade"
|
147
|
-
tbl.puts " do |t|"
|
148
125
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
126
|
+
tbl.print ", force: :cascade"
|
127
|
+
tbl.puts " do |t|"
|
128
|
+
|
129
|
+
# then dump all non-primary key columns
|
130
|
+
column_specs = columns.map do |column|
|
131
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
132
|
+
next if column.name == pk
|
133
|
+
@connection.column_spec(column)
|
134
|
+
end.compact
|
135
|
+
|
136
|
+
# find all migration keys used in this table
|
137
|
+
#
|
138
|
+
# TODO `& column_specs.map(&:keys).flatten` should be executed
|
139
|
+
# in migration_keys_with_oracle_enhanced
|
140
|
+
keys = @connection.migration_keys & column_specs.map(&:keys).flatten
|
155
141
|
|
156
|
-
|
157
|
-
|
158
|
-
# TODO `& column_specs.map(&:keys).flatten` should be executed
|
159
|
-
# in migration_keys_with_oracle_enhanced
|
160
|
-
keys = @connection.migration_keys & column_specs.map(&:keys).flatten
|
142
|
+
# figure out the lengths for each column based on above keys
|
143
|
+
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
161
144
|
|
162
|
-
|
163
|
-
|
145
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
146
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
164
147
|
|
165
|
-
|
166
|
-
|
148
|
+
# find the max length for the 'type' column, which is special
|
149
|
+
type_length = column_specs.map{ |column| column[:type].length }.max
|
167
150
|
|
168
|
-
|
169
|
-
|
151
|
+
# add column type definition to our format string
|
152
|
+
format_string.unshift " t.%-#{type_length}s "
|
170
153
|
|
171
|
-
|
172
|
-
format_string.unshift " t.%-#{type_length}s "
|
154
|
+
format_string *= ''
|
173
155
|
|
174
|
-
|
156
|
+
# dirty hack to replace virtual_type: with type:
|
157
|
+
column_specs.each do |colspec|
|
158
|
+
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
159
|
+
values.unshift colspec[:type]
|
160
|
+
tbl.print((format_string % values).gsub(/,\s*$/, '').gsub(/virtual_type:/, "type:"))
|
161
|
+
tbl.puts
|
162
|
+
end
|
175
163
|
|
176
|
-
|
177
|
-
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
178
|
-
values.unshift colspec[:type]
|
179
|
-
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
164
|
+
tbl.puts " end"
|
180
165
|
tbl.puts
|
166
|
+
|
167
|
+
indexes(table, tbl)
|
168
|
+
|
169
|
+
tbl.rewind
|
170
|
+
stream.print tbl.read
|
171
|
+
rescue => e
|
172
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
173
|
+
stream.puts "# #{e.message}"
|
174
|
+
stream.puts
|
181
175
|
end
|
182
176
|
|
183
|
-
|
184
|
-
tbl.puts
|
185
|
-
|
186
|
-
indexes(table, tbl)
|
187
|
-
|
188
|
-
tbl.rewind
|
189
|
-
stream.print tbl.read
|
190
|
-
rescue => e
|
191
|
-
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
192
|
-
stream.puts "# #{e.message}"
|
193
|
-
stream.puts
|
177
|
+
stream
|
194
178
|
end
|
195
|
-
|
196
|
-
stream
|
197
|
-
end
|
198
179
|
|
199
|
-
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
# remove table name prefix and suffix when doing #inspect (which is used in tables method)
|
204
|
-
module TableInspect #:nodoc:
|
205
|
-
def inspect
|
206
|
-
remove_prefix_and_suffix(self)
|
180
|
+
def remove_prefix_and_suffix(table)
|
181
|
+
table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
|
207
182
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
183
|
+
|
184
|
+
# remove table name prefix and suffix when doing #inspect (which is used in tables method)
|
185
|
+
module TableInspect #:nodoc:
|
186
|
+
def inspect
|
187
|
+
remove_prefix_and_suffix(self)
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
def remove_prefix_and_suffix(table_name)
|
192
|
+
if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix.to_s.gsub('$','\$')}(.*)#{ActiveRecord::Base.table_name_suffix.to_s.gsub('$','\$')}\Z/
|
193
|
+
"\"#{$1}\""
|
194
|
+
else
|
195
|
+
"\"#{table_name}\""
|
196
|
+
end
|
215
197
|
end
|
216
198
|
end
|
217
|
-
end
|
218
199
|
|
200
|
+
end
|
219
201
|
end
|
220
202
|
end
|
221
|
-
end
|
222
203
|
|
223
|
-
|
224
|
-
|
204
|
+
class SchemaDumper #:nodoc:
|
205
|
+
prepend ConnectionAdapters::OracleEnhanced::SchemaDumper
|
206
|
+
end
|
225
207
|
end
|