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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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