activerecord-oracle_enhanced-adapter 1.6.9 → 1.7.0.beta1
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.
- 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
|