activerecord-oracle_enhanced-adapter 1.4.2.rc1 → 1.4.2.rc2

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### 1.4.2.rc2 / 2013-03-01
2
+
3
+ * Bug fixes:
4
+ * Do not consider the numeric attribute as changed if the old value is zero and the new value is not a string [#247]
5
+ * Removed table_name_prefix and table_name_suffix when schema dumper executed [#248]
6
+ * Remove_column should raise an ArgumentError when no columns are passed [#246]
7
+ * Don't dump type for NUMBER virtual columns [#256]
8
+ * Address :returning_id column should be of type Column [#274]
9
+ * Migrated versions should be dumped in order [#277]
10
+ * Always write serialized LOB columns [#275]
11
+ * Truncate the schema_migrations index [#276]
12
+ * Split paths on windows machines in the right way [#231]
13
+
1
14
  ### 1.4.2.rc1 / 2012-11-13
2
15
 
3
16
  * Enhancements:
data/README.md CHANGED
@@ -113,6 +113,8 @@ If you deploy JRuby on Rails application in Java application server that support
113
113
  adapter: oracle_enhanced
114
114
  jndi: "jdbc/jndi_connection_name"
115
115
 
116
+ To use jndi with Tomcat you need to set the accessToUnderlyingConnectionAllowed to true property on the pool. See the [Tomcat Documentation](http://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html) for reference.
117
+
116
118
  You can find other available database.yml connection parameters in [oracle_enhanced_adapter.rb](/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb). There are many NLS settings as well as some other Oracle session settings.
117
119
 
118
120
  ### Adapter settings
@@ -257,7 +259,7 @@ And you can even create index on multiple tables by providing SELECT statements
257
259
  Post.contains(:all_text, "aaa within title")
258
260
  Post.contains(:all_text, "bbb within comment_author")
259
261
 
260
- ### Oracle virtual collumns support
262
+ ### Oracle virtual columns support
261
263
 
262
264
  Since version R11G1 Oracle database allows adding computed [Virtual Columns](http://www.oracle-base.com/articles/11g/virtual-columns-11gr1.php) to the table.
263
265
  They can be used as normal fields in the queries, in the foreign key contstraints and to partitioning data.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.2.rc1
1
+ 1.4.2.rc2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{activerecord-oracle_enhanced-adapter}
8
- s.version = "1.4.2.rc1"
8
+ s.version = "1.4.2.rc2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Raimonds Simanovskis}]
12
- s.date = %q{2012-11-13}
12
+ s.date = %q{2013-03-01}
13
13
  s.description = %q{Oracle "enhanced" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases.
14
14
  This adapter is superset of original ActiveRecord Oracle adapter.
15
15
  }
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  # Oracle enhanced adapter will work with both
47
47
  # Ruby 1.8/1.9 ruby-oci8 gem (which provides interface to Oracle OCI client)
48
48
  # or with JRuby and Oracle JDBC driver.
49
- #
49
+ #
50
50
  # It should work with Oracle 9i, 10g and 11g databases.
51
51
  # Limited set of functionality should work on Oracle 8i as well but several features
52
52
  # rely on newer functionality in Oracle database.
@@ -71,9 +71,9 @@ module ActiveRecord
71
71
  # * <tt>:username</tt>
72
72
  # * <tt>:password</tt>
73
73
  # * <tt>:database</tt> - either TNS alias or connection string for OCI client or database name in JDBC connection string
74
- #
74
+ #
75
75
  # Optional parameters:
76
- #
76
+ #
77
77
  # * <tt>:host</tt> - host name for JDBC connection, defaults to "localhost"
78
78
  # * <tt>:port</tt> - port number for JDBC connection, defaults to 1521
79
79
  # * <tt>:privilege</tt> - set "SYSDBA" if you want to connect with this privilege
@@ -82,11 +82,10 @@ module ActiveRecord
82
82
  # * <tt>:cursor_sharing</tt> - cursor sharing mode to minimize amount of unique statements, defaults to "force"
83
83
  # * <tt>:time_zone</tt> - database session time zone
84
84
  # (it is recommended to set it using ENV['TZ'] which will be then also used for database session time zone)
85
- #
85
+ #
86
86
  # Optionals NLS parameters:
87
- #
87
+ #
88
88
  # * <tt>:nls_calendar</tt>
89
- # * <tt>:nls_characterset</tt>
90
89
  # * <tt>:nls_comp</tt>
91
90
  # * <tt>:nls_currency</tt>
92
91
  # * <tt>:nls_date_format</tt> - format for :date columns, defaults to <tt>YYYY-MM-DD HH24:MI:SS</tt>
@@ -96,7 +95,6 @@ module ActiveRecord
96
95
  # * <tt>:nls_language</tt>
97
96
  # * <tt>:nls_length_semantics</tt> - semantics of size of VARCHAR2 and CHAR columns, defaults to <tt>CHAR</tt>
98
97
  # (meaning that size specifies number of characters and not bytes)
99
- # * <tt>:nls_nchar_characterset</tt>
100
98
  # * <tt>:nls_nchar_conv_excp</tt>
101
99
  # * <tt>:nls_numeric_characters</tt>
102
100
  # * <tt>:nls_sort</tt>
@@ -105,7 +103,7 @@ module ActiveRecord
105
103
  # * <tt>:nls_timestamp_tz_format</tt>
106
104
  # * <tt>:nls_time_format</tt>
107
105
  # * <tt>:nls_time_tz_format</tt>
108
- #
106
+ #
109
107
  class OracleEnhancedAdapter < AbstractAdapter
110
108
 
111
109
  ##
@@ -126,12 +124,12 @@ module ActiveRecord
126
124
  # to Date then you can add the following line to your initializer file:
127
125
  #
128
126
  # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = true
129
- #
127
+ #
130
128
  # As this option can have side effects when unnecessary typecasting is done it is recommended
131
129
  # that Date columns are explicily defined with +set_date_columns+ method.
132
130
  cattr_accessor :emulate_dates
133
131
  self.emulate_dates = false
134
-
132
+
135
133
  ##
136
134
  # :singleton-method:
137
135
  # OracleEnhancedAdapter will use the default tablespace, but if you want specific types of
@@ -139,7 +137,7 @@ module ActiveRecord
139
137
  #
140
138
  # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
141
139
  # {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
142
- #
140
+ #
143
141
  # Using the :tablespace option where available (e.g create_table) will take precedence
144
142
  # over these settings.
145
143
  cattr_accessor :default_tablespaces
@@ -153,7 +151,7 @@ module ActiveRecord
153
151
  # to Date then you can add the following line to your initializer file:
154
152
  #
155
153
  # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
156
- #
154
+ #
157
155
  # As this option can have side effects when unnecessary typecasting is done it is recommended
158
156
  # that Date columns are explicily defined with +set_date_columns+ method.
159
157
  cattr_accessor :emulate_dates_by_column_name
@@ -212,7 +210,7 @@ module ActiveRecord
212
210
  return true if ["CHAR(1)","VARCHAR2(1)"].include?(field_type)
213
211
  field_type =~ /^VARCHAR2/ && (name =~ /_flag$/i || name =~ /_yn$/i)
214
212
  end
215
-
213
+
216
214
  # How boolean value should be quoted to String.
217
215
  # Used if +emulate_booleans_from_strings+ option is set to +true+.
218
216
  def self.boolean_to_string(bool)
@@ -222,15 +220,15 @@ module ActiveRecord
222
220
  ##
223
221
  # :singleton-method:
224
222
  # Specify non-default date format that should be used when assigning string values to :date columns, e.g.:
225
- #
223
+ #
226
224
  # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = “%d.%m.%Y”
227
225
  cattr_accessor :string_to_date_format
228
226
  self.string_to_date_format = nil
229
-
227
+
230
228
  ##
231
229
  # :singleton-method:
232
230
  # Specify non-default time format that should be used when assigning string values to :datetime columns, e.g.:
233
- #
231
+ #
234
232
  # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = “%d.%m.%Y %H:%M:%S”
235
233
  cattr_accessor :string_to_time_format
236
234
  self.string_to_time_format = nil
@@ -279,7 +277,7 @@ module ActiveRecord
279
277
  end
280
278
 
281
279
  ADAPTER_NAME = 'OracleEnhanced'.freeze
282
-
280
+
283
281
  def adapter_name #:nodoc:
284
282
  ADAPTER_NAME
285
283
  end
@@ -299,7 +297,6 @@ module ActiveRecord
299
297
  #:stopdoc:
300
298
  DEFAULT_NLS_PARAMETERS = {
301
299
  :nls_calendar => nil,
302
- :nls_characterset => nil,
303
300
  :nls_comp => nil,
304
301
  :nls_currency => nil,
305
302
  :nls_date_format => 'YYYY-MM-DD HH24:MI:SS',
@@ -308,7 +305,6 @@ module ActiveRecord
308
305
  :nls_iso_currency => nil,
309
306
  :nls_language => nil,
310
307
  :nls_length_semantics => 'CHAR',
311
- :nls_nchar_characterset => nil,
312
308
  :nls_nchar_conv_excp => nil,
313
309
  :nls_numeric_characters => nil,
314
310
  :nls_sort => nil,
@@ -418,12 +414,12 @@ module ActiveRecord
418
414
  # Names must be from 1 to 30 bytes long with these exceptions:
419
415
  # * Names of databases are limited to 8 bytes.
420
416
  # * Names of database links can be as long as 128 bytes.
421
- #
417
+ #
422
418
  # Nonquoted identifiers cannot be Oracle Database reserved words
423
- #
419
+ #
424
420
  # Nonquoted identifiers must begin with an alphabetic character from
425
421
  # your database character set
426
- #
422
+ #
427
423
  # Nonquoted identifiers can contain only alphanumeric characters from
428
424
  # your database character set and the underscore (_), dollar sign ($),
429
425
  # and pound sign (#). Database links can also contain periods (.) and
@@ -438,7 +434,7 @@ module ActiveRecord
438
434
  # can be prefixed with schema name
439
435
  # CamelCase table names should be quoted
440
436
  def self.valid_table_name?(name) #:nodoc:
441
- name = name.to_s
437
+ name = name.to_s
442
438
  name =~ VALID_TABLE_NAME && !(name =~ /[A-Z]/ && name =~ /[a-z]/) ? true : false
443
439
  end
444
440
 
@@ -446,7 +442,7 @@ module ActiveRecord
446
442
  name = name.to_s
447
443
  @quoted_table_names[name] ||= name.split('.').map{|n| n.split('@').map{|m| quote_column_name(m)}.join('@')}.join('.')
448
444
  end
449
-
445
+
450
446
  def quote_string(s) #:nodoc:
451
447
  s.gsub(/'/, "''")
452
448
  end
@@ -696,17 +692,16 @@ module ActiveRecord
696
692
  def sql_for_insert(sql, pk, id_value, sequence_name, binds)
697
693
  unless id_value || pk.nil? || (defined?(CompositePrimaryKeys) && pk.kind_of?(CompositePrimaryKeys::CompositeKeys))
698
694
  sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
699
- (binds = binds.dup) << [:returning_id, nil]
695
+ returning_id_col = OracleEnhancedColumn.new("returning_id", nil, "number", true, "dual", :integer, true, true)
696
+ (binds = binds.dup) << [returning_id_col, nil]
700
697
  end
701
698
  [sql, binds]
702
699
  end
703
700
 
704
- EXEC_INSERT_RESULT_COLUMNS = %w(returning_id) #:nodoc:
705
-
706
701
  # New method in ActiveRecord 3.1
707
702
  def exec_insert(sql, name, binds)
708
703
  log(sql, name, binds) do
709
- returning_id_index = nil
704
+ returning_id_col = returning_id_index = nil
710
705
  cursor = if @statements.key?(sql)
711
706
  @statements[sql]
712
707
  else
@@ -715,7 +710,8 @@ module ActiveRecord
715
710
 
716
711
  binds.each_with_index do |bind, i|
717
712
  col, val = bind
718
- if col == :returning_id
713
+ if col.returning_id?
714
+ returning_id_col = [col]
719
715
  returning_id_index = i + 1
720
716
  cursor.bind_returning_param(returning_id_index, Integer)
721
717
  else
@@ -730,7 +726,7 @@ module ActiveRecord
730
726
  returning_id = cursor.get_returning_param(returning_id_index, Integer)
731
727
  rows << [returning_id]
732
728
  end
733
- ActiveRecord::Result.new(EXEC_INSERT_RESULT_COLUMNS, rows)
729
+ ActiveRecord::Result.new(returning_id_col || [], rows)
734
730
  end
735
731
  end
736
732
 
@@ -977,7 +973,7 @@ module ActiveRecord
977
973
  current_index = row['index_name']
978
974
  end
979
975
 
980
- # Functional index columns and virtual columns both get stored as column expressions,
976
+ # Functional index columns and virtual columns both get stored as column expressions,
981
977
  # but re-creating a virtual column index as an expression (instead of using the virtual column's name)
982
978
  # results in a ORA-54018 error. Thus, we only want the column expression value returned
983
979
  # when the column is not virtual.
@@ -1003,12 +999,12 @@ module ActiveRecord
1003
999
  @@ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
1004
1000
  @@ignore_table_columns[table_name].uniq!
1005
1001
  end
1006
-
1002
+
1007
1003
  def ignored_table_columns(table_name) #:nodoc:
1008
1004
  @@ignore_table_columns ||= {}
1009
1005
  @@ignore_table_columns[table_name]
1010
1006
  end
1011
-
1007
+
1012
1008
  # used just in tests to clear ignored table columns
1013
1009
  def clear_ignored_table_columns #:nodoc:
1014
1010
  @@ignore_table_columns = nil
@@ -1024,7 +1020,7 @@ module ActiveRecord
1024
1020
  @@table_column_type[table_name][col.to_s.downcase] = column_type
1025
1021
  end
1026
1022
  end
1027
-
1023
+
1028
1024
  def get_type_for_column(table_name, column_name) #:nodoc:
1029
1025
  @@table_column_type && @@table_column_type[table_name] && @@table_column_type[table_name][column_name.to_s.downcase]
1030
1026
  end
@@ -1111,7 +1107,7 @@ module ActiveRecord
1111
1107
  if row['data_default'] && !is_virtual
1112
1108
  row['data_default'].sub!(/^(.*?)\s*$/, '\1')
1113
1109
 
1114
- # If a default contains a newline these cleanup regexes need to
1110
+ # If a default contains a newline these cleanup regexes need to
1115
1111
  # match newlines.
1116
1112
  row['data_default'].sub!(/^'(.*)'$/m, '\1')
1117
1113
  row['data_default'] = nil if row['data_default'] =~ /^(null|empty_[bc]lob\(\))$/i
@@ -1150,7 +1146,7 @@ module ActiveRecord
1150
1146
  cattr_accessor :default_sequence_start_value
1151
1147
  self.default_sequence_start_value = 10000
1152
1148
 
1153
- # Find a table's primary key and sequence.
1149
+ # Find a table's primary key and sequence.
1154
1150
  # *Note*: Only primary key is implemented - sequence will be nil.
1155
1151
  def pk_and_sequence_for(table_name, owner=nil, desc_table_name=nil, db_link=nil) #:nodoc:
1156
1152
  if @@cache_columns
@@ -1198,7 +1194,7 @@ module ActiveRecord
1198
1194
  # Oracle requires the ORDER BY columns to be in the SELECT list for DISTINCT
1199
1195
  # queries. However, with those columns included in the SELECT DISTINCT list, you
1200
1196
  # won't actually get a distinct list of the column you want (presuming the column
1201
- # has duplicates with multiple values for the ordered-by columns. So we use the
1197
+ # has duplicates with multiple values for the ordered-by columns. So we use the
1202
1198
  # FIRST_VALUE function to get a single (first) value for each column, effectively
1203
1199
  # making every row the same.
1204
1200
  #
@@ -1296,7 +1292,7 @@ module ActiveRecord
1296
1292
  #
1297
1293
  # PL/SQL in Oracle uses dbms_output for logging print statements
1298
1294
  # These methods stick that output into the Rails log so Ruby and PL/SQL
1299
- # code can can be debugged together in a single application
1295
+ # code can can be debugged together in a single application
1300
1296
 
1301
1297
  # Maximum DBMS_OUTPUT buffer size
1302
1298
  DBMS_OUTPUT_BUFFER_SIZE = 10000 # can be 1-1000000
@@ -1328,7 +1324,7 @@ module ActiveRecord
1328
1324
  ensure
1329
1325
  log_dbms_output if dbms_output_enabled?
1330
1326
  end
1331
-
1327
+
1332
1328
  private
1333
1329
 
1334
1330
  def set_dbms_output_plsql_connection
@@ -75,7 +75,10 @@ module ActiveRecord
75
75
  end
76
76
  end
77
77
  def record_changed_lobs
78
- @changed_lob_columns = self.class.lob_columns.select{|col| self.send(:"#{col.name}_changed?") && !self.class.readonly_attributes.to_a.include?(col.name)}
78
+ @changed_lob_columns = self.class.lob_columns.select do |col|
79
+ self.class.serialized_attributes.keys.include?(col.name) ||
80
+ (self.send(:"#{col.name}_changed?") && !self.class.readonly_attributes.to_a.include?(col.name))
81
+ end
79
82
  end
80
83
  private :enhanced_write_lobs
81
84
  private :record_changed_lobs
@@ -2,13 +2,14 @@ module ActiveRecord
2
2
  module ConnectionAdapters #:nodoc:
3
3
  class OracleEnhancedColumn < Column
4
4
 
5
- attr_reader :table_name, :forced_column_type, :nchar, :virtual_column_data_default #:nodoc:
5
+ attr_reader :table_name, :forced_column_type, :nchar, :virtual_column_data_default, :returning_id #:nodoc:
6
6
 
7
- def initialize(name, default, sql_type = nil, null = true, table_name = nil, forced_column_type = nil, virtual=false) #:nodoc:
7
+ def initialize(name, default, sql_type = nil, null = true, table_name = nil, forced_column_type = nil, virtual=false, returning_id=false) #:nodoc:
8
8
  @table_name = table_name
9
9
  @forced_column_type = forced_column_type
10
10
  @virtual = virtual
11
11
  @virtual_column_data_default = default.inspect if virtual
12
+ @returning_id = returning_id
12
13
  default = nil if virtual
13
14
  super(name, default, sql_type, null)
14
15
  # Is column NCHAR or NVARCHAR2 (will need to use N'...' value quoting for these data types)?
@@ -26,6 +27,10 @@ module ActiveRecord
26
27
  @virtual
27
28
  end
28
29
 
30
+ def returning_id?
31
+ @returning_id
32
+ end
33
+
29
34
  def lob?
30
35
  self.sql_type =~ /LOB$/i
31
36
  end
@@ -18,6 +18,8 @@ module ActiveRecord #:nodoc:
18
18
  # therefore need to convert empty string value to nil if old value is nil
19
19
  elsif column.type == :string && column.null && old.nil?
20
20
  value = nil if value == ''
21
+ elsif old == 0 && value.is_a?(String) && value.present? && value != '0'
22
+ value = nil
21
23
  else
22
24
  value = column.type_cast(value)
23
25
  end
@@ -41,4 +43,4 @@ if ActiveRecord::Base.method_defined?(:changed?)
41
43
  alias_method :field_changed?, :_field_changed?
42
44
  end
43
45
  end
44
- end
46
+ end
@@ -15,7 +15,7 @@ begin
15
15
 
16
16
  unless ojdbc_jar.nil? || ENV_JAVA['java.class.path'] =~ Regexp.new(ojdbc_jar)
17
17
  # On Unix environment variable should be PATH, on Windows it is sometimes Path
18
- env_path = (ENV["PATH"] || ENV["Path"] || '').split(/[:;]/)
18
+ env_path = (ENV["PATH"] || ENV["Path"] || '').split(File::PATH_SEPARATOR)
19
19
  # Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
20
20
  # then in Ruby load path and finally in environment PATH
21
21
  if ojdbc_jar_path = ['./lib'].concat($LOAD_PATH).concat(env_path).find{|d| File.exists?(File.join(d,ojdbc_jar))}
@@ -13,10 +13,10 @@ module ActiveRecord #:nodoc:
13
13
  private
14
14
 
15
15
  def ignore_table?(table)
16
- [ActiveRecord::Migrator.proper_table_name('schema_migrations'), ignore_tables].flatten.any? do |ignored|
16
+ ['schema_migrations', ignore_tables].flatten.any? do |ignored|
17
17
  case ignored
18
- when String; table == ignored
19
- when Regexp; table =~ ignored
18
+ when String; remove_prefix_and_suffix(table) == ignored
19
+ when Regexp; remove_prefix_and_suffix(table) =~ ignored
20
20
  else
21
21
  raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
22
22
  end
@@ -177,7 +177,7 @@ module ActiveRecord #:nodoc:
177
177
  spec[:name] = column.name.inspect
178
178
  spec[:type] = column.virtual? ? 'virtual' : column.type.to_s
179
179
  spec[:type] = column.virtual? ? 'virtual' : column.type.to_s
180
- spec[:virtual_type] = column.type.inspect if column.virtual?
180
+ spec[:virtual_type] = column.type.inspect if column.virtual? && column.sql_type != 'NUMBER'
181
181
  spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
182
182
  spec[:precision] = column.precision.inspect if !column.precision.nil?
183
183
  spec[:scale] = column.scale.inspect if !column.scale.nil?
@@ -230,7 +230,10 @@ module ActiveRecord #:nodoc:
230
230
 
231
231
  stream
232
232
  end
233
-
233
+
234
+ def remove_prefix_and_suffix(table)
235
+ table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
236
+ end
234
237
 
235
238
  # remove table name prefix and suffix when doing #inspect (which is used in tables method)
236
239
  module TableInspect #:nodoc:
@@ -22,11 +22,11 @@ module ActiveRecord
22
22
  # end
23
23
  #
24
24
  # Create primary key trigger (so that you can skip primary key value in INSERT statement).
25
- # By default trigger name will be "table_name_pkt", you can override the name with
25
+ # By default trigger name will be "table_name_pkt", you can override the name with
26
26
  # :trigger_name option (but it is not recommended to override it as then this trigger will
27
27
  # not be detected by ActiveRecord model and it will still do prefetching of sequence value).
28
28
  # Example:
29
- #
29
+ #
30
30
  # create_table :users, :primary_key_trigger => true do |t|
31
31
  # # ...
32
32
  # end
@@ -37,11 +37,11 @@ module ActiveRecord
37
37
  # t.string :first_name, :comment => “Given name”
38
38
  # t.string :last_name, :comment => “Surname”
39
39
  # end
40
-
40
+
41
41
  def create_table(name, options = {}, &block)
42
42
  create_sequence = options[:id] != false
43
43
  column_comments = {}
44
-
44
+
45
45
  table_definition = TableDefinition.new(self)
46
46
  table_definition.primary_key(options[:primary_key] || Base.get_primary_key(name.to_s.singularize)) unless options[:id] == false
47
47
 
@@ -87,14 +87,14 @@ module ActiveRecord
87
87
  end
88
88
  create_sql << " #{options[:options]}"
89
89
  execute create_sql
90
-
90
+
91
91
  create_sequence_and_trigger(name, options) if create_sequence
92
-
92
+
93
93
  add_table_comment name, options[:comment]
94
94
  column_comments.each do |column_name, comment|
95
95
  add_comment name, column_name, comment
96
96
  end
97
-
97
+
98
98
  end
99
99
 
100
100
  def rename_table(name, new_name) #:nodoc:
@@ -116,6 +116,35 @@ module ActiveRecord
116
116
  clear_table_columns_cache(name)
117
117
  end
118
118
 
119
+ def initialize_schema_migrations_table
120
+ sm_table = ActiveRecord::Migrator.schema_migrations_table_name
121
+
122
+ unless table_exists?(sm_table)
123
+ index_name = "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
124
+ if index_name.length > index_name_length
125
+ truncate_to = index_name_length - index_name.to_s.length - 1
126
+ truncated_name = "unique_schema_migrations"[0..truncate_to]
127
+ index_name = "#{Base.table_name_prefix}#{truncated_name}#{Base.table_name_suffix}"
128
+ end
129
+
130
+ create_table(sm_table, :id => false) do |schema_migrations_table|
131
+ schema_migrations_table.column :version, :string, :null => false
132
+ end
133
+ add_index sm_table, :version, :unique => true, :name => index_name
134
+
135
+ # Backwards-compatibility: if we find schema_info, assume we've
136
+ # migrated up to that point:
137
+ si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
138
+ if table_exists?(si_table)
139
+ ActiveSupport::Deprecation.warn "Usage of the schema table `#{si_table}` is deprecated. Please switch to using `schema_migrations` table"
140
+
141
+ old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
142
+ assume_migrated_upto_version(old_version)
143
+ drop_table(si_table)
144
+ end
145
+ end
146
+ end
147
+
119
148
  # clear cached indexes when adding new index
120
149
  def add_index(table_name, column_name, options = {}) #:nodoc:
121
150
  column_names = Array(column_name)
@@ -166,10 +195,10 @@ module ActiveRecord
166
195
  options = {} unless options.is_a?(Hash)
167
196
  identifier_max_length = options[:identifier_max_length] || index_name_length
168
197
  return default_name if default_name.length <= identifier_max_length
169
-
198
+
170
199
  # remove 'index', 'on' and 'and' keywords
171
200
  shortened_name = "i_#{table_name}_#{Array(options[:column]) * '_'}"
172
-
201
+
173
202
  # leave just first three letters from each word
174
203
  if shortened_name.length > identifier_max_length
175
204
  shortened_name = shortened_name.split('_').map{|w| w[0,3]}.join('_')
@@ -271,6 +300,8 @@ module ActiveRecord
271
300
  end
272
301
 
273
302
  def remove_column(table_name, *column_names) #:nodoc:
303
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
304
+
274
305
  major, minor = ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR
275
306
  is_deprecated = (major == 3 and minor >= 2) or major > 3
276
307
 
@@ -94,9 +94,11 @@ module ActiveRecord
94
94
  references = options[:references] ? options[:references].first : nil
95
95
  references_sql = quote_column_name(options[:primary_key] || references || "id")
96
96
  end
97
-
98
- sql = "FOREIGN KEY (#{columns_sql}) REFERENCES #{quote_table_name(to_table)}(#{references_sql})"
99
-
97
+
98
+ table_name = ActiveRecord::Migrator.proper_table_name(to_table)
99
+
100
+ sql = "FOREIGN KEY (#{columns_sql}) REFERENCES #{quote_table_name(table_name)}(#{references_sql})"
101
+
100
102
  case options[:dependent]
101
103
  when :nullify
102
104
  sql << " ON DELETE SET NULL"
@@ -136,7 +136,7 @@ module ActiveRecord #:nodoc:
136
136
 
137
137
  def dump_schema_information #:nodoc:
138
138
  sm_table = ActiveRecord::Migrator.schema_migrations_table_name
139
- migrated = select_values("SELECT version FROM #{sm_table}")
139
+ migrated = select_values("SELECT version FROM #{sm_table} ORDER BY version")
140
140
  join_with_statement_token(migrated.map{|v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}')" })
141
141
  end
142
142
 
@@ -1052,6 +1052,18 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
1052
1052
  @employee.reload
1053
1053
  @employee.comments.should == @char_data
1054
1054
  end
1055
+
1056
+ it "should keep unchanged serialized data when other columns changed" do
1057
+ @employee = Test2Employee.create!(
1058
+ :first_name => "First",
1059
+ :last_name => "Last",
1060
+ :comments => "initial serialized data"
1061
+ )
1062
+ @employee.first_name = "Steve"
1063
+ @employee.save
1064
+ @employee.reload
1065
+ @employee.comments.should == "initial serialized data"
1066
+ end
1055
1067
  end
1056
1068
 
1057
1069
  describe "OracleEnhancedAdapter handling of BLOB columns" do
@@ -355,6 +355,7 @@ describe "OracleEnhancedAdapter schema dump" do
355
355
  t.virtual :full_name, :as => "first_name || ', ' || last_name"
356
356
  t.virtual :short_name, :as => "COALESCE(first_name, last_name)", :type => :string, :limit => 300
357
357
  t.virtual :abbrev_name, :as => "SUBSTR(first_name,1,50) || ' ' || SUBSTR(last_name,1,1) || '.'", :type => "VARCHAR(100)"
358
+ t.virtual :name_ratio, :as=>'(LENGTH(first_name)*10/LENGTH(last_name)*10)'
358
359
  t.column :full_name_length, :virtual, :as => "length(first_name || ', ' || last_name)", :type => :integer
359
360
  t.virtual :field_with_leading_space, :as => "' ' || first_name || ' '", :limit => 300, :type => :string
360
361
  end
@@ -388,6 +389,7 @@ describe "OracleEnhancedAdapter schema dump" do
388
389
  standard_dump.should =~ /t\.virtual "full_name",(\s*):limit => 512,(\s*):as => "\\"FIRST_NAME\\"\|\|', '\|\|\\"LAST_NAME\\"",(\s*):type => :string/
389
390
  standard_dump.should =~ /t\.virtual "short_name",(\s*):limit => 300,(\s*):as =>(.*),(\s*):type => :string/
390
391
  standard_dump.should =~ /t\.virtual "full_name_length",(\s*):precision => 38,(\s*):scale => 0,(\s*):as =>(.*),(\s*):type => :integer/
392
+ standard_dump.should =~ /t\.virtual "name_ratio",(\s*):as =>(.*)\"$/ # no :type
391
393
  standard_dump.should =~ /t\.virtual "abbrev_name",(\s*):limit => 100,(\s*):as =>(.*),(\s*):type => :string/
392
394
  standard_dump.should =~ /t\.virtual "field_with_leading_space",(\s*):limit => 300,(\s*):as => "' '\|\|\\"FIRST_NAME\\"\|\|' '",(\s*):type => :string/
393
395
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "OracleEnhancedAdapter schema definition" do
4
4
  include SchemaSpecHelper
5
+ include LoggerSpecHelper
5
6
 
6
7
  before(:all) do
7
8
  ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
@@ -186,6 +187,14 @@ describe "OracleEnhancedAdapter schema definition" do
186
187
  e = TestEmployee.create!(:first_name => 'Raimonds')
187
188
  @conn.select_value("SELECT test_employees_seq.currval FROM dual").should == e.id
188
189
  end
190
+
191
+ it "should not generate NoMethodError for :returning_id:Symbol" do
192
+ set_logger
193
+ insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Yasuo')", nil, "id")
194
+ @logger.output(:error).should_not match(/^Could not log "sql.active_record" event. NoMethodError: undefined method `name' for :returning_id:Symbol/)
195
+ clear_logger
196
+ end
197
+
189
198
  end
190
199
 
191
200
  describe "with separate creation of primary key trigger" do
@@ -313,7 +322,7 @@ describe "OracleEnhancedAdapter schema definition" do
313
322
  drop_table :test_employees
314
323
  end
315
324
  Object.send(:remove_const, "TestEmployee")
316
- ActiveRecord::Base.table_name_prefix = nil
325
+ ActiveRecord::Base.table_name_prefix = ''
317
326
  ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
318
327
  end
319
328
 
@@ -536,7 +545,12 @@ end
536
545
  end
537
546
 
538
547
  describe "foreign key constraints" do
548
+ let(:table_name_prefix) { '' }
549
+ let(:table_name_suffix) { '' }
550
+
539
551
  before(:each) do
552
+ ActiveRecord::Base.table_name_prefix = table_name_prefix
553
+ ActiveRecord::Base.table_name_suffix = table_name_suffix
540
554
  schema_define do
541
555
  create_table :test_posts, :force => true do |t|
542
556
  t.string :title
@@ -562,6 +576,8 @@ end
562
576
  drop_table :test_comments rescue nil
563
577
  drop_table :test_posts rescue nil
564
578
  end
579
+ ActiveRecord::Base.table_name_prefix = ''
580
+ ActiveRecord::Base.table_name_suffix = ''
565
581
  ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
566
582
  end
567
583
 
@@ -574,6 +590,34 @@ end
574
590
  end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.TEST_COMMENTS_TEST_POST_ID_FK/}
575
591
  end
576
592
 
593
+ context "with table_name_prefix" do
594
+ let(:table_name_prefix) { 'xxx_' }
595
+
596
+ it "should use table_name_prefix for foreign table" do
597
+ schema_define do
598
+ add_foreign_key :test_comments, :test_posts
599
+ end
600
+
601
+ lambda do
602
+ TestComment.create(:body => "test", :test_post_id => 1)
603
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.XXX_TES_COM_TES_POS_ID_FK/}
604
+ end
605
+ end
606
+
607
+ context "with table_name_suffix" do
608
+ let(:table_name_suffix) { '_xxx' }
609
+
610
+ it "should use table_name_suffix for foreign table" do
611
+ schema_define do
612
+ add_foreign_key :test_comments, :test_posts
613
+ end
614
+
615
+ lambda do
616
+ TestComment.create(:body => "test", :test_post_id => 1)
617
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.TES_COM_XXX_TES_POS_ID_FK/}
618
+ end
619
+ end
620
+
577
621
  it "should add foreign key with name" do
578
622
  schema_define do
579
623
  add_foreign_key :test_comments, :test_posts, :name => "comments_posts_fk"
@@ -1276,5 +1320,65 @@ end
1276
1320
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:index)
1277
1321
  @would_execute_sql.should =~ /CREATE +INDEX .* ON .* \(.*\) TABLESPACE #{DATABASE_NON_DEFAULT_TABLESPACE}/
1278
1322
  end
1323
+
1324
+ describe "#initialize_schema_migrations_table" do
1325
+ # In Rails 2.3 to 3.2.x the index name for the migrations
1326
+ # table is hard-coded. We can modify the index name here
1327
+ # so we can support prefixes/suffixes that would
1328
+ # cause the index to be too long.
1329
+ #
1330
+ # Rails 4 can use this solution as well.
1331
+ after(:each) do
1332
+ ActiveRecord::Base.table_name_prefix = ''
1333
+ ActiveRecord::Base.table_name_suffix = ''
1334
+ end
1335
+
1336
+ def add_schema_migrations_index
1337
+ schema_define do
1338
+ initialize_schema_migrations_table
1339
+ end
1340
+ end
1341
+
1342
+ context "without prefix or suffix" do
1343
+ it "should not truncate the index name" do
1344
+ add_schema_migrations_index
1345
+
1346
+ @would_execute_sql.should include('CREATE UNIQUE INDEX "UNIQUE_SCHEMA_MIGRATIONS" ON "SCHEMA_MIGRATIONS" ("VERSION")')
1347
+ end
1348
+ end
1349
+
1350
+ context "with prefix" do
1351
+ before { ActiveRecord::Base.table_name_prefix = 'toolong_' }
1352
+
1353
+ it "should truncate the 'unique_schema_migrations' portion of the index name to fit the prefix within the limit" do
1354
+ add_schema_migrations_index
1355
+
1356
+ @would_execute_sql.should include('CREATE UNIQUE INDEX "TOOLONG_UNIQUE_SCHEMA_MIGRATIO" ON "TOOLONG_SCHEMA_MIGRATIONS" ("VERSION")')
1357
+ end
1358
+ end
1359
+
1360
+ context "with suffix" do
1361
+ before { ActiveRecord::Base.table_name_suffix = '_toolong' }
1362
+
1363
+ it "should truncate the 'unique_schema_migrations' portion of the index name to fit the suffix within the limit" do
1364
+ add_schema_migrations_index
1365
+
1366
+ @would_execute_sql.should include('CREATE UNIQUE INDEX "UNIQUE_SCHEMA_MIGRATIO_TOOLONG" ON "SCHEMA_MIGRATIONS_TOOLONG" ("VERSION")')
1367
+ end
1368
+ end
1369
+
1370
+ context "with prefix and suffix" do
1371
+ before do
1372
+ ActiveRecord::Base.table_name_prefix = 'begin_'
1373
+ ActiveRecord::Base.table_name_suffix = '_end'
1374
+ end
1375
+
1376
+ it "should truncate the 'unique_schema_migrations' portion of the index name to fit the suffix within the limit" do
1377
+ add_schema_migrations_index
1378
+
1379
+ @would_execute_sql.should include('CREATE UNIQUE INDEX "BEGIN_UNIQUE_SCHEMA_MIGRAT_END" ON "BEGIN_SCHEMA_MIGRATIONS_END" ("VERSION")')
1380
+ end
1381
+ end
1382
+ end
1279
1383
  end
1280
1384
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-oracle_enhanced-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2.rc1
4
+ version: 1.4.2.rc2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-13 00:00:00.000000000 Z
12
+ date: 2013-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
+ type: :development
15
16
  name: jeweler
16
17
  requirement: !ruby/object:Gem::Requirement
17
18
  none: false
@@ -19,15 +20,15 @@ dependencies:
19
20
  - - ~>
20
21
  - !ruby/object:Gem::Version
21
22
  version: 1.5.1
22
- type: :development
23
- prerelease: false
24
23
  version_requirements: !ruby/object:Gem::Requirement
25
24
  none: false
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
28
  version: 1.5.1
29
+ prerelease: false
30
30
  - !ruby/object:Gem::Dependency
31
+ type: :development
31
32
  name: rspec
32
33
  requirement: !ruby/object:Gem::Requirement
33
34
  none: false
@@ -35,15 +36,15 @@ dependencies:
35
36
  - - ~>
36
37
  - !ruby/object:Gem::Version
37
38
  version: '2.4'
38
- type: :development
39
- prerelease: false
40
39
  version_requirements: !ruby/object:Gem::Requirement
41
40
  none: false
42
41
  requirements:
43
42
  - - ~>
44
43
  - !ruby/object:Gem::Version
45
44
  version: '2.4'
45
+ prerelease: false
46
46
  - !ruby/object:Gem::Dependency
47
+ type: :development
47
48
  name: rdoc
48
49
  requirement: !ruby/object:Gem::Requirement
49
50
  none: false
@@ -51,79 +52,79 @@ dependencies:
51
52
  - - ! '>='
52
53
  - !ruby/object:Gem::Version
53
54
  version: '0'
54
- type: :development
55
- prerelease: false
56
55
  version_requirements: !ruby/object:Gem::Requirement
57
56
  none: false
58
57
  requirements:
59
58
  - - ! '>='
60
59
  - !ruby/object:Gem::Version
61
60
  version: '0'
61
+ prerelease: false
62
62
  - !ruby/object:Gem::Dependency
63
+ type: :development
63
64
  name: activerecord
64
65
  requirement: !ruby/object:Gem::Requirement
65
66
  none: false
66
67
  requirements:
67
68
  - - '='
68
69
  - !ruby/object:Gem::Version
69
- version: 3.2.9
70
- type: :development
71
- prerelease: false
70
+ version: 3.2.12
72
71
  version_requirements: !ruby/object:Gem::Requirement
73
72
  none: false
74
73
  requirements:
75
74
  - - '='
76
75
  - !ruby/object:Gem::Version
77
- version: 3.2.9
76
+ version: 3.2.12
77
+ prerelease: false
78
78
  - !ruby/object:Gem::Dependency
79
+ type: :development
79
80
  name: actionpack
80
81
  requirement: !ruby/object:Gem::Requirement
81
82
  none: false
82
83
  requirements:
83
84
  - - '='
84
85
  - !ruby/object:Gem::Version
85
- version: 3.2.9
86
- type: :development
87
- prerelease: false
86
+ version: 3.2.12
88
87
  version_requirements: !ruby/object:Gem::Requirement
89
88
  none: false
90
89
  requirements:
91
90
  - - '='
92
91
  - !ruby/object:Gem::Version
93
- version: 3.2.9
92
+ version: 3.2.12
93
+ prerelease: false
94
94
  - !ruby/object:Gem::Dependency
95
+ type: :development
95
96
  name: activesupport
96
97
  requirement: !ruby/object:Gem::Requirement
97
98
  none: false
98
99
  requirements:
99
100
  - - '='
100
101
  - !ruby/object:Gem::Version
101
- version: 3.2.9
102
- type: :development
103
- prerelease: false
102
+ version: 3.2.12
104
103
  version_requirements: !ruby/object:Gem::Requirement
105
104
  none: false
106
105
  requirements:
107
106
  - - '='
108
107
  - !ruby/object:Gem::Version
109
- version: 3.2.9
108
+ version: 3.2.12
109
+ prerelease: false
110
110
  - !ruby/object:Gem::Dependency
111
+ type: :development
111
112
  name: railties
112
113
  requirement: !ruby/object:Gem::Requirement
113
114
  none: false
114
115
  requirements:
115
116
  - - '='
116
117
  - !ruby/object:Gem::Version
117
- version: 3.2.9
118
- type: :development
119
- prerelease: false
118
+ version: 3.2.12
120
119
  version_requirements: !ruby/object:Gem::Requirement
121
120
  none: false
122
121
  requirements:
123
122
  - - '='
124
123
  - !ruby/object:Gem::Version
125
- version: 3.2.9
124
+ version: 3.2.12
125
+ prerelease: false
126
126
  - !ruby/object:Gem::Dependency
127
+ type: :development
127
128
  name: ruby-plsql
128
129
  requirement: !ruby/object:Gem::Requirement
129
130
  none: false
@@ -131,15 +132,15 @@ dependencies:
131
132
  - - ! '>='
132
133
  - !ruby/object:Gem::Version
133
134
  version: 0.4.4
134
- type: :development
135
- prerelease: false
136
135
  version_requirements: !ruby/object:Gem::Requirement
137
136
  none: false
138
137
  requirements:
139
138
  - - ! '>='
140
139
  - !ruby/object:Gem::Version
141
140
  version: 0.4.4
141
+ prerelease: false
142
142
  - !ruby/object:Gem::Dependency
143
+ type: :development
143
144
  name: ruby-oci8
144
145
  requirement: !ruby/object:Gem::Requirement
145
146
  none: false
@@ -147,14 +148,13 @@ dependencies:
147
148
  - - ! '>='
148
149
  - !ruby/object:Gem::Version
149
150
  version: 2.0.4
150
- type: :development
151
- prerelease: false
152
151
  version_requirements: !ruby/object:Gem::Requirement
153
152
  none: false
154
153
  requirements:
155
154
  - - ! '>='
156
155
  - !ruby/object:Gem::Version
157
156
  version: 2.0.4
157
+ prerelease: false
158
158
  description: ! 'Oracle "enhanced" ActiveRecord adapter contains useful additional
159
159
  methods for working with new and legacy Oracle databases.
160
160
 
@@ -223,10 +223,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
223
223
  requirements:
224
224
  - - ! '>='
225
225
  - !ruby/object:Gem::Version
226
- version: '0'
227
226
  segments:
228
227
  - 0
229
- hash: -4041151724223707895
228
+ version: '0'
229
+ hash: -4155307569324953447
230
230
  required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  none: false
232
232
  requirements:
@@ -235,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
235
  version: 1.3.1
236
236
  requirements: []
237
237
  rubyforge_project:
238
- rubygems_version: 1.8.24
238
+ rubygems_version: 1.8.25
239
239
  signing_key:
240
240
  specification_version: 3
241
241
  summary: Oracle enhanced adapter for ActiveRecord