activerecord 1.15.6 → 2.0.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 +2454 -34
- data/README +1 -1
- data/RUNNING_UNIT_TESTS +3 -34
- data/Rakefile +98 -77
- data/install.rb +1 -1
- data/lib/active_record.rb +13 -22
- data/lib/active_record/aggregations.rb +38 -49
- data/lib/active_record/associations.rb +452 -333
- data/lib/active_record/associations/association_collection.rb +66 -20
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +38 -18
- data/lib/active_record/associations/has_one_association.rb +30 -14
- data/lib/active_record/attribute_methods.rb +253 -0
- data/lib/active_record/base.rb +719 -494
- data/lib/active_record/calculations.rb +62 -63
- data/lib/active_record/callbacks.rb +57 -83
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
- data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
- data/lib/active_record/fixtures.rb +503 -113
- data/lib/active_record/locking/optimistic.rb +72 -34
- data/lib/active_record/migration.rb +80 -57
- data/lib/active_record/observer.rb +13 -10
- data/lib/active_record/query_cache.rb +16 -57
- data/lib/active_record/reflection.rb +35 -38
- data/lib/active_record/schema.rb +5 -5
- data/lib/active_record/schema_dumper.rb +35 -13
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
- data/lib/active_record/timestamp.rb +20 -21
- data/lib/active_record/transactions.rb +39 -43
- data/lib/active_record/validations.rb +256 -107
- data/lib/active_record/version.rb +3 -3
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +15 -2
- data/test/abstract_unit.rb +24 -17
- data/test/active_schema_test_mysql.rb +20 -8
- data/test/adapter_test.rb +23 -5
- data/test/adapter_test_sqlserver.rb +15 -1
- data/test/aggregations_test.rb +16 -1
- data/test/all.sh +2 -2
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +51 -30
- data/test/associations/cascaded_eager_loading_test.rb +1 -29
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +42 -6
- data/test/associations/extension_test.rb +6 -1
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +47 -16
- data/test/associations_test.rb +449 -226
- data/test/attribute_methods_test.rb +97 -0
- data/test/base_test.rb +251 -105
- data/test/binary_test.rb +22 -27
- data/test/calculations_test.rb +37 -5
- data/test/callbacks_test.rb +23 -0
- data/test/connection_test_firebird.rb +2 -2
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_mysql/connection.rb +3 -0
- data/test/connections/native_sqlite/connection.rb +5 -14
- data/test/connections/native_sqlite3/connection.rb +5 -14
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
- data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
- data/test/datatype_test_postgresql.rb +178 -27
- data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
- data/test/defaults_test.rb +8 -1
- data/test/deprecated_finder_test.rb +7 -128
- data/test/finder_test.rb +192 -54
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +12 -5
- data/test/fixtures/binaries.yml +130 -435
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +8 -1
- data/test/fixtures/computer.rb +1 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +4 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
- data/test/fixtures/db_definitions/firebird.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase.sql +5 -0
- data/test/fixtures/db_definitions/openbase.sql +41 -25
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +87 -58
- data/test/fixtures/db_definitions/postgresql2.sql +1 -2
- data/test/fixtures/db_definitions/schema.rb +280 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +4 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
- data/test/fixtures/db_definitions/sybase.sql +4 -0
- data/test/fixtures/developer.rb +10 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +0 -3
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixins.yml +2 -100
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +1 -0
- data/test/fixtures/project.rb +3 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/tagging.rb +4 -0
- data/test/fixtures/taggings.yml +8 -1
- data/test/fixtures/topic.rb +13 -1
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures_test.rb +205 -24
- data/test/inheritance_test.rb +7 -1
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +1 -1
- data/test/locking_test.rb +85 -2
- data/test/migration_test.rb +206 -40
- data/test/mixin_test.rb +13 -515
- data/test/pk_test.rb +3 -6
- data/test/query_cache_test.rb +104 -0
- data/test/reflection_test.rb +16 -0
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_dumper_test.rb +38 -3
- data/test/serialization_test.rb +47 -0
- data/test/transactions_test.rb +74 -23
- data/test/unconnected_test.rb +1 -1
- data/test/validations_test.rb +322 -32
- data/test/xml_serialization_test.rb +121 -44
- metadata +48 -41
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -85
- data/lib/active_record/acts/list.rb +0 -256
- data/lib/active_record/acts/nested_set.rb +0 -211
- data/lib/active_record/acts/tree.rb +0 -96
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
- data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
- data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
- data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
- data/lib/active_record/deprecated_associations.rb +0 -104
- data/lib/active_record/deprecated_finders.rb +0 -44
- data/lib/active_record/vendor/simple.rb +0 -693
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -58
- data/test/connections/native_sqlserver/connection.rb +0 -23
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
- data/test/deprecated_associations_test.rb +0 -396
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
- data/test/fixtures/db_definitions/mysql.sql +0 -234
- data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/mysql2.sql +0 -5
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
- data/test/fixtures/db_definitions/sqlserver.sql +0 -243
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
- data/test/fixtures/mixin.rb +0 -63
- data/test/mixin_nested_set_test.rb +0 -196
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
# [<tt>:temporary</tt>]
|
55
55
|
# Make a temporary table.
|
56
56
|
# [<tt>:force</tt>]
|
57
|
-
# Set to true
|
57
|
+
# Set to true to drop the table before creating it.
|
58
58
|
# Defaults to false.
|
59
59
|
#
|
60
60
|
# ===== Examples
|
@@ -81,45 +81,45 @@ module ActiveRecord
|
|
81
81
|
# t.column :supplier_id, :integer
|
82
82
|
# end
|
83
83
|
# generates:
|
84
|
-
# CREATE TABLE
|
84
|
+
# CREATE TABLE categories_suppliers (
|
85
85
|
# category_id int,
|
86
86
|
# supplier_id int
|
87
87
|
# )
|
88
88
|
#
|
89
89
|
# See also TableDefinition#column for details on how to create columns.
|
90
|
-
def create_table(
|
90
|
+
def create_table(table_name, options = {})
|
91
91
|
table_definition = TableDefinition.new(self)
|
92
92
|
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
|
93
93
|
|
94
94
|
yield table_definition
|
95
95
|
|
96
96
|
if options[:force]
|
97
|
-
drop_table(
|
97
|
+
drop_table(table_name, options) rescue nil
|
98
98
|
end
|
99
99
|
|
100
100
|
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
101
|
-
create_sql << "#{
|
101
|
+
create_sql << "#{quote_table_name(table_name)} ("
|
102
102
|
create_sql << table_definition.to_sql
|
103
103
|
create_sql << ") #{options[:options]}"
|
104
104
|
execute create_sql
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# Renames a table.
|
108
108
|
# ===== Example
|
109
109
|
# rename_table('octopuses', 'octopi')
|
110
|
-
def rename_table(
|
110
|
+
def rename_table(table_name, new_name)
|
111
111
|
raise NotImplementedError, "rename_table is not implemented"
|
112
112
|
end
|
113
113
|
|
114
114
|
# Drops a table from the database.
|
115
|
-
def drop_table(
|
116
|
-
execute "DROP TABLE #{
|
115
|
+
def drop_table(table_name, options = {})
|
116
|
+
execute "DROP TABLE #{quote_table_name(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], options[:precision], options[:scale])}"
|
122
|
+
add_column_sql = "ALTER TABLE #{quote_table_name(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
|
@@ -128,7 +128,7 @@ module ActiveRecord
|
|
128
128
|
# ===== Examples
|
129
129
|
# remove_column(:suppliers, :qualification)
|
130
130
|
def remove_column(table_name, column_name)
|
131
|
-
execute "ALTER TABLE #{table_name} DROP #{quote_column_name(column_name)}"
|
131
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
132
132
|
end
|
133
133
|
|
134
134
|
# Changes the column's definition according to the new options.
|
@@ -142,7 +142,7 @@ module ActiveRecord
|
|
142
142
|
|
143
143
|
# Sets a new default value for a column. If you want to set the default
|
144
144
|
# value to +NULL+, you are out of luck. You need to
|
145
|
-
# DatabaseStatements#execute the
|
145
|
+
# DatabaseStatements#execute the appropriate SQL statement yourself.
|
146
146
|
# ===== Examples
|
147
147
|
# change_column_default(:suppliers, :qualification, 'new')
|
148
148
|
# change_column_default(:accounts, :authorized, 1)
|
@@ -160,13 +160,13 @@ module ActiveRecord
|
|
160
160
|
# Adds a new index to the table. +column_name+ can be a single Symbol, or
|
161
161
|
# an Array of Symbols.
|
162
162
|
#
|
163
|
-
# The index will be named after the table and the first column
|
163
|
+
# The index will be named after the table and the first column name,
|
164
164
|
# unless you pass +:name+ as an option.
|
165
165
|
#
|
166
166
|
# When creating an index on multiple columns, the first column is used as a name
|
167
167
|
# for the index. For example, when you specify an index on two columns
|
168
168
|
# [+:first+, +:last+], the DBMS creates an index for both columns as well as an
|
169
|
-
# index for the first
|
169
|
+
# index for the first column +:first+. Using just the first name for this index
|
170
170
|
# makes sense, because you will never have to create a singular index with this
|
171
171
|
# name.
|
172
172
|
#
|
@@ -194,7 +194,7 @@ module ActiveRecord
|
|
194
194
|
index_type = options
|
195
195
|
end
|
196
196
|
quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
|
197
|
-
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{table_name} (#{quoted_column_names})"
|
197
|
+
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
|
198
198
|
end
|
199
199
|
|
200
200
|
# Remove the given index from the table.
|
@@ -234,17 +234,17 @@ module ActiveRecord
|
|
234
234
|
# The migrations module handles this automatically.
|
235
235
|
def initialize_schema_information
|
236
236
|
begin
|
237
|
-
execute "CREATE TABLE #{ActiveRecord::Migrator.schema_info_table_name} (version #{type_to_sql(:integer)})"
|
238
|
-
execute "INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} (version) VALUES(0)"
|
237
|
+
execute "CREATE TABLE #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version #{type_to_sql(:integer)})"
|
238
|
+
execute "INSERT INTO #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version) VALUES(0)"
|
239
239
|
rescue ActiveRecord::StatementInvalid
|
240
|
-
# Schema has been
|
240
|
+
# Schema has been initialized
|
241
241
|
end
|
242
242
|
end
|
243
243
|
|
244
244
|
def dump_schema_information #:nodoc:
|
245
245
|
begin
|
246
246
|
if (current_schema = ActiveRecord::Migrator.current_version) > 0
|
247
|
-
return "INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} (version) VALUES (#{current_schema})"
|
247
|
+
return "INSERT INTO #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version) VALUES (#{current_schema})"
|
248
248
|
end
|
249
249
|
rescue ActiveRecord::StatementInvalid
|
250
250
|
# No Schema Info
|
@@ -253,25 +253,28 @@ module ActiveRecord
|
|
253
253
|
|
254
254
|
|
255
255
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
256
|
-
native = native_database_types[type]
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
256
|
+
if native = native_database_types[type]
|
257
|
+
column_type_sql = native.is_a?(Hash) ? native[:name] : native
|
258
|
+
if type == :decimal # ignore limit, use precision 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
|
264
267
|
else
|
265
|
-
|
268
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" if scale
|
266
269
|
end
|
270
|
+
column_type_sql
|
267
271
|
else
|
268
|
-
|
272
|
+
limit ||= native[:limit]
|
273
|
+
column_type_sql << "(#{limit})" if limit
|
274
|
+
column_type_sql
|
269
275
|
end
|
270
|
-
column_type_sql
|
271
276
|
else
|
272
|
-
|
273
|
-
column_type_sql << "(#{limit})" if limit
|
274
|
-
column_type_sql
|
277
|
+
column_type_sql = type
|
275
278
|
end
|
276
279
|
end
|
277
280
|
|
@@ -291,7 +294,7 @@ module ActiveRecord
|
|
291
294
|
# ORDER BY clause for the passed order option.
|
292
295
|
# PostgreSQL overrides this due to its stricter standards compliance.
|
293
296
|
def add_order_by_for_association_limiting!(sql, options)
|
294
|
-
sql << "ORDER BY #{options[:order]}"
|
297
|
+
sql << " ORDER BY #{options[:order]}"
|
295
298
|
end
|
296
299
|
|
297
300
|
protected
|
@@ -8,6 +8,7 @@ require 'active_record/connection_adapters/abstract/schema_statements'
|
|
8
8
|
require 'active_record/connection_adapters/abstract/database_statements'
|
9
9
|
require 'active_record/connection_adapters/abstract/quoting'
|
10
10
|
require 'active_record/connection_adapters/abstract/connection_specification'
|
11
|
+
require 'active_record/connection_adapters/abstract/query_cache'
|
11
12
|
|
12
13
|
module ActiveRecord
|
13
14
|
module ConnectionAdapters # :nodoc:
|
@@ -22,8 +23,9 @@ module ActiveRecord
|
|
22
23
|
# SchemaStatements#remove_column are very useful.
|
23
24
|
class AbstractAdapter
|
24
25
|
include Quoting, DatabaseStatements, SchemaStatements
|
26
|
+
include QueryCache
|
25
27
|
@@row_even = true
|
26
|
-
|
28
|
+
|
27
29
|
def initialize(connection, logger = nil) #:nodoc:
|
28
30
|
@connection, @logger = connection, logger
|
29
31
|
@runtime = 0
|
@@ -41,7 +43,7 @@ module ActiveRecord
|
|
41
43
|
def supports_migrations?
|
42
44
|
false
|
43
45
|
end
|
44
|
-
|
46
|
+
|
45
47
|
# Does this adapter support using DISTINCT within COUNT? This is +true+
|
46
48
|
# for all adapters except sqlite.
|
47
49
|
def supports_count_distinct?
|
@@ -61,6 +63,19 @@ module ActiveRecord
|
|
61
63
|
rt
|
62
64
|
end
|
63
65
|
|
66
|
+
# QUOTING ==================================================
|
67
|
+
|
68
|
+
# Override to return the quoted table name if the database needs it
|
69
|
+
def quote_table_name(name)
|
70
|
+
name
|
71
|
+
end
|
72
|
+
|
73
|
+
# REFERENTIAL INTEGRITY ====================================
|
74
|
+
|
75
|
+
# Override to turn off referential integrity while executing +&block+
|
76
|
+
def disable_referential_integrity(&block)
|
77
|
+
yield
|
78
|
+
end
|
64
79
|
|
65
80
|
# CONNECTION MANAGEMENT ====================================
|
66
81
|
|
@@ -86,7 +101,7 @@ module ActiveRecord
|
|
86
101
|
end
|
87
102
|
|
88
103
|
# Lazily verify this connection, calling +active?+ only if it hasn't
|
89
|
-
# been called for +timeout+ seconds.
|
104
|
+
# been called for +timeout+ seconds.
|
90
105
|
def verify!(timeout)
|
91
106
|
now = Time.now.to_i
|
92
107
|
if (now - @last_verification) > timeout
|
@@ -94,7 +109,7 @@ module ActiveRecord
|
|
94
109
|
@last_verification = now
|
95
110
|
end
|
96
111
|
end
|
97
|
-
|
112
|
+
|
98
113
|
# Provides access to the underlying database connection. Useful for
|
99
114
|
# when you need to call a proprietary method such as postgresql's lo_*
|
100
115
|
# methods
|
@@ -102,10 +117,17 @@ module ActiveRecord
|
|
102
117
|
@connection
|
103
118
|
end
|
104
119
|
|
120
|
+
def log_info(sql, name, runtime)
|
121
|
+
if @logger && @logger.debug?
|
122
|
+
name = "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})"
|
123
|
+
@logger.debug format_log_entry(name, sql.squeeze(' '))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
105
127
|
protected
|
106
128
|
def log(sql, name)
|
107
129
|
if block_given?
|
108
|
-
if @logger and @logger.
|
130
|
+
if @logger and @logger.debug?
|
109
131
|
result = nil
|
110
132
|
seconds = Benchmark.realtime { result = yield }
|
111
133
|
@runtime += seconds
|
@@ -120,7 +142,7 @@ module ActiveRecord
|
|
120
142
|
end
|
121
143
|
rescue Exception => e
|
122
144
|
# Log message and raise exception.
|
123
|
-
# Set
|
145
|
+
# Set last_verification to 0, so that connection gets verified
|
124
146
|
# upon reentering the request loop
|
125
147
|
@last_verification = 0
|
126
148
|
message = "#{e.class.name}: #{e.message}: #{sql}"
|
@@ -128,17 +150,6 @@ module ActiveRecord
|
|
128
150
|
raise ActiveRecord::StatementInvalid, message
|
129
151
|
end
|
130
152
|
|
131
|
-
def log_info(sql, name, runtime)
|
132
|
-
return unless @logger
|
133
|
-
|
134
|
-
@logger.debug(
|
135
|
-
format_log_entry(
|
136
|
-
"#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})",
|
137
|
-
sql.gsub(/ +/, " ")
|
138
|
-
)
|
139
|
-
)
|
140
|
-
end
|
141
|
-
|
142
153
|
def format_log_entry(message, dump = nil)
|
143
154
|
if ActiveRecord::Base.colorize_logging
|
144
155
|
if @@row_even
|
@@ -33,7 +33,8 @@ module MysqlCompat #:nodoc:
|
|
33
33
|
end_eval
|
34
34
|
end
|
35
35
|
|
36
|
-
unless target.instance_methods.include?('all_hashes')
|
36
|
+
unless target.instance_methods.include?('all_hashes') ||
|
37
|
+
target.instance_methods.include?(:all_hashes)
|
37
38
|
raise "Failed to defined #{target.name}#all_hashes method. Mysql::VERSION = #{Mysql::VERSION.inspect}"
|
38
39
|
end
|
39
40
|
end
|
@@ -49,6 +50,11 @@ module ActiveRecord
|
|
49
50
|
rescue LoadError => cannot_require_mysql
|
50
51
|
# Use the bundled Ruby/MySQL driver if no driver is already in place
|
51
52
|
begin
|
53
|
+
ActiveRecord::Base.logger.info(
|
54
|
+
"WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " +
|
55
|
+
"Please install the C-based MySQL library instead (gem install mysql)."
|
56
|
+
) if ActiveRecord::Base.logger
|
57
|
+
|
52
58
|
require 'active_record/vendor/mysql'
|
53
59
|
rescue LoadError
|
54
60
|
raise cannot_require_mysql
|
@@ -85,12 +91,18 @@ module ActiveRecord
|
|
85
91
|
|
86
92
|
module ConnectionAdapters
|
87
93
|
class MysqlColumn < Column #:nodoc:
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
+
def extract_default(default)
|
95
|
+
if type == :binary || type == :text
|
96
|
+
if default.blank?
|
97
|
+
default
|
98
|
+
else
|
99
|
+
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
100
|
+
end
|
101
|
+
elsif missing_default_forged_as_empty_string?(default)
|
102
|
+
nil
|
103
|
+
else
|
104
|
+
super
|
105
|
+
end
|
94
106
|
end
|
95
107
|
|
96
108
|
private
|
@@ -102,13 +114,13 @@ module ActiveRecord
|
|
102
114
|
|
103
115
|
# MySQL misreports NOT NULL column default when none is given.
|
104
116
|
# We can't detect this for columns which may have a legitimate ''
|
105
|
-
# default (string
|
106
|
-
#
|
117
|
+
# default (string) but we can for others (integer, datetime, boolean,
|
118
|
+
# and the rest).
|
107
119
|
#
|
108
120
|
# Test whether the column has default '', is not null, and is not
|
109
121
|
# a type allowing default ''.
|
110
|
-
def missing_default_forged_as_empty_string?
|
111
|
-
!null &&
|
122
|
+
def missing_default_forged_as_empty_string?(default)
|
123
|
+
type != :string && !null && default == ''
|
112
124
|
end
|
113
125
|
end
|
114
126
|
|
@@ -123,6 +135,7 @@ module ActiveRecord
|
|
123
135
|
# * <tt>:username</tt> -- Defaults to root
|
124
136
|
# * <tt>:password</tt> -- Defaults to nothing
|
125
137
|
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
|
138
|
+
# * <tt>:encoding</tt> -- (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection
|
126
139
|
# * <tt>:sslkey</tt> -- Necessary to use MySQL with an SSL connection
|
127
140
|
# * <tt>:sslcert</tt> -- Necessary to use MySQL with an SSL connection
|
128
141
|
# * <tt>:sslcapath</tt> -- Necessary to use MySQL with an SSL connection
|
@@ -195,6 +208,10 @@ module ActiveRecord
|
|
195
208
|
"`#{name}`"
|
196
209
|
end
|
197
210
|
|
211
|
+
def quote_table_name(name) #:nodoc:
|
212
|
+
quote_column_name(name).gsub('.', '`.`')
|
213
|
+
end
|
214
|
+
|
198
215
|
def quote_string(string) #:nodoc:
|
199
216
|
@connection.quote(string)
|
200
217
|
end
|
@@ -202,11 +219,23 @@ module ActiveRecord
|
|
202
219
|
def quoted_true
|
203
220
|
"1"
|
204
221
|
end
|
205
|
-
|
222
|
+
|
206
223
|
def quoted_false
|
207
224
|
"0"
|
208
225
|
end
|
209
226
|
|
227
|
+
# REFERENTIAL INTEGRITY ====================================
|
228
|
+
|
229
|
+
def disable_referential_integrity(&block) #:nodoc:
|
230
|
+
old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
|
231
|
+
|
232
|
+
begin
|
233
|
+
update("SET FOREIGN_KEY_CHECKS = 0")
|
234
|
+
yield
|
235
|
+
ensure
|
236
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
237
|
+
end
|
238
|
+
end
|
210
239
|
|
211
240
|
# CONNECTION MANAGEMENT ====================================
|
212
241
|
|
@@ -231,7 +260,7 @@ module ActiveRecord
|
|
231
260
|
disconnect!
|
232
261
|
connect
|
233
262
|
end
|
234
|
-
|
263
|
+
|
235
264
|
def disconnect!
|
236
265
|
@connection.close rescue nil
|
237
266
|
end
|
@@ -239,6 +268,15 @@ module ActiveRecord
|
|
239
268
|
|
240
269
|
# DATABASE STATEMENTS ======================================
|
241
270
|
|
271
|
+
def select_rows(sql, name = nil)
|
272
|
+
@connection.query_with_result = true
|
273
|
+
result = execute(sql, name)
|
274
|
+
rows = []
|
275
|
+
result.each { |row| rows << row }
|
276
|
+
result.free
|
277
|
+
rows
|
278
|
+
end
|
279
|
+
|
242
280
|
def execute(sql, name = nil) #:nodoc:
|
243
281
|
log(sql, name) { @connection.query(sql) }
|
244
282
|
rescue ActiveRecord::StatementInvalid => exception
|
@@ -249,13 +287,13 @@ module ActiveRecord
|
|
249
287
|
end
|
250
288
|
end
|
251
289
|
|
252
|
-
def
|
253
|
-
|
290
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
291
|
+
super sql, name
|
254
292
|
id_value || @connection.insert_id
|
255
293
|
end
|
256
294
|
|
257
|
-
def
|
258
|
-
|
295
|
+
def update_sql(sql, name = nil) #:nodoc:
|
296
|
+
super
|
259
297
|
@connection.affected_rows
|
260
298
|
end
|
261
299
|
|
@@ -297,10 +335,10 @@ module ActiveRecord
|
|
297
335
|
else
|
298
336
|
sql = "SHOW TABLES"
|
299
337
|
end
|
300
|
-
|
338
|
+
|
301
339
|
select_all(sql).inject("") do |structure, table|
|
302
340
|
table.delete('Table_type')
|
303
|
-
structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
|
341
|
+
structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n"
|
304
342
|
end
|
305
343
|
end
|
306
344
|
|
@@ -309,16 +347,37 @@ module ActiveRecord
|
|
309
347
|
create_database(name)
|
310
348
|
end
|
311
349
|
|
312
|
-
|
313
|
-
|
350
|
+
# Create a new MySQL database with optional :charset and :collation.
|
351
|
+
# Charset defaults to utf8.
|
352
|
+
#
|
353
|
+
# Example:
|
354
|
+
# create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
|
355
|
+
# create_database 'matt_development'
|
356
|
+
# create_database 'matt_development', :charset => :big5
|
357
|
+
def create_database(name, options = {})
|
358
|
+
if options[:collation]
|
359
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
360
|
+
else
|
361
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
362
|
+
end
|
314
363
|
end
|
315
|
-
|
364
|
+
|
316
365
|
def drop_database(name) #:nodoc:
|
317
366
|
execute "DROP DATABASE IF EXISTS `#{name}`"
|
318
367
|
end
|
319
368
|
|
320
369
|
def current_database
|
321
|
-
|
370
|
+
select_value 'SELECT DATABASE() as db'
|
371
|
+
end
|
372
|
+
|
373
|
+
# Returns the database character set.
|
374
|
+
def charset
|
375
|
+
show_variable 'character_set_database'
|
376
|
+
end
|
377
|
+
|
378
|
+
# Returns the database collation strategy.
|
379
|
+
def collation
|
380
|
+
show_variable 'collation_database'
|
322
381
|
end
|
323
382
|
|
324
383
|
def tables(name = nil) #:nodoc:
|
@@ -327,10 +386,14 @@ module ActiveRecord
|
|
327
386
|
tables
|
328
387
|
end
|
329
388
|
|
389
|
+
def drop_table(table_name, options = {})
|
390
|
+
super(table_name, options)
|
391
|
+
end
|
392
|
+
|
330
393
|
def indexes(table_name, name = nil)#:nodoc:
|
331
394
|
indexes = []
|
332
395
|
current_index = nil
|
333
|
-
execute("SHOW KEYS FROM #{table_name}", name).each do |row|
|
396
|
+
execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name).each do |row|
|
334
397
|
if current_index != row[2]
|
335
398
|
next if row[2] == "PRIMARY" # skip the primary key
|
336
399
|
current_index = row[2]
|
@@ -343,42 +406,61 @@ module ActiveRecord
|
|
343
406
|
end
|
344
407
|
|
345
408
|
def columns(table_name, name = nil)#:nodoc:
|
346
|
-
sql = "SHOW FIELDS FROM #{table_name}"
|
409
|
+
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
347
410
|
columns = []
|
348
411
|
execute(sql, name).each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") }
|
349
412
|
columns
|
350
413
|
end
|
351
414
|
|
352
|
-
def create_table(
|
353
|
-
super(
|
415
|
+
def create_table(table_name, options = {}) #:nodoc:
|
416
|
+
super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
|
417
|
+
end
|
418
|
+
|
419
|
+
def rename_table(table_name, new_name)
|
420
|
+
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
354
421
|
end
|
355
|
-
|
356
|
-
def rename_table(name, new_name)
|
357
|
-
execute "RENAME TABLE #{name} TO #{new_name}"
|
358
|
-
end
|
359
422
|
|
360
423
|
def change_column_default(table_name, column_name, default) #:nodoc:
|
361
|
-
current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Type"]
|
424
|
+
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
362
425
|
|
363
|
-
execute("ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{current_type} DEFAULT #{quote(default)}")
|
426
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}")
|
364
427
|
end
|
365
428
|
|
366
429
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
367
430
|
unless options_include_default?(options)
|
368
|
-
|
431
|
+
if column = columns(table_name).find { |c| c.name == column_name.to_s }
|
432
|
+
options[:default] = column.default
|
433
|
+
else
|
434
|
+
raise "No such column: #{table_name}.#{column_name}"
|
435
|
+
end
|
369
436
|
end
|
370
437
|
|
371
|
-
change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
438
|
+
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
372
439
|
add_column_options!(change_column_sql, options)
|
373
440
|
execute(change_column_sql)
|
374
441
|
end
|
375
442
|
|
376
443
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
377
|
-
current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Type"]
|
378
|
-
execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}"
|
444
|
+
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
445
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
|
379
446
|
end
|
380
447
|
|
381
448
|
|
449
|
+
# SHOW VARIABLES LIKE 'name'
|
450
|
+
def show_variable(name)
|
451
|
+
variables = select_all("SHOW VARIABLES LIKE '#{name}'")
|
452
|
+
variables.first['Value'] unless variables.empty?
|
453
|
+
end
|
454
|
+
|
455
|
+
# Returns a table's primary key and belonging sequence.
|
456
|
+
def pk_and_sequence_for(table) #:nodoc:
|
457
|
+
keys = []
|
458
|
+
execute("describe #{quote_table_name(table)}").each_hash do |h|
|
459
|
+
keys << h["Field"]if h["Key"] == "PRI"
|
460
|
+
end
|
461
|
+
keys.length == 1 ? [keys.first, nil] : nil
|
462
|
+
end
|
463
|
+
|
382
464
|
private
|
383
465
|
def connect
|
384
466
|
encoding = @config[:encoding]
|