activerecord 2.3.18 → 3.0.0.beta
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 +105 -34
- data/examples/performance.rb +3 -39
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +81 -47
- data/lib/active_record/aggregations.rb +1 -3
- data/lib/active_record/association_preload.rb +39 -54
- data/lib/active_record/associations.rb +262 -419
- data/lib/active_record/associations/association_collection.rb +85 -100
- data/lib/active_record/associations/association_proxy.rb +20 -18
- data/lib/active_record/associations/belongs_to_association.rb +8 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
- data/lib/active_record/associations/has_many_association.rb +11 -19
- data/lib/active_record/associations/has_many_through_association.rb +30 -183
- data/lib/active_record/associations/has_one_association.rb +10 -10
- data/lib/active_record/associations/has_one_through_association.rb +13 -11
- data/lib/active_record/associations/through_association_scope.rb +153 -0
- data/lib/active_record/attribute_methods.rb +17 -370
- data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
- data/lib/active_record/attribute_methods/dirty.rb +87 -0
- data/lib/active_record/attribute_methods/primary_key.rb +44 -0
- data/lib/active_record/attribute_methods/query.rb +37 -0
- data/lib/active_record/attribute_methods/read.rb +116 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
- data/lib/active_record/attribute_methods/write.rb +37 -0
- data/lib/active_record/autosave_association.rb +20 -41
- data/lib/active_record/base.rb +357 -1180
- data/lib/active_record/batches.rb +10 -16
- data/lib/active_record/callbacks.rb +66 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
- data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
- data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
- data/lib/active_record/fixtures.rb +21 -25
- data/lib/active_record/locale/en.yml +9 -27
- data/lib/active_record/locking/optimistic.rb +16 -48
- data/lib/active_record/migration.rb +59 -46
- data/lib/active_record/named_scope.rb +85 -92
- data/lib/active_record/nested_attributes.rb +18 -24
- data/lib/active_record/observer.rb +18 -94
- data/lib/active_record/railtie.rb +83 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +477 -0
- data/lib/active_record/railties/subscriber.rb +27 -0
- data/lib/active_record/reflection.rb +2 -15
- data/lib/active_record/relation.rb +339 -0
- data/lib/active_record/relation/calculations.rb +259 -0
- data/lib/active_record/relation/finder_methods.rb +315 -0
- data/lib/active_record/relation/predicate_builder.rb +46 -0
- data/lib/active_record/relation/query_methods.rb +218 -0
- data/lib/active_record/relation/spawn_methods.rb +102 -0
- data/lib/active_record/schema_dumper.rb +10 -6
- data/lib/active_record/serialization.rb +31 -74
- data/lib/active_record/serializers/xml_serializer.rb +33 -121
- data/lib/active_record/session_store.rb +1 -9
- data/lib/active_record/test_case.rb +1 -3
- data/lib/active_record/timestamp.rb +7 -5
- data/lib/active_record/transactions.rb +9 -9
- data/lib/active_record/validations.rb +51 -1100
- data/lib/active_record/validations/associated.rb +47 -0
- data/lib/active_record/validations/uniqueness.rb +181 -0
- data/lib/active_record/version.rb +3 -3
- data/lib/generators/active_record.rb +30 -0
- data/lib/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/generators/active_record/migration/templates/migration.rb +11 -0
- data/lib/generators/active_record/model/model_generator.rb +33 -0
- data/lib/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/generators/active_record/model/templates/model.rb +5 -0
- data/lib/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +67 -325
- data/RUNNING_UNIT_TESTS +0 -36
- data/Rakefile +0 -268
- data/install.rb +0 -30
- data/lib/active_record/calculations.rb +0 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
- data/lib/active_record/dirty.rb +0 -183
- data/lib/active_record/serializers/json_serializer.rb +0 -91
- data/lib/activerecord.rb +0 -2
- data/test/assets/example.log +0 -1
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +0 -24
- data/test/cases/active_schema_test_mysql.rb +0 -122
- data/test/cases/active_schema_test_postgresql.rb +0 -24
- data/test/cases/adapter_test.rb +0 -144
- data/test/cases/aggregations_test.rb +0 -167
- data/test/cases/ar_schema_test.rb +0 -32
- data/test/cases/associations/belongs_to_associations_test.rb +0 -438
- data/test/cases/associations/callbacks_test.rb +0 -161
- data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
- data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
- data/test/cases/associations/eager_singularization_test.rb +0 -145
- data/test/cases/associations/eager_test.rb +0 -852
- data/test/cases/associations/extension_test.rb +0 -62
- data/test/cases/associations/habtm_join_table_test.rb +0 -56
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
- data/test/cases/associations/has_many_associations_test.rb +0 -1273
- data/test/cases/associations/has_many_through_associations_test.rb +0 -360
- data/test/cases/associations/has_one_associations_test.rb +0 -330
- data/test/cases/associations/has_one_through_associations_test.rb +0 -209
- data/test/cases/associations/inner_join_association_test.rb +0 -93
- data/test/cases/associations/inverse_associations_test.rb +0 -566
- data/test/cases/associations/join_model_test.rb +0 -712
- data/test/cases/associations_test.rb +0 -282
- data/test/cases/attribute_methods_test.rb +0 -305
- data/test/cases/autosave_association_test.rb +0 -1218
- data/test/cases/base_test.rb +0 -2166
- data/test/cases/batches_test.rb +0 -81
- data/test/cases/binary_test.rb +0 -30
- data/test/cases/calculations_test.rb +0 -360
- data/test/cases/callbacks_observers_test.rb +0 -38
- data/test/cases/callbacks_test.rb +0 -438
- data/test/cases/class_inheritable_attributes_test.rb +0 -32
- data/test/cases/column_alias_test.rb +0 -17
- data/test/cases/column_definition_test.rb +0 -70
- data/test/cases/connection_pool_test.rb +0 -25
- data/test/cases/connection_test_firebird.rb +0 -8
- data/test/cases/connection_test_mysql.rb +0 -65
- data/test/cases/copy_table_test_sqlite.rb +0 -80
- data/test/cases/counter_cache_test.rb +0 -84
- data/test/cases/database_statements_test.rb +0 -12
- data/test/cases/datatype_test_postgresql.rb +0 -204
- data/test/cases/date_time_test.rb +0 -37
- data/test/cases/default_test_firebird.rb +0 -16
- data/test/cases/defaults_test.rb +0 -111
- data/test/cases/deprecated_finder_test.rb +0 -30
- data/test/cases/dirty_test.rb +0 -316
- data/test/cases/finder_respond_to_test.rb +0 -76
- data/test/cases/finder_test.rb +0 -1098
- data/test/cases/fixtures_test.rb +0 -661
- data/test/cases/helper.rb +0 -68
- data/test/cases/i18n_test.rb +0 -46
- data/test/cases/inheritance_test.rb +0 -262
- data/test/cases/invalid_date_test.rb +0 -24
- data/test/cases/json_serialization_test.rb +0 -219
- data/test/cases/lifecycle_test.rb +0 -193
- data/test/cases/locking_test.rb +0 -350
- data/test/cases/method_scoping_test.rb +0 -704
- data/test/cases/migration_test.rb +0 -1649
- data/test/cases/migration_test_firebird.rb +0 -124
- data/test/cases/mixin_test.rb +0 -96
- data/test/cases/modules_test.rb +0 -109
- data/test/cases/multiple_db_test.rb +0 -85
- data/test/cases/named_scope_test.rb +0 -372
- data/test/cases/nested_attributes_test.rb +0 -840
- data/test/cases/pk_test.rb +0 -119
- data/test/cases/pooled_connections_test.rb +0 -103
- data/test/cases/query_cache_test.rb +0 -129
- data/test/cases/readonly_test.rb +0 -107
- data/test/cases/reflection_test.rb +0 -234
- data/test/cases/reload_models_test.rb +0 -22
- data/test/cases/repair_helper.rb +0 -50
- data/test/cases/reserved_word_test_mysql.rb +0 -176
- data/test/cases/sanitize_test.rb +0 -25
- data/test/cases/schema_authorization_test_postgresql.rb +0 -75
- data/test/cases/schema_dumper_test.rb +0 -211
- data/test/cases/schema_test_postgresql.rb +0 -178
- data/test/cases/serialization_test.rb +0 -47
- data/test/cases/sp_test_mysql.rb +0 -16
- data/test/cases/synonym_test_oracle.rb +0 -17
- data/test/cases/timestamp_test.rb +0 -75
- data/test/cases/transactions_test.rb +0 -543
- data/test/cases/unconnected_test.rb +0 -32
- data/test/cases/validations_i18n_test.rb +0 -925
- data/test/cases/validations_test.rb +0 -1684
- data/test/cases/xml_serialization_test.rb +0 -240
- data/test/cases/yaml_serialization_test.rb +0 -11
- data/test/config.rb +0 -5
- data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
- data/test/connections/jdbc_jdbch2/connection.rb +0 -18
- data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
- data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
- data/test/connections/native_db2/connection.rb +0 -25
- data/test/connections/native_firebird/connection.rb +0 -26
- data/test/connections/native_frontbase/connection.rb +0 -27
- data/test/connections/native_mysql/connection.rb +0 -25
- data/test/connections/native_openbase/connection.rb +0 -21
- data/test/connections/native_oracle/connection.rb +0 -27
- data/test/connections/native_postgresql/connection.rb +0 -21
- data/test/connections/native_sqlite/connection.rb +0 -25
- data/test/connections/native_sqlite3/connection.rb +0 -25
- data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
- data/test/connections/native_sybase/connection.rb +0 -23
- data/test/fixtures/accounts.yml +0 -29
- 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_addresses.yml +0 -5
- data/test/fixtures/author_favorites.yml +0 -4
- data/test/fixtures/authors.yml +0 -9
- data/test/fixtures/binaries.yml +0 -132
- data/test/fixtures/books.yml +0 -7
- data/test/fixtures/categories.yml +0 -14
- data/test/fixtures/categories/special_categories.yml +0 -9
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
- data/test/fixtures/categories_ordered.yml +0 -7
- data/test/fixtures/categories_posts.yml +0 -23
- data/test/fixtures/categorizations.yml +0 -17
- data/test/fixtures/clubs.yml +0 -6
- data/test/fixtures/comments.yml +0 -59
- data/test/fixtures/companies.yml +0 -56
- data/test/fixtures/computers.yml +0 -4
- data/test/fixtures/courses.yml +0 -7
- data/test/fixtures/customers.yml +0 -26
- data/test/fixtures/developers.yml +0 -21
- data/test/fixtures/developers_projects.yml +0 -17
- data/test/fixtures/edges.yml +0 -6
- data/test/fixtures/entrants.yml +0 -14
- data/test/fixtures/faces.yml +0 -11
- data/test/fixtures/fk_test_has_fk.yml +0 -3
- data/test/fixtures/fk_test_has_pk.yml +0 -2
- data/test/fixtures/funny_jokes.yml +0 -10
- data/test/fixtures/interests.yml +0 -33
- data/test/fixtures/items.yml +0 -4
- data/test/fixtures/jobs.yml +0 -7
- data/test/fixtures/legacy_things.yml +0 -3
- data/test/fixtures/mateys.yml +0 -4
- data/test/fixtures/member_types.yml +0 -6
- data/test/fixtures/members.yml +0 -6
- data/test/fixtures/memberships.yml +0 -20
- data/test/fixtures/men.yml +0 -5
- data/test/fixtures/minimalistics.yml +0 -2
- data/test/fixtures/mixed_case_monkeys.yml +0 -6
- data/test/fixtures/mixins.yml +0 -29
- data/test/fixtures/movies.yml +0 -7
- data/test/fixtures/naked/csv/accounts.csv +0 -1
- data/test/fixtures/naked/yml/accounts.yml +0 -1
- data/test/fixtures/naked/yml/companies.yml +0 -1
- data/test/fixtures/naked/yml/courses.yml +0 -1
- data/test/fixtures/organizations.yml +0 -5
- data/test/fixtures/owners.yml +0 -7
- data/test/fixtures/parrots.yml +0 -27
- data/test/fixtures/parrots_pirates.yml +0 -7
- data/test/fixtures/people.yml +0 -15
- data/test/fixtures/pets.yml +0 -14
- data/test/fixtures/pirates.yml +0 -9
- data/test/fixtures/polymorphic_designs.yml +0 -19
- data/test/fixtures/polymorphic_prices.yml +0 -19
- data/test/fixtures/posts.yml +0 -52
- data/test/fixtures/price_estimates.yml +0 -7
- data/test/fixtures/projects.yml +0 -7
- data/test/fixtures/readers.yml +0 -9
- data/test/fixtures/references.yml +0 -17
- data/test/fixtures/reserved_words/distinct.yml +0 -5
- data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
- data/test/fixtures/reserved_words/group.yml +0 -14
- data/test/fixtures/reserved_words/select.yml +0 -8
- data/test/fixtures/reserved_words/values.yml +0 -7
- data/test/fixtures/ships.yml +0 -5
- data/test/fixtures/sponsors.yml +0 -9
- data/test/fixtures/subscribers.yml +0 -7
- data/test/fixtures/subscriptions.yml +0 -12
- data/test/fixtures/taggings.yml +0 -28
- data/test/fixtures/tags.yml +0 -7
- data/test/fixtures/tasks.yml +0 -7
- data/test/fixtures/tees.yml +0 -4
- data/test/fixtures/ties.yml +0 -4
- data/test/fixtures/topics.yml +0 -42
- data/test/fixtures/toys.yml +0 -4
- data/test/fixtures/treasures.yml +0 -10
- data/test/fixtures/vertices.yml +0 -4
- data/test/fixtures/warehouse-things.yml +0 -3
- data/test/fixtures/zines.yml +0 -5
- data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
- data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
- data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
- data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
- data/test/migrations/duplicate/3_foo.rb +0 -7
- data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
- data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
- data/test/migrations/missing/1_people_have_last_names.rb +0 -9
- data/test/migrations/missing/3_we_need_reminders.rb +0 -12
- data/test/migrations/missing/4_innocent_jointable.rb +0 -12
- data/test/migrations/valid/1_people_have_last_names.rb +0 -9
- data/test/migrations/valid/2_we_need_reminders.rb +0 -12
- data/test/migrations/valid/3_innocent_jointable.rb +0 -12
- data/test/models/author.rb +0 -151
- data/test/models/auto_id.rb +0 -4
- data/test/models/binary.rb +0 -2
- data/test/models/bird.rb +0 -9
- data/test/models/book.rb +0 -4
- data/test/models/categorization.rb +0 -5
- data/test/models/category.rb +0 -34
- data/test/models/citation.rb +0 -6
- data/test/models/club.rb +0 -13
- data/test/models/column_name.rb +0 -3
- data/test/models/comment.rb +0 -29
- data/test/models/company.rb +0 -173
- data/test/models/company_in_module.rb +0 -78
- data/test/models/computer.rb +0 -3
- data/test/models/contact.rb +0 -16
- data/test/models/contract.rb +0 -5
- data/test/models/course.rb +0 -3
- data/test/models/customer.rb +0 -73
- data/test/models/default.rb +0 -2
- data/test/models/developer.rb +0 -101
- data/test/models/edge.rb +0 -5
- data/test/models/entrant.rb +0 -3
- data/test/models/essay.rb +0 -3
- data/test/models/event.rb +0 -3
- data/test/models/event_author.rb +0 -8
- data/test/models/face.rb +0 -7
- data/test/models/guid.rb +0 -2
- data/test/models/interest.rb +0 -5
- data/test/models/invoice.rb +0 -4
- data/test/models/item.rb +0 -7
- data/test/models/job.rb +0 -5
- data/test/models/joke.rb +0 -3
- data/test/models/keyboard.rb +0 -3
- data/test/models/legacy_thing.rb +0 -3
- data/test/models/line_item.rb +0 -3
- data/test/models/man.rb +0 -9
- data/test/models/matey.rb +0 -4
- data/test/models/member.rb +0 -12
- data/test/models/member_detail.rb +0 -5
- data/test/models/member_type.rb +0 -3
- data/test/models/membership.rb +0 -9
- data/test/models/minimalistic.rb +0 -2
- data/test/models/mixed_case_monkey.rb +0 -3
- data/test/models/movie.rb +0 -5
- data/test/models/order.rb +0 -4
- data/test/models/organization.rb +0 -6
- data/test/models/owner.rb +0 -5
- data/test/models/parrot.rb +0 -22
- data/test/models/person.rb +0 -16
- data/test/models/pet.rb +0 -5
- data/test/models/pirate.rb +0 -80
- data/test/models/polymorphic_design.rb +0 -3
- data/test/models/polymorphic_price.rb +0 -3
- data/test/models/post.rb +0 -102
- data/test/models/price_estimate.rb +0 -3
- data/test/models/project.rb +0 -30
- data/test/models/reader.rb +0 -4
- data/test/models/reference.rb +0 -4
- data/test/models/reply.rb +0 -46
- data/test/models/ship.rb +0 -19
- data/test/models/ship_part.rb +0 -7
- data/test/models/sponsor.rb +0 -4
- data/test/models/subject.rb +0 -4
- data/test/models/subscriber.rb +0 -8
- data/test/models/subscription.rb +0 -4
- data/test/models/tag.rb +0 -7
- data/test/models/tagging.rb +0 -10
- data/test/models/task.rb +0 -3
- data/test/models/tee.rb +0 -4
- data/test/models/tie.rb +0 -4
- data/test/models/topic.rb +0 -80
- data/test/models/toy.rb +0 -6
- data/test/models/treasure.rb +0 -8
- data/test/models/vertex.rb +0 -9
- data/test/models/warehouse_thing.rb +0 -5
- data/test/models/zine.rb +0 -3
- data/test/schema/mysql_specific_schema.rb +0 -31
- data/test/schema/postgresql_specific_schema.rb +0 -114
- data/test/schema/schema.rb +0 -550
- data/test/schema/schema2.rb +0 -6
- data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
13
13
|
|
14
14
|
def dirties_query_cache(base, *method_names)
|
15
15
|
method_names.each do |method_name|
|
16
|
-
base.class_eval <<-end_code, __FILE__, __LINE__
|
16
|
+
base.class_eval <<-end_code, __FILE__, __LINE__
|
17
17
|
def #{method_name}_with_query_dirty(*args) # def update_with_query_dirty(*args)
|
18
18
|
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
|
19
19
|
#{method_name}_without_query_dirty(*args) # update_without_query_dirty(*args)
|
@@ -75,7 +75,8 @@ module ActiveRecord
|
|
75
75
|
def cache_sql(sql)
|
76
76
|
result =
|
77
77
|
if @query_cache.has_key?(sql)
|
78
|
-
|
78
|
+
ActiveSupport::Notifications.instrument("active_record.sql",
|
79
|
+
:sql => sql, :name => "CACHE", :connection_id => self.object_id)
|
79
80
|
@query_cache[sql]
|
80
81
|
else
|
81
82
|
@query_cache[sql] = yield
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/big_decimal/conversions'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module Quoting
|
@@ -11,12 +13,12 @@ module ActiveRecord
|
|
11
13
|
when String, ActiveSupport::Multibyte::Chars
|
12
14
|
value = value.to_s
|
13
15
|
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
14
|
-
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
16
|
+
"#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
15
17
|
elsif column && [:integer, :float].include?(column.type)
|
16
18
|
value = column.type == :integer ? value.to_i : value.to_f
|
17
19
|
value.to_s
|
18
20
|
else
|
19
|
-
"'#{quote_string(value)}'" # ' (for ruby-mode)
|
21
|
+
"#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
|
20
22
|
end
|
21
23
|
when NilClass then "NULL"
|
22
24
|
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
|
@@ -28,7 +30,7 @@ module ActiveRecord
|
|
28
30
|
if value.acts_like?(:date) || value.acts_like?(:time)
|
29
31
|
"'#{quoted_date(value)}'"
|
30
32
|
else
|
31
|
-
"'#{quote_string(value.to_yaml)}'"
|
33
|
+
"#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -58,7 +60,16 @@ module ActiveRecord
|
|
58
60
|
end
|
59
61
|
|
60
62
|
def quoted_date(value)
|
61
|
-
value.
|
63
|
+
if value.acts_like?(:time)
|
64
|
+
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
65
|
+
value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
|
66
|
+
else
|
67
|
+
value
|
68
|
+
end.to_s(:db)
|
69
|
+
end
|
70
|
+
|
71
|
+
def quoted_string_prefix
|
72
|
+
''
|
62
73
|
end
|
63
74
|
end
|
64
75
|
end
|
@@ -256,7 +256,7 @@ module ActiveRecord
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
|
-
class IndexDefinition < Struct.new(:table, :name, :unique, :columns
|
259
|
+
class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
|
260
260
|
end
|
261
261
|
|
262
262
|
# Abstract representation of a column definition. Instances of this type
|
@@ -8,6 +8,11 @@ module ActiveRecord
|
|
8
8
|
{}
|
9
9
|
end
|
10
10
|
|
11
|
+
# This is the maximum length a table alias can be
|
12
|
+
def table_alias_length
|
13
|
+
255
|
14
|
+
end
|
15
|
+
|
11
16
|
# Truncates a table alias according to the limits of the current adapter.
|
12
17
|
def table_alias_for(table_name)
|
13
18
|
table_name[0..table_alias_length-1].gsub(/\./, '_')
|
@@ -36,11 +41,19 @@ module ActiveRecord
|
|
36
41
|
# # create_table() passes a TableDefinition object to the block.
|
37
42
|
# # This form will not only create the table, but also columns for the
|
38
43
|
# # table.
|
44
|
+
#
|
39
45
|
# create_table(:suppliers) do |t|
|
40
46
|
# t.column :name, :string, :limit => 60
|
41
47
|
# # Other fields here
|
42
48
|
# end
|
43
49
|
#
|
50
|
+
# === Block form, with shorthand
|
51
|
+
# # You can also use the column types as method calls, rather than calling the column method.
|
52
|
+
# create_table(:suppliers) do |t|
|
53
|
+
# t.string :name, :limit => 60
|
54
|
+
# # Other fields here
|
55
|
+
# end
|
56
|
+
#
|
44
57
|
# === Regular form
|
45
58
|
# # Creates a table called 'suppliers' with no columns.
|
46
59
|
# create_table(:suppliers)
|
@@ -195,7 +208,6 @@ module ActiveRecord
|
|
195
208
|
# remove_column(:suppliers, :qualification)
|
196
209
|
# remove_columns(:suppliers, :qualification, :experience)
|
197
210
|
def remove_column(table_name, *column_names)
|
198
|
-
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
|
199
211
|
column_names.flatten.each do |column_name|
|
200
212
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
201
213
|
end
|
@@ -242,53 +254,29 @@ module ActiveRecord
|
|
242
254
|
# name.
|
243
255
|
#
|
244
256
|
# ===== Examples
|
245
|
-
#
|
246
257
|
# ====== Creating a simple index
|
247
258
|
# add_index(:suppliers, :name)
|
248
259
|
# generates
|
249
260
|
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
250
|
-
#
|
251
261
|
# ====== Creating a unique index
|
252
262
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true)
|
253
263
|
# generates
|
254
264
|
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
255
|
-
#
|
256
265
|
# ====== Creating a named index
|
257
266
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
|
258
267
|
# generates
|
259
268
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
260
|
-
#
|
261
|
-
# ====== Creating an index with specific key length
|
262
|
-
# add_index(:accounts, :name, :name => 'by_name', :length => 10)
|
263
|
-
# generates
|
264
|
-
# CREATE INDEX by_name ON accounts(name(10))
|
265
|
-
#
|
266
|
-
# add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})
|
267
|
-
# generates
|
268
|
-
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
269
|
-
#
|
270
|
-
# Note: SQLite doesn't support index length
|
271
269
|
def add_index(table_name, column_name, options = {})
|
272
270
|
column_names = Array(column_name)
|
273
271
|
index_name = index_name(table_name, :column => column_names)
|
274
272
|
|
275
273
|
if Hash === options # legacy support, since this param was a string
|
276
274
|
index_type = options[:unique] ? "UNIQUE" : ""
|
277
|
-
index_name = options[:name]
|
275
|
+
index_name = options[:name] || index_name
|
278
276
|
else
|
279
277
|
index_type = options
|
280
278
|
end
|
281
|
-
|
282
|
-
if index_name.length > index_name_length
|
283
|
-
@logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.")
|
284
|
-
return
|
285
|
-
end
|
286
|
-
if index_exists?(table_name, index_name, false)
|
287
|
-
@logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.")
|
288
|
-
return
|
289
|
-
end
|
290
|
-
quoted_column_names = quoted_columns_for_index(column_names, options).join(", ")
|
291
|
-
|
279
|
+
quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
|
292
280
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
|
293
281
|
end
|
294
282
|
|
@@ -303,28 +291,7 @@ module ActiveRecord
|
|
303
291
|
# Remove the index named by_branch_party in the accounts table.
|
304
292
|
# remove_index :accounts, :name => :by_branch_party
|
305
293
|
def remove_index(table_name, options = {})
|
306
|
-
|
307
|
-
unless index_exists?(table_name, index_name, true)
|
308
|
-
@logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.")
|
309
|
-
return
|
310
|
-
end
|
311
|
-
remove_index!(table_name, index_name)
|
312
|
-
end
|
313
|
-
|
314
|
-
def remove_index!(table_name, index_name) #:nodoc:
|
315
|
-
execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}"
|
316
|
-
end
|
317
|
-
|
318
|
-
# Rename an index.
|
319
|
-
#
|
320
|
-
# Rename the index_people_on_last_name index to index_users_on_last_name
|
321
|
-
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
322
|
-
def rename_index(table_name, old_name, new_name)
|
323
|
-
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
324
|
-
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
325
|
-
return unless old_index_def
|
326
|
-
remove_index(table_name, :name => old_name)
|
327
|
-
add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
|
294
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
|
328
295
|
end
|
329
296
|
|
330
297
|
def index_name(table_name, options) #:nodoc:
|
@@ -341,16 +308,6 @@ module ActiveRecord
|
|
341
308
|
end
|
342
309
|
end
|
343
310
|
|
344
|
-
# Verify the existence of an index.
|
345
|
-
#
|
346
|
-
# The default argument is returned if the underlying implementation does not define the indexes method,
|
347
|
-
# as there's no way to determine the correct answer in that case.
|
348
|
-
def index_exists?(table_name, index_name, default)
|
349
|
-
return default unless respond_to?(:indexes)
|
350
|
-
index_name = index_name.to_s
|
351
|
-
indexes(table_name).detect { |i| i.name == index_name }
|
352
|
-
end
|
353
|
-
|
354
311
|
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
|
355
312
|
# entire structure of the database.
|
356
313
|
def structure_dump
|
@@ -367,7 +324,7 @@ module ActiveRecord
|
|
367
324
|
def initialize_schema_migrations_table
|
368
325
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
369
326
|
|
370
|
-
unless
|
327
|
+
unless table_exists?(sm_table)
|
371
328
|
create_table(sm_table, :id => false) do |schema_migrations_table|
|
372
329
|
schema_migrations_table.column :version, :string, :null => false
|
373
330
|
end
|
@@ -378,7 +335,7 @@ module ActiveRecord
|
|
378
335
|
# migrated up to that point:
|
379
336
|
si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
|
380
337
|
|
381
|
-
if
|
338
|
+
if table_exists?(si_table)
|
382
339
|
|
383
340
|
old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
|
384
341
|
assume_migrated_upto_version(old_version)
|
@@ -454,12 +411,6 @@ module ActiveRecord
|
|
454
411
|
"DISTINCT #{columns}"
|
455
412
|
end
|
456
413
|
|
457
|
-
# ORDER BY clause for the passed order option.
|
458
|
-
# PostgreSQL overrides this due to its stricter standards compliance.
|
459
|
-
def add_order_by_for_association_limiting!(sql, options)
|
460
|
-
sql << " ORDER BY #{options[:order]}"
|
461
|
-
end
|
462
|
-
|
463
414
|
# Adds timestamps (created_at and updated_at) columns to the named table.
|
464
415
|
# ===== Examples
|
465
416
|
# add_timestamps(:suppliers)
|
@@ -477,11 +428,6 @@ module ActiveRecord
|
|
477
428
|
end
|
478
429
|
|
479
430
|
protected
|
480
|
-
# Overridden by the mysql adapter for supporting index lengths
|
481
|
-
def quoted_columns_for_index(column_names, options = {})
|
482
|
-
column_names.map {|name| quote_column_name(name) }
|
483
|
-
end
|
484
|
-
|
485
431
|
def options_include_default?(options)
|
486
432
|
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
487
433
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'benchmark'
|
2
1
|
require 'date'
|
3
2
|
require 'bigdecimal'
|
4
3
|
require 'bigdecimal/util'
|
4
|
+
require 'active_support/core_ext/benchmark'
|
5
5
|
|
6
6
|
# TODO: Autoload these files
|
7
7
|
require 'active_record/connection_adapters/abstract/schema_definitions'
|
@@ -11,7 +11,6 @@ require 'active_record/connection_adapters/abstract/quoting'
|
|
11
11
|
require 'active_record/connection_adapters/abstract/connection_pool'
|
12
12
|
require 'active_record/connection_adapters/abstract/connection_specification'
|
13
13
|
require 'active_record/connection_adapters/abstract/query_cache'
|
14
|
-
require 'active_record/connection_adapters/abstract/database_limits'
|
15
14
|
|
16
15
|
module ActiveRecord
|
17
16
|
module ConnectionAdapters # :nodoc:
|
@@ -30,9 +29,9 @@ module ActiveRecord
|
|
30
29
|
# notably, the instance methods provided by SchemaStatement are very useful.
|
31
30
|
class AbstractAdapter
|
32
31
|
include Quoting, DatabaseStatements, SchemaStatements
|
33
|
-
include DatabaseLimits
|
34
32
|
include QueryCache
|
35
33
|
include ActiveSupport::Callbacks
|
34
|
+
|
36
35
|
define_callbacks :checkout, :checkin
|
37
36
|
|
38
37
|
@@row_even = true
|
@@ -40,7 +39,6 @@ module ActiveRecord
|
|
40
39
|
def initialize(connection, logger = nil) #:nodoc:
|
41
40
|
@connection, @logger = connection, logger
|
42
41
|
@runtime = 0
|
43
|
-
@last_verification = 0
|
44
42
|
@query_cache_enabled = false
|
45
43
|
end
|
46
44
|
|
@@ -75,7 +73,7 @@ module ActiveRecord
|
|
75
73
|
def supports_ddl_transactions?
|
76
74
|
false
|
77
75
|
end
|
78
|
-
|
76
|
+
|
79
77
|
# Does this adapter support savepoints? PostgreSQL and MySQL do, SQLite
|
80
78
|
# does not.
|
81
79
|
def supports_savepoints?
|
@@ -192,58 +190,27 @@ module ActiveRecord
|
|
192
190
|
"active_record_#{open_transactions}"
|
193
191
|
end
|
194
192
|
|
195
|
-
def log_info(sql, name, ms)
|
196
|
-
if @logger && @logger.debug?
|
197
|
-
name = '%s (%.1fms)' % [name || 'SQL', ms]
|
198
|
-
@logger.debug(format_log_entry(name, sql.squeeze(' ')))
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
193
|
protected
|
194
|
+
|
203
195
|
def log(sql, name)
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
result
|
210
|
-
else
|
211
|
-
log_info(sql, name, 0)
|
212
|
-
nil
|
196
|
+
name ||= "SQL"
|
197
|
+
result = nil
|
198
|
+
ActiveSupport::Notifications.instrument("active_record.sql",
|
199
|
+
:sql => sql, :name => name, :connection_id => self.object_id) do
|
200
|
+
@runtime += Benchmark.ms { result = yield }
|
213
201
|
end
|
214
|
-
|
215
|
-
# Don't re-wrap these exceptions. They are probably not being caused by invalid
|
216
|
-
# sql, but rather some external stimulus beyond the responsibilty of this code.
|
217
|
-
# Additionaly, wrapping these exceptions with StatementInvalid would lead to
|
218
|
-
# meaningful loss of data, such as losing SystemExit#status.
|
219
|
-
raise e
|
202
|
+
result
|
220
203
|
rescue Exception => e
|
221
|
-
# Log message and raise exception.
|
222
|
-
# Set last_verification to 0, so that connection gets verified
|
223
|
-
# upon reentering the request loop
|
224
|
-
@last_verification = 0
|
225
204
|
message = "#{e.class.name}: #{e.message}: #{sql}"
|
226
|
-
|
227
|
-
raise
|
205
|
+
@logger.debug message if @logger
|
206
|
+
raise translate_exception(e, message)
|
228
207
|
end
|
229
208
|
|
230
|
-
def
|
231
|
-
|
232
|
-
|
233
|
-
@@row_even = false
|
234
|
-
message_color, dump_color = "4;36;1", "0;1"
|
235
|
-
else
|
236
|
-
@@row_even = true
|
237
|
-
message_color, dump_color = "4;35;1", "0"
|
238
|
-
end
|
239
|
-
|
240
|
-
log_entry = " \e[#{message_color}m#{message}\e[0m "
|
241
|
-
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
|
242
|
-
log_entry
|
243
|
-
else
|
244
|
-
"%s %s" % [message, dump]
|
245
|
-
end
|
209
|
+
def translate_exception(e, message)
|
210
|
+
# override in derived class
|
211
|
+
ActiveRecord::StatementInvalid.new(message)
|
246
212
|
end
|
213
|
+
|
247
214
|
end
|
248
215
|
end
|
249
216
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
+
require 'active_support/core_ext/kernel/requires'
|
2
3
|
require 'set'
|
3
4
|
|
4
5
|
module MysqlCompat #:nodoc:
|
@@ -210,7 +211,7 @@ module ActiveRecord
|
|
210
211
|
def supports_migrations? #:nodoc:
|
211
212
|
true
|
212
213
|
end
|
213
|
-
|
214
|
+
|
214
215
|
def supports_primary_key? #:nodoc:
|
215
216
|
true
|
216
217
|
end
|
@@ -238,7 +239,7 @@ module ActiveRecord
|
|
238
239
|
end
|
239
240
|
|
240
241
|
def quote_column_name(name) #:nodoc:
|
241
|
-
@quoted_column_names[name] ||= "`#{name
|
242
|
+
@quoted_column_names[name] ||= "`#{name}`"
|
242
243
|
end
|
243
244
|
|
244
245
|
def quote_table_name(name) #:nodoc:
|
@@ -315,7 +316,6 @@ module ActiveRecord
|
|
315
316
|
rows = []
|
316
317
|
result.each { |row| rows << row }
|
317
318
|
result.free
|
318
|
-
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
319
319
|
rows
|
320
320
|
end
|
321
321
|
|
@@ -334,6 +334,7 @@ module ActiveRecord
|
|
334
334
|
super sql, name
|
335
335
|
id_value || @connection.insert_id
|
336
336
|
end
|
337
|
+
alias :create :insert_sql
|
337
338
|
|
338
339
|
def update_sql(sql, name = nil) #:nodoc:
|
339
340
|
super
|
@@ -370,18 +371,6 @@ module ActiveRecord
|
|
370
371
|
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
|
371
372
|
end
|
372
373
|
|
373
|
-
def add_limit_offset!(sql, options) #:nodoc:
|
374
|
-
if limit = options[:limit]
|
375
|
-
limit = sanitize_limit(limit)
|
376
|
-
unless offset = options[:offset]
|
377
|
-
sql << " LIMIT #{limit}"
|
378
|
-
else
|
379
|
-
sql << " LIMIT #{offset.to_i}, #{limit}"
|
380
|
-
end
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
374
|
# SCHEMA STATEMENTS ========================================
|
386
375
|
|
387
376
|
def structure_dump #:nodoc:
|
@@ -455,11 +444,10 @@ module ActiveRecord
|
|
455
444
|
if current_index != row[2]
|
456
445
|
next if row[2] == "PRIMARY" # skip the primary key
|
457
446
|
current_index = row[2]
|
458
|
-
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", []
|
447
|
+
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [])
|
459
448
|
end
|
460
449
|
|
461
450
|
indexes.last.columns << row[4]
|
462
|
-
indexes.last.lengths << row[7]
|
463
451
|
end
|
464
452
|
result.free
|
465
453
|
indexes
|
@@ -589,16 +577,17 @@ module ActiveRecord
|
|
589
577
|
end
|
590
578
|
|
591
579
|
protected
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
580
|
+
|
581
|
+
def translate_exception(exception, message)
|
582
|
+
return super unless exception.respond_to?(:errno)
|
583
|
+
|
584
|
+
case exception.errno
|
585
|
+
when 1062
|
586
|
+
RecordNotUnique.new(message, exception)
|
587
|
+
when 1452
|
588
|
+
InvalidForeignKey.new(message, exception)
|
600
589
|
else
|
601
|
-
|
590
|
+
super
|
602
591
|
end
|
603
592
|
end
|
604
593
|
|
@@ -639,7 +628,6 @@ module ActiveRecord
|
|
639
628
|
result = execute(sql, name)
|
640
629
|
rows = result.all_hashes
|
641
630
|
result.free
|
642
|
-
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
643
631
|
rows
|
644
632
|
end
|
645
633
|
|