activerecord 1.14.4 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +400 -1
- data/README +2 -2
- data/RUNNING_UNIT_TESTS +21 -3
- data/Rakefile +55 -10
- data/lib/active_record.rb +10 -4
- data/lib/active_record/acts/list.rb +15 -4
- data/lib/active_record/acts/nested_set.rb +11 -12
- data/lib/active_record/acts/tree.rb +13 -14
- data/lib/active_record/aggregations.rb +46 -22
- data/lib/active_record/associations.rb +213 -162
- data/lib/active_record/associations/association_collection.rb +45 -15
- data/lib/active_record/associations/association_proxy.rb +32 -13
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +18 -18
- data/lib/active_record/associations/has_many_association.rb +37 -17
- data/lib/active_record/associations/has_many_through_association.rb +120 -30
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/attribute_methods.rb +75 -0
- data/lib/active_record/base.rb +282 -203
- data/lib/active_record/calculations.rb +95 -54
- data/lib/active_record/callbacks.rb +13 -24
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +12 -1
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb.rej +21 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -9
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +121 -37
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -23
- data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -11
- data/lib/active_record/connection_adapters/firebird_adapter.rb +364 -50
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -33
- data/lib/active_record/connection_adapters/openbase_adapter.rb +4 -3
- data/lib/active_record/connection_adapters/oracle_adapter.rb +151 -127
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +125 -48
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +38 -10
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +183 -155
- data/lib/active_record/connection_adapters/sybase_adapter.rb +190 -212
- data/lib/active_record/deprecated_associations.rb +24 -10
- data/lib/active_record/deprecated_finders.rb +4 -1
- data/lib/active_record/fixtures.rb +37 -23
- data/lib/active_record/locking/optimistic.rb +106 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +8 -5
- data/lib/active_record/observer.rb +73 -34
- data/lib/active_record/reflection.rb +21 -7
- data/lib/active_record/schema_dumper.rb +33 -5
- data/lib/active_record/timestamp.rb +23 -34
- data/lib/active_record/transactions.rb +37 -30
- data/lib/active_record/validations.rb +46 -30
- data/lib/active_record/vendor/mysql.rb +20 -5
- data/lib/active_record/version.rb +2 -2
- data/lib/active_record/wrappings.rb +1 -2
- data/lib/active_record/xml_serialization.rb +308 -0
- data/test/aaa_create_tables_test.rb +5 -1
- data/test/abstract_unit.rb +18 -8
- data/test/{active_schema_mysql.rb → active_schema_test_mysql.rb} +2 -2
- data/test/adapter_test.rb +9 -7
- data/test/adapter_test_sqlserver.rb +81 -0
- data/test/aggregations_test.rb +29 -0
- data/test/{association_callbacks_test.rb → associations/callbacks_test.rb} +10 -8
- data/test/{associations_cascaded_eager_loading_test.rb → associations/cascaded_eager_loading_test.rb} +35 -3
- data/test/{associations_go_eager_test.rb → associations/eager_test.rb} +36 -2
- data/test/{associations_extensions_test.rb → associations/extension_test.rb} +5 -0
- data/test/{associations_join_model_test.rb → associations/join_model_test.rb} +118 -8
- data/test/associations_test.rb +339 -45
- data/test/attribute_methods_test.rb +49 -0
- data/test/base_test.rb +321 -67
- data/test/calculations_test.rb +48 -10
- data/test/callbacks_test.rb +13 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connections/native_db2/connection.rb +18 -17
- data/test/connections/native_firebird/connection.rb +19 -17
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +18 -15
- data/test/connections/native_openbase/connection.rb +14 -15
- data/test/connections/native_oracle/connection.rb +16 -12
- data/test/connections/native_postgresql/connection.rb +16 -17
- data/test/connections/native_sqlite/connection.rb +3 -6
- data/test/connections/native_sqlite3/connection.rb +3 -6
- data/test/connections/native_sqlserver/connection.rb +16 -17
- data/test/connections/native_sqlserver_odbc/connection.rb +18 -19
- data/test/connections/native_sybase/connection.rb +16 -17
- data/test/datatype_test_postgresql.rb +52 -0
- data/test/defaults_test.rb +52 -10
- data/test/deprecated_associations_test.rb +151 -107
- data/test/deprecated_finder_test.rb +83 -66
- data/test/empty_date_time_test.rb +25 -0
- data/test/finder_test.rb +118 -11
- data/test/fixtures/accounts.yml +6 -1
- data/test/fixtures/author.rb +27 -4
- data/test/fixtures/categorizations.yml +8 -2
- data/test/fixtures/category.rb +1 -2
- data/test/fixtures/comments.yml +0 -6
- data/test/fixtures/companies.yml +6 -1
- data/test/fixtures/company.rb +23 -1
- data/test/fixtures/company_in_module.rb +8 -10
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/customers.yml +9 -0
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +9 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -0
- data/test/fixtures/db_definitions/firebird.sql +13 -1
- data/test/fixtures/db_definitions/frontbase.drop.sql +31 -0
- data/test/fixtures/db_definitions/frontbase.sql +262 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
- data/test/fixtures/db_definitions/mysql.sql +23 -14
- data/test/fixtures/db_definitions/openbase.sql +13 -1
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +29 -2
- data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
- data/test/fixtures/db_definitions/postgresql.sql +13 -3
- data/test/fixtures/db_definitions/schema.rb +29 -1
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +12 -3
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +35 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
- data/test/fixtures/db_definitions/sybase.sql +13 -4
- data/test/fixtures/developer.rb +12 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/funny_jokes.yml +3 -7
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/mixin.rb +15 -0
- data/test/fixtures/mixins.yml +38 -0
- data/test/fixtures/post.rb +3 -2
- data/test/fixtures/project.rb +3 -1
- data/test/fixtures/topic.rb +6 -1
- data/test/fixtures/topics.yml +4 -4
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +45 -0
- data/test/inheritance_test.rb +67 -6
- data/test/lifecycle_test.rb +40 -19
- data/test/locking_test.rb +170 -26
- data/test/method_scoping_test.rb +2 -2
- data/test/migration_test.rb +387 -110
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_nested_set_test.rb +14 -2
- data/test/mixin_test.rb +56 -18
- data/test/modules_test.rb +8 -2
- data/test/multiple_db_test.rb +2 -2
- data/test/pk_test.rb +1 -0
- data/test/reflection_test.rb +8 -2
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +40 -4
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +19 -16
- data/test/transactions_test.rb +86 -72
- data/test/validations_test.rb +126 -56
- data/test/xml_serialization_test.rb +125 -0
- metadata +45 -11
- data/lib/active_record/locking.rb +0 -79
@@ -1,10 +1,12 @@
|
|
1
|
-
require '
|
1
|
+
require 'date'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'bigdecimal/util'
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters #:nodoc:
|
5
7
|
# An abstract definition of a column in a table.
|
6
8
|
class Column
|
7
|
-
attr_reader :name, :default, :type, :limit, :null, :sql_type
|
9
|
+
attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
|
8
10
|
attr_accessor :primary
|
9
11
|
|
10
12
|
# Instantiates a new column in the table.
|
@@ -14,22 +16,20 @@ module ActiveRecord
|
|
14
16
|
# +sql_type+ is only used to extract the column's length, if necessary. For example, <tt>company_name varchar(<b>60</b>)</tt>.
|
15
17
|
# +null+ determines if this column allows +NULL+ values.
|
16
18
|
def initialize(name, default, sql_type = nil, null = true)
|
17
|
-
@name, @
|
18
|
-
@
|
19
|
-
|
19
|
+
@name, @sql_type, @null = name, sql_type, null
|
20
|
+
@limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
|
21
|
+
@type = simplified_type(sql_type)
|
20
22
|
@default = type_cast(default)
|
21
|
-
|
23
|
+
|
22
24
|
@primary = nil
|
23
|
-
@text = [:string, :text].include? @type
|
24
|
-
@number = [:float, :integer].include? @type
|
25
25
|
end
|
26
26
|
|
27
27
|
def text?
|
28
|
-
|
28
|
+
[:string, :text].include? type
|
29
29
|
end
|
30
30
|
|
31
31
|
def number?
|
32
|
-
|
32
|
+
[:float, :integer, :decimal].include? type
|
33
33
|
end
|
34
34
|
|
35
35
|
# Returns the Ruby class that corresponds to the abstract data type.
|
@@ -37,6 +37,7 @@ module ActiveRecord
|
|
37
37
|
case type
|
38
38
|
when :integer then Fixnum
|
39
39
|
when :float then Float
|
40
|
+
when :decimal then BigDecimal
|
40
41
|
when :datetime then Time
|
41
42
|
when :date then Date
|
42
43
|
when :timestamp then Time
|
@@ -55,6 +56,7 @@ module ActiveRecord
|
|
55
56
|
when :text then value
|
56
57
|
when :integer then value.to_i rescue value ? 1 : 0
|
57
58
|
when :float then value.to_f
|
59
|
+
when :decimal then self.class.value_to_decimal(value)
|
58
60
|
when :datetime then self.class.string_to_time(value)
|
59
61
|
when :timestamp then self.class.string_to_time(value)
|
60
62
|
when :time then self.class.string_to_dummy_time(value)
|
@@ -71,6 +73,7 @@ module ActiveRecord
|
|
71
73
|
when :text then nil
|
72
74
|
when :integer then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
|
73
75
|
when :float then "#{var_name}.to_f"
|
76
|
+
when :decimal then "#{self.class.name}.value_to_decimal(#{var_name})"
|
74
77
|
when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
|
75
78
|
when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
|
76
79
|
when :time then "#{self.class.name}.string_to_dummy_time(#{var_name})"
|
@@ -108,39 +111,74 @@ module ActiveRecord
|
|
108
111
|
|
109
112
|
def self.string_to_time(string)
|
110
113
|
return string unless string.is_a?(String)
|
111
|
-
|
114
|
+
time_hash = Date._parse(string)
|
115
|
+
time_hash[:sec_fraction] = microseconds(time_hash)
|
116
|
+
time_array = time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction)
|
112
117
|
# treat 0000-00-00 00:00:00 as nil
|
113
|
-
Time.send(Base.default_timezone, *time_array) rescue nil
|
118
|
+
Time.send(Base.default_timezone, *time_array) rescue DateTime.new(*time_array[0..5]) rescue nil
|
114
119
|
end
|
115
120
|
|
116
121
|
def self.string_to_dummy_time(string)
|
117
122
|
return string unless string.is_a?(String)
|
118
|
-
|
123
|
+
return nil if string.empty?
|
124
|
+
time_hash = Date._parse(string)
|
125
|
+
time_hash[:sec_fraction] = microseconds(time_hash)
|
119
126
|
# pad the resulting array with dummy date information
|
120
|
-
time_array
|
127
|
+
time_array = [2000, 1, 1]
|
128
|
+
time_array += time_hash.values_at(:hour, :min, :sec, :sec_fraction)
|
121
129
|
Time.send(Base.default_timezone, *time_array) rescue nil
|
122
130
|
end
|
123
131
|
|
124
132
|
# convert something to a boolean
|
125
133
|
def self.value_to_boolean(value)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
134
|
+
if value == true || value == false
|
135
|
+
value
|
136
|
+
else
|
137
|
+
%w(true t 1).include?(value.to_s.downcase)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# convert something to a BigDecimal
|
142
|
+
def self.value_to_decimal(value)
|
143
|
+
if value.is_a?(BigDecimal)
|
144
|
+
value
|
145
|
+
elsif value.respond_to?(:to_d)
|
146
|
+
value.to_d
|
147
|
+
else
|
148
|
+
value.to_s.to_d
|
130
149
|
end
|
131
150
|
end
|
132
151
|
|
133
|
-
|
152
|
+
private
|
153
|
+
# '0.123456' -> 123456
|
154
|
+
# '1.123456' -> 123456
|
155
|
+
def self.microseconds(time)
|
156
|
+
((time[:sec_fraction].to_f % 1) * 1_000_000).to_i
|
157
|
+
end
|
158
|
+
|
134
159
|
def extract_limit(sql_type)
|
135
160
|
$1.to_i if sql_type =~ /\((.*)\)/
|
136
161
|
end
|
137
162
|
|
163
|
+
def extract_precision(sql_type)
|
164
|
+
$2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
|
165
|
+
end
|
166
|
+
|
167
|
+
def extract_scale(sql_type)
|
168
|
+
case sql_type
|
169
|
+
when /^(numeric|decimal|number)\((\d+)\)/i then 0
|
170
|
+
when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
138
174
|
def simplified_type(field_type)
|
139
175
|
case field_type
|
140
176
|
when /int/i
|
141
177
|
:integer
|
142
|
-
when /float|double
|
178
|
+
when /float|double/i
|
143
179
|
:float
|
180
|
+
when /decimal|numeric|number/i
|
181
|
+
extract_scale(field_type) == 0 ? :integer : :decimal
|
144
182
|
when /datetime/i
|
145
183
|
:datetime
|
146
184
|
when /timestamp/i
|
@@ -164,18 +202,20 @@ module ActiveRecord
|
|
164
202
|
class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
|
165
203
|
end
|
166
204
|
|
167
|
-
class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :default, :null) #:nodoc:
|
205
|
+
class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
|
206
|
+
|
207
|
+
def sql_type
|
208
|
+
base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
|
209
|
+
end
|
210
|
+
|
168
211
|
def to_sql
|
169
|
-
column_sql = "#{base.quote_column_name(name)} #{
|
170
|
-
add_column_options!(column_sql, :null => null, :default => default)
|
212
|
+
column_sql = "#{base.quote_column_name(name)} #{sql_type}"
|
213
|
+
add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key
|
171
214
|
column_sql
|
172
215
|
end
|
173
216
|
alias to_s :to_sql
|
174
217
|
|
175
218
|
private
|
176
|
-
def type_to_sql(name, limit)
|
177
|
-
base.type_to_sql(name, limit) rescue name
|
178
|
-
end
|
179
219
|
|
180
220
|
def add_column_options!(sql, options)
|
181
221
|
base.add_column_options!(sql, options.merge(:column => self))
|
@@ -195,7 +235,7 @@ module ActiveRecord
|
|
195
235
|
# Appends a primary key definition to the table definition.
|
196
236
|
# Can be called multiple times, but this is probably not a good idea.
|
197
237
|
def primary_key(name)
|
198
|
-
column(name,
|
238
|
+
column(name, :primary_key)
|
199
239
|
end
|
200
240
|
|
201
241
|
# Returns a ColumnDefinition for the column with name +name+.
|
@@ -206,37 +246,81 @@ module ActiveRecord
|
|
206
246
|
# Instantiates a new column for the table.
|
207
247
|
# The +type+ parameter must be one of the following values:
|
208
248
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
209
|
-
# <tt>:integer</tt>, <tt>:float</tt>, <tt>:
|
210
|
-
# <tt>:
|
211
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
249
|
+
# <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
|
250
|
+
# <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
|
251
|
+
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
|
212
252
|
#
|
213
253
|
# Available options are (none of these exists by default):
|
214
254
|
# * <tt>:limit</tt>:
|
215
255
|
# Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
|
216
256
|
# <tt>:binary</tt> or <tt>:integer</tt> columns only)
|
217
257
|
# * <tt>:default</tt>:
|
218
|
-
# The column's default value.
|
219
|
-
# value to +NULL+. Simply leave off this option if you want a +NULL+
|
220
|
-
# default value.
|
258
|
+
# The column's default value. Use nil for NULL.
|
221
259
|
# * <tt>:null</tt>:
|
222
260
|
# Allows or disallows +NULL+ values in the column. This option could
|
223
261
|
# have been named <tt>:null_allowed</tt>.
|
262
|
+
# * <tt>:precision</tt>:
|
263
|
+
# Specifies the precision for a <tt>:decimal</tt> column.
|
264
|
+
# * <tt>:scale</tt>:
|
265
|
+
# Specifies the scale for a <tt>:decimal</tt> column.
|
266
|
+
#
|
267
|
+
# Please be aware of different RDBMS implementations behavior with
|
268
|
+
# <tt>:decimal</tt> columns:
|
269
|
+
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
270
|
+
# <tt>:precision</tt>, and makes no comments about the requirements of
|
271
|
+
# <tt>:precision</tt>.
|
272
|
+
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
273
|
+
# Default is (10,0).
|
274
|
+
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
275
|
+
# <tt>:scale</tt> [0..infinity]. No default.
|
276
|
+
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
|
277
|
+
# Internal storage as strings. No default.
|
278
|
+
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
279
|
+
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
280
|
+
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
281
|
+
# Default is (38,0).
|
282
|
+
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
283
|
+
# Default unknown.
|
284
|
+
# * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
|
285
|
+
# Default (9,0). Internal types NUMERIC and DECIMAL have different
|
286
|
+
# storage rules, decimal being better.
|
287
|
+
# * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
288
|
+
# Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
|
289
|
+
# NUMERIC is 19, and DECIMAL is 38.
|
290
|
+
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
291
|
+
# Default (38,0).
|
292
|
+
# * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
293
|
+
# Default (38,0).
|
294
|
+
# * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
|
224
295
|
#
|
225
296
|
# This method returns <tt>self</tt>.
|
226
297
|
#
|
227
298
|
# ===== Examples
|
228
|
-
# # Assuming
|
229
|
-
#
|
299
|
+
# # Assuming td is an instance of TableDefinition
|
300
|
+
# td.column(:granted, :boolean)
|
230
301
|
# #=> granted BOOLEAN
|
231
302
|
#
|
232
|
-
#
|
303
|
+
# td.column(:picture, :binary, :limit => 2.megabytes)
|
233
304
|
# #=> picture BLOB(2097152)
|
234
305
|
#
|
235
|
-
#
|
306
|
+
# td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
|
236
307
|
# #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
|
308
|
+
#
|
309
|
+
# def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
|
310
|
+
# #=> bill_gates_money DECIMAL(15,2)
|
311
|
+
#
|
312
|
+
# def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
|
313
|
+
# #=> sensor_reading DECIMAL(30,20)
|
314
|
+
#
|
315
|
+
# # While <tt>:scale</tt> defaults to zero on most databases, it
|
316
|
+
# # probably wouldn't hurt to include it.
|
317
|
+
# def.column(:huge_integer, :decimal, :precision => 30)
|
318
|
+
# #=> huge_integer DECIMAL(30)
|
237
319
|
def column(name, type, options = {})
|
238
320
|
column = self[name] || ColumnDefinition.new(@base, name, type)
|
239
321
|
column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
|
322
|
+
column.precision = options[:precision]
|
323
|
+
column.scale = options[:scale]
|
240
324
|
column.default = options[:default]
|
241
325
|
column.null = options[:null]
|
242
326
|
@columns << column unless @columns.include? column
|
@@ -44,8 +44,8 @@ module ActiveRecord
|
|
44
44
|
#
|
45
45
|
# The +options+ hash can include the following keys:
|
46
46
|
# [<tt>:id</tt>]
|
47
|
-
#
|
48
|
-
#
|
47
|
+
# Whether to automatically add a primary key column. Defaults to true.
|
48
|
+
# Join tables for has_and_belongs_to_many should set :id => false.
|
49
49
|
# [<tt>:primary_key</tt>]
|
50
50
|
# The name of the primary key, if one is to be added automatically.
|
51
51
|
# Defaults to +id+.
|
@@ -94,7 +94,7 @@ module ActiveRecord
|
|
94
94
|
yield table_definition
|
95
95
|
|
96
96
|
if options[:force]
|
97
|
-
drop_table(name) rescue nil
|
97
|
+
drop_table(name, options) rescue nil
|
98
98
|
end
|
99
99
|
|
100
100
|
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
@@ -112,14 +112,14 @@ module ActiveRecord
|
|
112
112
|
end
|
113
113
|
|
114
114
|
# Drops a table from the database.
|
115
|
-
def drop_table(name)
|
115
|
+
def drop_table(name, options = {})
|
116
116
|
execute "DROP TABLE #{name}"
|
117
117
|
end
|
118
118
|
|
119
119
|
# Adds a new column to the named table.
|
120
120
|
# See TableDefinition#column for details of the options you can use.
|
121
121
|
def add_column(table_name, column_name, type, options = {})
|
122
|
-
add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
|
122
|
+
add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
123
123
|
add_column_options!(add_column_sql, options)
|
124
124
|
execute(add_column_sql)
|
125
125
|
end
|
@@ -178,14 +178,14 @@ module ActiveRecord
|
|
178
178
|
# ====== Creating a unique index
|
179
179
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true)
|
180
180
|
# generates
|
181
|
-
# CREATE UNIQUE INDEX
|
181
|
+
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
182
182
|
# ====== Creating a named index
|
183
183
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
|
184
184
|
# generates
|
185
185
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
186
186
|
def add_index(table_name, column_name, options = {})
|
187
187
|
column_names = Array(column_name)
|
188
|
-
index_name = index_name(table_name, :column => column_names
|
188
|
+
index_name = index_name(table_name, :column => column_names)
|
189
189
|
|
190
190
|
if Hash === options # legacy support, since this param was a string
|
191
191
|
index_type = options[:unique] ? "UNIQUE" : ""
|
@@ -199,16 +199,14 @@ module ActiveRecord
|
|
199
199
|
|
200
200
|
# Remove the given index from the table.
|
201
201
|
#
|
202
|
-
# Remove the suppliers_name_index in the suppliers table
|
202
|
+
# Remove the suppliers_name_index in the suppliers table.
|
203
203
|
# remove_index :suppliers, :name
|
204
|
-
# Remove the index named
|
204
|
+
# Remove the index named accounts_branch_id_index in the accounts table.
|
205
205
|
# remove_index :accounts, :column => :branch_id
|
206
|
+
# Remove the index named accounts_branch_id_party_id_index in the accounts table.
|
207
|
+
# remove_index :accounts, :column => [:branch_id, :party_id]
|
206
208
|
# Remove the index named by_branch_party in the accounts table.
|
207
209
|
# remove_index :accounts, :name => :by_branch_party
|
208
|
-
#
|
209
|
-
# You can remove an index on multiple columns by specifying the first column.
|
210
|
-
# add_index :accounts, [:username, :password]
|
211
|
-
# remove_index :accounts, :username
|
212
210
|
def remove_index(table_name, options = {})
|
213
211
|
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
|
214
212
|
end
|
@@ -216,14 +214,14 @@ module ActiveRecord
|
|
216
214
|
def index_name(table_name, options) #:nodoc:
|
217
215
|
if Hash === options # legacy support
|
218
216
|
if options[:column]
|
219
|
-
"#{table_name}
|
217
|
+
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
220
218
|
elsif options[:name]
|
221
219
|
options[:name]
|
222
220
|
else
|
223
221
|
raise ArgumentError, "You must specify the index name"
|
224
222
|
end
|
225
223
|
else
|
226
|
-
|
224
|
+
index_name(table_name, :column => options)
|
227
225
|
end
|
228
226
|
end
|
229
227
|
|
@@ -254,18 +252,52 @@ module ActiveRecord
|
|
254
252
|
end
|
255
253
|
|
256
254
|
|
257
|
-
def type_to_sql(type, limit = nil) #:nodoc:
|
255
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
258
256
|
native = native_database_types[type]
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
257
|
+
column_type_sql = native.is_a?(Hash) ? native[:name] : native
|
258
|
+
if type == :decimal # ignore limit, use precison and scale
|
259
|
+
precision ||= native[:precision]
|
260
|
+
scale ||= native[:scale]
|
261
|
+
if precision
|
262
|
+
if scale
|
263
|
+
column_type_sql << "(#{precision},#{scale})"
|
264
|
+
else
|
265
|
+
column_type_sql << "(#{precision})"
|
266
|
+
end
|
267
|
+
else
|
268
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" if scale
|
269
|
+
end
|
270
|
+
column_type_sql
|
271
|
+
else
|
272
|
+
limit ||= native[:limit]
|
273
|
+
column_type_sql << "(#{limit})" if limit
|
274
|
+
column_type_sql
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
265
278
|
def add_column_options!(sql, options) #:nodoc:
|
266
|
-
sql << " DEFAULT #{quote(options[:default], options[:column])}"
|
279
|
+
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
|
267
280
|
sql << " NOT NULL" if options[:null] == false
|
268
281
|
end
|
282
|
+
|
283
|
+
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
284
|
+
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
|
285
|
+
#
|
286
|
+
# distinct("posts.id", "posts.created_at desc")
|
287
|
+
def distinct(columns, order_by)
|
288
|
+
"DISTINCT #{columns}"
|
289
|
+
end
|
290
|
+
|
291
|
+
# ORDER BY clause for the passed order option.
|
292
|
+
# PostgreSQL overrides this due to its stricter standards compliance.
|
293
|
+
def add_order_by_for_association_limiting!(sql, options)
|
294
|
+
sql << "ORDER BY #{options[:order]}"
|
295
|
+
end
|
296
|
+
|
297
|
+
protected
|
298
|
+
def options_include_default?(options)
|
299
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
300
|
+
end
|
269
301
|
end
|
270
302
|
end
|
271
303
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'benchmark'
|
2
2
|
require 'date'
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'bigdecimal/util'
|
3
5
|
|
4
6
|
require 'active_record/connection_adapters/abstract/schema_definitions'
|
5
7
|
require 'active_record/connection_adapters/abstract/schema_statements'
|
@@ -77,6 +79,12 @@ module ActiveRecord
|
|
77
79
|
@active = false
|
78
80
|
end
|
79
81
|
|
82
|
+
# Returns true if its safe to reload the connection between requests for development mode.
|
83
|
+
# This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
|
84
|
+
def requires_reloading?
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
80
88
|
# Lazily verify this connection, calling +active?+ only if it hasn't
|
81
89
|
# been called for +timeout+ seconds.
|
82
90
|
def verify!(timeout)
|
@@ -47,14 +47,6 @@ begin
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
51
|
-
def select_all(sql, name = nil)
|
52
|
-
select(sql, name)
|
53
|
-
end
|
54
|
-
|
55
|
-
def select_one(sql, name = nil)
|
56
|
-
select(sql, name).first
|
57
|
-
end
|
58
50
|
|
59
51
|
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
60
52
|
execute(sql, name = nil)
|
@@ -72,9 +64,6 @@ begin
|
|
72
64
|
rows_affected
|
73
65
|
end
|
74
66
|
|
75
|
-
alias_method :update, :execute
|
76
|
-
alias_method :delete, :execute
|
77
|
-
|
78
67
|
def begin_db_transaction
|
79
68
|
@connection.set_auto_commit_off
|
80
69
|
end
|
@@ -162,6 +151,7 @@ begin
|
|
162
151
|
:text => { :name => 'clob', :limit => 32768 },
|
163
152
|
:integer => { :name => 'int' },
|
164
153
|
:float => { :name => 'float' },
|
154
|
+
:decimal => { :name => 'decimal' },
|
165
155
|
:datetime => { :name => 'timestamp' },
|
166
156
|
:timestamp => { :name => 'timestamp' },
|
167
157
|
:time => { :name => 'time' },
|