activerecord_csi 2.3.5.p6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5858 -0
- data/README +351 -0
- data/RUNNING_UNIT_TESTS +36 -0
- data/Rakefile +270 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +162 -0
- data/install.rb +30 -0
- data/lib/active_record/aggregations.rb +261 -0
- data/lib/active_record/association_preload.rb +389 -0
- data/lib/active_record/associations/association_collection.rb +475 -0
- data/lib/active_record/associations/association_proxy.rb +278 -0
- data/lib/active_record/associations/belongs_to_association.rb +76 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
- data/lib/active_record/associations/has_many_association.rb +122 -0
- data/lib/active_record/associations/has_many_through_association.rb +266 -0
- data/lib/active_record/associations/has_one_association.rb +133 -0
- data/lib/active_record/associations/has_one_through_association.rb +37 -0
- data/lib/active_record/associations.rb +2241 -0
- data/lib/active_record/attribute_methods.rb +388 -0
- data/lib/active_record/autosave_association.rb +364 -0
- data/lib/active_record/base.rb +3171 -0
- data/lib/active_record/batches.rb +81 -0
- data/lib/active_record/calculations.rb +311 -0
- data/lib/active_record/callbacks.rb +360 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
- data/lib/active_record/dirty.rb +183 -0
- data/lib/active_record/dynamic_finder_match.rb +41 -0
- data/lib/active_record/dynamic_scope_match.rb +25 -0
- data/lib/active_record/fixtures.rb +996 -0
- data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
- data/lib/active_record/locale/en.yml +58 -0
- data/lib/active_record/locking/optimistic.rb +148 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/migration.rb +566 -0
- data/lib/active_record/named_scope.rb +192 -0
- data/lib/active_record/nested_attributes.rb +392 -0
- data/lib/active_record/observer.rb +197 -0
- data/lib/active_record/query_cache.rb +33 -0
- data/lib/active_record/reflection.rb +320 -0
- data/lib/active_record/schema.rb +51 -0
- data/lib/active_record/schema_dumper.rb +182 -0
- data/lib/active_record/serialization.rb +101 -0
- data/lib/active_record/serializers/json_serializer.rb +91 -0
- data/lib/active_record/serializers/xml_serializer.rb +357 -0
- data/lib/active_record/session_store.rb +326 -0
- data/lib/active_record/test_case.rb +66 -0
- data/lib/active_record/timestamp.rb +71 -0
- data/lib/active_record/transactions.rb +235 -0
- data/lib/active_record/validations.rb +1135 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +84 -0
- data/lib/activerecord.rb +2 -0
- data/test/assets/example.log +1 -0
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +24 -0
- data/test/cases/active_schema_test_mysql.rb +100 -0
- data/test/cases/active_schema_test_postgresql.rb +24 -0
- data/test/cases/adapter_test.rb +145 -0
- data/test/cases/aggregations_test.rb +167 -0
- data/test/cases/ar_schema_test.rb +32 -0
- data/test/cases/associations/belongs_to_associations_test.rb +425 -0
- data/test/cases/associations/callbacks_test.rb +161 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
- data/test/cases/associations/eager_singularization_test.rb +145 -0
- data/test/cases/associations/eager_test.rb +834 -0
- data/test/cases/associations/extension_test.rb +62 -0
- data/test/cases/associations/habtm_join_table_test.rb +56 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
- data/test/cases/associations/has_many_associations_test.rb +1134 -0
- data/test/cases/associations/has_many_through_associations_test.rb +346 -0
- data/test/cases/associations/has_one_associations_test.rb +330 -0
- data/test/cases/associations/has_one_through_associations_test.rb +209 -0
- data/test/cases/associations/inner_join_association_test.rb +93 -0
- data/test/cases/associations/join_model_test.rb +712 -0
- data/test/cases/associations_test.rb +262 -0
- data/test/cases/attribute_methods_test.rb +305 -0
- data/test/cases/autosave_association_test.rb +1142 -0
- data/test/cases/base_test.rb +2154 -0
- data/test/cases/batches_test.rb +61 -0
- data/test/cases/binary_test.rb +30 -0
- data/test/cases/calculations_test.rb +348 -0
- data/test/cases/callbacks_observers_test.rb +38 -0
- data/test/cases/callbacks_test.rb +438 -0
- data/test/cases/class_inheritable_attributes_test.rb +32 -0
- data/test/cases/column_alias_test.rb +17 -0
- data/test/cases/column_definition_test.rb +70 -0
- data/test/cases/connection_pool_test.rb +25 -0
- data/test/cases/connection_test_firebird.rb +8 -0
- data/test/cases/connection_test_mysql.rb +64 -0
- data/test/cases/copy_table_test_sqlite.rb +80 -0
- data/test/cases/database_statements_test.rb +12 -0
- data/test/cases/datatype_test_postgresql.rb +204 -0
- data/test/cases/date_time_test.rb +37 -0
- data/test/cases/default_test_firebird.rb +16 -0
- data/test/cases/defaults_test.rb +111 -0
- data/test/cases/deprecated_finder_test.rb +30 -0
- data/test/cases/dirty_test.rb +316 -0
- data/test/cases/finder_respond_to_test.rb +76 -0
- data/test/cases/finder_test.rb +1066 -0
- data/test/cases/fixtures_test.rb +656 -0
- data/test/cases/helper.rb +68 -0
- data/test/cases/i18n_test.rb +46 -0
- data/test/cases/inheritance_test.rb +262 -0
- data/test/cases/invalid_date_test.rb +24 -0
- data/test/cases/json_serialization_test.rb +205 -0
- data/test/cases/lifecycle_test.rb +193 -0
- data/test/cases/locking_test.rb +304 -0
- data/test/cases/method_scoping_test.rb +704 -0
- data/test/cases/migration_test.rb +1523 -0
- data/test/cases/migration_test_firebird.rb +124 -0
- data/test/cases/mixin_test.rb +96 -0
- data/test/cases/modules_test.rb +81 -0
- data/test/cases/multiple_db_test.rb +85 -0
- data/test/cases/named_scope_test.rb +361 -0
- data/test/cases/nested_attributes_test.rb +581 -0
- data/test/cases/pk_test.rb +119 -0
- data/test/cases/pooled_connections_test.rb +103 -0
- data/test/cases/query_cache_test.rb +123 -0
- data/test/cases/readonly_test.rb +107 -0
- data/test/cases/reflection_test.rb +194 -0
- data/test/cases/reload_models_test.rb +22 -0
- data/test/cases/repair_helper.rb +50 -0
- data/test/cases/reserved_word_test_mysql.rb +176 -0
- data/test/cases/sanitize_test.rb +25 -0
- data/test/cases/schema_authorization_test_postgresql.rb +75 -0
- data/test/cases/schema_dumper_test.rb +211 -0
- data/test/cases/schema_test_postgresql.rb +178 -0
- data/test/cases/serialization_test.rb +47 -0
- data/test/cases/synonym_test_oracle.rb +17 -0
- data/test/cases/timestamp_test.rb +75 -0
- data/test/cases/transactions_test.rb +522 -0
- data/test/cases/unconnected_test.rb +32 -0
- data/test/cases/validations_i18n_test.rb +955 -0
- data/test/cases/validations_test.rb +1640 -0
- data/test/cases/xml_serialization_test.rb +240 -0
- data/test/config.rb +5 -0
- data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
- data/test/connections/jdbc_jdbch2/connection.rb +18 -0
- data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
- data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +25 -0
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +25 -0
- data/test/connections/native_sqlite/connection.rb +25 -0
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/fixtures/accounts.yml +29 -0
- 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 +5 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +9 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/clubs.yml +6 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +56 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customers.yml +26 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/jobs.yml +7 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/member_types.yml +6 -0
- data/test/fixtures/members.yml +6 -0
- data/test/fixtures/memberships.yml +20 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/organizations.yml +5 -0
- data/test/fixtures/owners.yml +7 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +15 -0
- data/test/fixtures/pets.yml +14 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/posts.yml +52 -0
- data/test/fixtures/price_estimates.yml +7 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/readers.yml +9 -0
- data/test/fixtures/references.yml +17 -0
- 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/ships.yml +5 -0
- data/test/fixtures/sponsors.yml +9 -0
- data/test/fixtures/subscribers.yml +7 -0
- data/test/fixtures/subscriptions.yml +12 -0
- data/test/fixtures/taggings.yml +28 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topics.yml +42 -0
- data/test/fixtures/toys.yml +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
- data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
- data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
- data/test/migrations/duplicate/3_foo.rb +7 -0
- data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
- data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/migrations/missing/3_we_need_reminders.rb +12 -0
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/valid/1_people_have_last_names.rb +9 -0
- data/test/migrations/valid/2_we_need_reminders.rb +12 -0
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/models/author.rb +146 -0
- data/test/models/auto_id.rb +4 -0
- data/test/models/binary.rb +2 -0
- data/test/models/bird.rb +3 -0
- data/test/models/book.rb +4 -0
- data/test/models/categorization.rb +5 -0
- data/test/models/category.rb +34 -0
- data/test/models/citation.rb +6 -0
- data/test/models/club.rb +13 -0
- data/test/models/column_name.rb +3 -0
- data/test/models/comment.rb +29 -0
- data/test/models/company.rb +171 -0
- data/test/models/company_in_module.rb +61 -0
- data/test/models/computer.rb +3 -0
- data/test/models/contact.rb +16 -0
- data/test/models/contract.rb +5 -0
- data/test/models/course.rb +3 -0
- data/test/models/customer.rb +73 -0
- data/test/models/default.rb +2 -0
- data/test/models/developer.rb +101 -0
- data/test/models/edge.rb +5 -0
- data/test/models/entrant.rb +3 -0
- data/test/models/essay.rb +3 -0
- data/test/models/event.rb +3 -0
- data/test/models/guid.rb +2 -0
- data/test/models/item.rb +7 -0
- data/test/models/job.rb +5 -0
- data/test/models/joke.rb +3 -0
- data/test/models/keyboard.rb +3 -0
- data/test/models/legacy_thing.rb +3 -0
- data/test/models/matey.rb +4 -0
- data/test/models/member.rb +12 -0
- data/test/models/member_detail.rb +5 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/membership.rb +9 -0
- data/test/models/minimalistic.rb +2 -0
- data/test/models/mixed_case_monkey.rb +3 -0
- data/test/models/movie.rb +5 -0
- data/test/models/order.rb +4 -0
- data/test/models/organization.rb +6 -0
- data/test/models/owner.rb +5 -0
- data/test/models/parrot.rb +16 -0
- data/test/models/person.rb +16 -0
- data/test/models/pet.rb +5 -0
- data/test/models/pirate.rb +70 -0
- data/test/models/post.rb +100 -0
- data/test/models/price_estimate.rb +3 -0
- data/test/models/project.rb +30 -0
- data/test/models/reader.rb +4 -0
- data/test/models/reference.rb +4 -0
- data/test/models/reply.rb +46 -0
- data/test/models/ship.rb +10 -0
- data/test/models/ship_part.rb +5 -0
- data/test/models/sponsor.rb +4 -0
- data/test/models/subject.rb +4 -0
- data/test/models/subscriber.rb +8 -0
- data/test/models/subscription.rb +4 -0
- data/test/models/tag.rb +7 -0
- data/test/models/tagging.rb +10 -0
- data/test/models/task.rb +3 -0
- data/test/models/topic.rb +80 -0
- data/test/models/toy.rb +6 -0
- data/test/models/treasure.rb +8 -0
- data/test/models/vertex.rb +9 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/mysql_specific_schema.rb +24 -0
- data/test/schema/postgresql_specific_schema.rb +114 -0
- data/test/schema/schema.rb +493 -0
- data/test/schema/schema2.rb +6 -0
- data/test/schema/sqlite_specific_schema.rb +25 -0
- metadata +420 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
2
|
+
require 'set'
|
|
3
|
+
|
|
4
|
+
module MysqlCompat #:nodoc:
|
|
5
|
+
# add all_hashes method to standard mysql-c bindings or pure ruby version
|
|
6
|
+
def self.define_all_hashes_method!
|
|
7
|
+
raise 'Mysql not loaded' unless defined?(::Mysql)
|
|
8
|
+
|
|
9
|
+
target = defined?(Mysql::Result) ? Mysql::Result : MysqlRes
|
|
10
|
+
return if target.instance_methods.include?('all_hashes') ||
|
|
11
|
+
target.instance_methods.include?(:all_hashes)
|
|
12
|
+
|
|
13
|
+
# Ruby driver has a version string and returns null values in each_hash
|
|
14
|
+
# C driver >= 2.7 returns null values in each_hash
|
|
15
|
+
if Mysql.const_defined?(:VERSION) && (Mysql::VERSION.is_a?(String) || Mysql::VERSION >= 20700)
|
|
16
|
+
target.class_eval <<-'end_eval'
|
|
17
|
+
def all_hashes # def all_hashes
|
|
18
|
+
rows = [] # rows = []
|
|
19
|
+
each_hash { |row| rows << row } # each_hash { |row| rows << row }
|
|
20
|
+
rows # rows
|
|
21
|
+
end # end
|
|
22
|
+
end_eval
|
|
23
|
+
|
|
24
|
+
# adapters before 2.7 don't have a version constant
|
|
25
|
+
# and don't return null values in each_hash
|
|
26
|
+
else
|
|
27
|
+
target.class_eval <<-'end_eval'
|
|
28
|
+
def all_hashes # def all_hashes
|
|
29
|
+
rows = [] # rows = []
|
|
30
|
+
all_fields = fetch_fields.inject({}) { |fields, f| # all_fields = fetch_fields.inject({}) { |fields, f|
|
|
31
|
+
fields[f.name] = nil; fields # fields[f.name] = nil; fields
|
|
32
|
+
} # }
|
|
33
|
+
each_hash { |row| rows << all_fields.dup.update(row) } # each_hash { |row| rows << all_fields.dup.update(row) }
|
|
34
|
+
rows # rows
|
|
35
|
+
end # end
|
|
36
|
+
end_eval
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
unless target.instance_methods.include?('all_hashes') ||
|
|
40
|
+
target.instance_methods.include?(:all_hashes)
|
|
41
|
+
raise "Failed to defined #{target.name}#all_hashes method. Mysql::VERSION = #{Mysql::VERSION.inspect}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module ActiveRecord
|
|
47
|
+
class Base
|
|
48
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
|
49
|
+
def self.mysql_connection(config) # :nodoc:
|
|
50
|
+
config = config.symbolize_keys
|
|
51
|
+
host = config[:host]
|
|
52
|
+
port = config[:port]
|
|
53
|
+
socket = config[:socket]
|
|
54
|
+
username = config[:username] ? config[:username].to_s : 'root'
|
|
55
|
+
password = config[:password].to_s
|
|
56
|
+
database = config[:database]
|
|
57
|
+
|
|
58
|
+
# Require the MySQL driver and define Mysql::Result.all_hashes
|
|
59
|
+
unless defined? Mysql
|
|
60
|
+
begin
|
|
61
|
+
require_library_or_gem('mysql')
|
|
62
|
+
rescue LoadError
|
|
63
|
+
$stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.'
|
|
64
|
+
raise
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
MysqlCompat.define_all_hashes_method!
|
|
69
|
+
|
|
70
|
+
mysql = Mysql.init
|
|
71
|
+
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey]
|
|
72
|
+
|
|
73
|
+
default_flags = Mysql.const_defined?(:CLIENT_MULTI_RESULTS) ? Mysql::CLIENT_MULTI_RESULTS : 0
|
|
74
|
+
options = [host, username, password, database, port, socket, default_flags]
|
|
75
|
+
ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module ConnectionAdapters
|
|
80
|
+
class MysqlColumn < Column #:nodoc:
|
|
81
|
+
def extract_default(default)
|
|
82
|
+
if sql_type =~ /blob/i || type == :text
|
|
83
|
+
if default.blank?
|
|
84
|
+
return null ? nil : ''
|
|
85
|
+
else
|
|
86
|
+
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
|
87
|
+
end
|
|
88
|
+
elsif missing_default_forged_as_empty_string?(default)
|
|
89
|
+
nil
|
|
90
|
+
else
|
|
91
|
+
super
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def has_default?
|
|
96
|
+
return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns
|
|
97
|
+
super
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
def simplified_type(field_type)
|
|
102
|
+
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
|
|
103
|
+
return :string if field_type =~ /enum/i
|
|
104
|
+
super
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def extract_limit(sql_type)
|
|
108
|
+
case sql_type
|
|
109
|
+
when /blob|text/i
|
|
110
|
+
case sql_type
|
|
111
|
+
when /tiny/i
|
|
112
|
+
255
|
|
113
|
+
when /medium/i
|
|
114
|
+
16777215
|
|
115
|
+
when /long/i
|
|
116
|
+
2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
|
|
117
|
+
else
|
|
118
|
+
super # we could return 65535 here, but we leave it undecorated by default
|
|
119
|
+
end
|
|
120
|
+
when /^bigint/i; 8
|
|
121
|
+
when /^int/i; 4
|
|
122
|
+
when /^mediumint/i; 3
|
|
123
|
+
when /^smallint/i; 2
|
|
124
|
+
when /^tinyint/i; 1
|
|
125
|
+
else
|
|
126
|
+
super
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# MySQL misreports NOT NULL column default when none is given.
|
|
131
|
+
# We can't detect this for columns which may have a legitimate ''
|
|
132
|
+
# default (string) but we can for others (integer, datetime, boolean,
|
|
133
|
+
# and the rest).
|
|
134
|
+
#
|
|
135
|
+
# Test whether the column has default '', is not null, and is not
|
|
136
|
+
# a type allowing default ''.
|
|
137
|
+
def missing_default_forged_as_empty_string?(default)
|
|
138
|
+
type != :string && !null && default == ''
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with
|
|
143
|
+
# the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/).
|
|
144
|
+
#
|
|
145
|
+
# Options:
|
|
146
|
+
#
|
|
147
|
+
# * <tt>:host</tt> - Defaults to "localhost".
|
|
148
|
+
# * <tt>:port</tt> - Defaults to 3306.
|
|
149
|
+
# * <tt>:socket</tt> - Defaults to "/tmp/mysql.sock".
|
|
150
|
+
# * <tt>:username</tt> - Defaults to "root"
|
|
151
|
+
# * <tt>:password</tt> - Defaults to nothing.
|
|
152
|
+
# * <tt>:database</tt> - The name of the database. No default, must be provided.
|
|
153
|
+
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
|
|
154
|
+
# * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
|
|
155
|
+
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
|
|
156
|
+
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
|
|
157
|
+
# * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
|
|
158
|
+
# * <tt>:sslcapath</tt> - Necessary to use MySQL with an SSL connection.
|
|
159
|
+
# * <tt>:sslcipher</tt> - Necessary to use MySQL with an SSL connection.
|
|
160
|
+
#
|
|
161
|
+
class MysqlAdapter < AbstractAdapter
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# :singleton-method:
|
|
165
|
+
# By default, the MysqlAdapter will consider all columns of type <tt>tinyint(1)</tt>
|
|
166
|
+
# as boolean. If you wish to disable this emulation (which was the default
|
|
167
|
+
# behavior in versions 0.13.1 and earlier) you can add the following line
|
|
168
|
+
# to your environment.rb file:
|
|
169
|
+
#
|
|
170
|
+
# ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
|
|
171
|
+
cattr_accessor :emulate_booleans
|
|
172
|
+
self.emulate_booleans = true
|
|
173
|
+
|
|
174
|
+
ADAPTER_NAME = 'MySQL'.freeze
|
|
175
|
+
|
|
176
|
+
LOST_CONNECTION_ERROR_MESSAGES = [
|
|
177
|
+
"Server shutdown in progress",
|
|
178
|
+
"Broken pipe",
|
|
179
|
+
"Lost connection to MySQL server during query",
|
|
180
|
+
"MySQL server has gone away" ]
|
|
181
|
+
|
|
182
|
+
QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
|
|
183
|
+
|
|
184
|
+
NATIVE_DATABASE_TYPES = {
|
|
185
|
+
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
|
|
186
|
+
:string => { :name => "varchar", :limit => 255 },
|
|
187
|
+
:text => { :name => "text" },
|
|
188
|
+
:integer => { :name => "int", :limit => 4 },
|
|
189
|
+
:float => { :name => "float" },
|
|
190
|
+
:decimal => { :name => "decimal" },
|
|
191
|
+
:datetime => { :name => "datetime" },
|
|
192
|
+
:timestamp => { :name => "datetime" },
|
|
193
|
+
:time => { :name => "time" },
|
|
194
|
+
:date => { :name => "date" },
|
|
195
|
+
:binary => { :name => "blob" },
|
|
196
|
+
:boolean => { :name => "tinyint", :limit => 1 }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
def initialize(connection, logger, connection_options, config)
|
|
200
|
+
super(connection, logger)
|
|
201
|
+
@connection_options, @config = connection_options, config
|
|
202
|
+
@quoted_column_names, @quoted_table_names = {}, {}
|
|
203
|
+
connect
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def adapter_name #:nodoc:
|
|
207
|
+
ADAPTER_NAME
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def supports_migrations? #:nodoc:
|
|
211
|
+
true
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def supports_primary_key? #:nodoc:
|
|
215
|
+
true
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def supports_savepoints? #:nodoc:
|
|
219
|
+
true
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def native_database_types #:nodoc:
|
|
223
|
+
NATIVE_DATABASE_TYPES
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# QUOTING ==================================================
|
|
228
|
+
|
|
229
|
+
def quote(value, column = nil)
|
|
230
|
+
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
|
231
|
+
s = column.class.string_to_binary(value).unpack("H*")[0]
|
|
232
|
+
"x'#{s}'"
|
|
233
|
+
elsif value.kind_of?(BigDecimal)
|
|
234
|
+
value.to_s("F")
|
|
235
|
+
else
|
|
236
|
+
super
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def quote_column_name(name) #:nodoc:
|
|
241
|
+
@quoted_column_names[name] ||= "`#{name}`"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def quote_table_name(name) #:nodoc:
|
|
245
|
+
@quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def quote_string(string) #:nodoc:
|
|
249
|
+
@connection.quote(string)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def quoted_true
|
|
253
|
+
QUOTED_TRUE
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def quoted_false
|
|
257
|
+
QUOTED_FALSE
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# REFERENTIAL INTEGRITY ====================================
|
|
261
|
+
|
|
262
|
+
def disable_referential_integrity(&block) #:nodoc:
|
|
263
|
+
old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
|
|
264
|
+
|
|
265
|
+
begin
|
|
266
|
+
update("SET FOREIGN_KEY_CHECKS = 0")
|
|
267
|
+
yield
|
|
268
|
+
ensure
|
|
269
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# CONNECTION MANAGEMENT ====================================
|
|
274
|
+
|
|
275
|
+
def active?
|
|
276
|
+
if @connection.respond_to?(:stat)
|
|
277
|
+
@connection.stat
|
|
278
|
+
else
|
|
279
|
+
@connection.query 'select 1'
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# mysql-ruby doesn't raise an exception when stat fails.
|
|
283
|
+
if @connection.respond_to?(:errno)
|
|
284
|
+
@connection.errno.zero?
|
|
285
|
+
else
|
|
286
|
+
true
|
|
287
|
+
end
|
|
288
|
+
rescue Mysql::Error
|
|
289
|
+
false
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def reconnect!
|
|
293
|
+
disconnect!
|
|
294
|
+
connect
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def disconnect!
|
|
298
|
+
@connection.close rescue nil
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def reset!
|
|
302
|
+
if @connection.respond_to?(:change_user)
|
|
303
|
+
# See http://bugs.mysql.com/bug.php?id=33540 -- the workaround way to
|
|
304
|
+
# reset the connection is to change the user to the same user.
|
|
305
|
+
@connection.change_user(@config[:username], @config[:password], @config[:database])
|
|
306
|
+
configure_connection
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# DATABASE STATEMENTS ======================================
|
|
311
|
+
|
|
312
|
+
def select_rows(sql, name = nil)
|
|
313
|
+
@connection.query_with_result = true
|
|
314
|
+
result = execute(sql, name)
|
|
315
|
+
rows = []
|
|
316
|
+
result.each { |row| rows << row }
|
|
317
|
+
result.free
|
|
318
|
+
rows
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Executes a SQL query and returns a MySQL::Result object. Note that you have to free the Result object after you're done using it.
|
|
322
|
+
def execute(sql, name = nil) #:nodoc:
|
|
323
|
+
log(sql, name) { @connection.query(sql) }
|
|
324
|
+
rescue ActiveRecord::StatementInvalid => exception
|
|
325
|
+
if exception.message.split(":").first =~ /Packets out of order/
|
|
326
|
+
raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
|
|
327
|
+
else
|
|
328
|
+
raise
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
|
333
|
+
super sql, name
|
|
334
|
+
id_value || @connection.insert_id
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def update_sql(sql, name = nil) #:nodoc:
|
|
338
|
+
super
|
|
339
|
+
@connection.affected_rows
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def begin_db_transaction #:nodoc:
|
|
343
|
+
execute "BEGIN"
|
|
344
|
+
rescue Exception
|
|
345
|
+
# Transactions aren't supported
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def commit_db_transaction #:nodoc:
|
|
349
|
+
execute "COMMIT"
|
|
350
|
+
rescue Exception
|
|
351
|
+
# Transactions aren't supported
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def rollback_db_transaction #:nodoc:
|
|
355
|
+
execute "ROLLBACK"
|
|
356
|
+
rescue Exception
|
|
357
|
+
# Transactions aren't supported
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def create_savepoint
|
|
361
|
+
execute("SAVEPOINT #{current_savepoint_name}")
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def rollback_to_savepoint
|
|
365
|
+
execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def release_savepoint
|
|
369
|
+
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def add_limit_offset!(sql, options) #:nodoc:
|
|
373
|
+
if limit = options[:limit]
|
|
374
|
+
limit = sanitize_limit(limit)
|
|
375
|
+
unless offset = options[:offset]
|
|
376
|
+
sql << " LIMIT #{limit}"
|
|
377
|
+
else
|
|
378
|
+
sql << " LIMIT #{offset.to_i}, #{limit}"
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
# SCHEMA STATEMENTS ========================================
|
|
385
|
+
|
|
386
|
+
def structure_dump #:nodoc:
|
|
387
|
+
if supports_views?
|
|
388
|
+
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
|
389
|
+
else
|
|
390
|
+
sql = "SHOW TABLES"
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
select_all(sql).inject("") do |structure, table|
|
|
394
|
+
table.delete('Table_type')
|
|
395
|
+
structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n"
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def recreate_database(name, options = {}) #:nodoc:
|
|
400
|
+
drop_database(name)
|
|
401
|
+
create_database(name, options)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
|
405
|
+
# Charset defaults to utf8.
|
|
406
|
+
#
|
|
407
|
+
# Example:
|
|
408
|
+
# create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
|
|
409
|
+
# create_database 'matt_development'
|
|
410
|
+
# create_database 'matt_development', :charset => :big5
|
|
411
|
+
def create_database(name, options = {})
|
|
412
|
+
if options[:collation]
|
|
413
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
|
414
|
+
else
|
|
415
|
+
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def drop_database(name) #:nodoc:
|
|
420
|
+
execute "DROP DATABASE IF EXISTS `#{name}`"
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def current_database
|
|
424
|
+
select_value 'SELECT DATABASE() as db'
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# Returns the database character set.
|
|
428
|
+
def charset
|
|
429
|
+
show_variable 'character_set_database'
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Returns the database collation strategy.
|
|
433
|
+
def collation
|
|
434
|
+
show_variable 'collation_database'
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def tables(name = nil) #:nodoc:
|
|
438
|
+
tables = []
|
|
439
|
+
result = execute("SHOW TABLES", name)
|
|
440
|
+
result.each { |field| tables << field[0] }
|
|
441
|
+
result.free
|
|
442
|
+
tables
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def drop_table(table_name, options = {})
|
|
446
|
+
super(table_name, options)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def indexes(table_name, name = nil)#:nodoc:
|
|
450
|
+
indexes = []
|
|
451
|
+
current_index = nil
|
|
452
|
+
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
|
|
453
|
+
result.each do |row|
|
|
454
|
+
if current_index != row[2]
|
|
455
|
+
next if row[2] == "PRIMARY" # skip the primary key
|
|
456
|
+
current_index = row[2]
|
|
457
|
+
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [])
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
indexes.last.columns << row[4]
|
|
461
|
+
end
|
|
462
|
+
result.free
|
|
463
|
+
indexes
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def columns(table_name, name = nil)#:nodoc:
|
|
467
|
+
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
|
468
|
+
columns = []
|
|
469
|
+
result = execute(sql, name)
|
|
470
|
+
result.each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") }
|
|
471
|
+
result.free
|
|
472
|
+
columns
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def create_table(table_name, options = {}) #:nodoc:
|
|
476
|
+
super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def rename_table(table_name, new_name)
|
|
480
|
+
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
|
484
|
+
column = column_for(table_name, column_name)
|
|
485
|
+
change_column table_name, column_name, column.sql_type, :default => default
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def change_column_null(table_name, column_name, null, default = nil)
|
|
489
|
+
column = column_for(table_name, column_name)
|
|
490
|
+
|
|
491
|
+
unless null || default.nil?
|
|
492
|
+
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
change_column table_name, column_name, column.sql_type, :null => null
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
|
499
|
+
column = column_for(table_name, column_name)
|
|
500
|
+
|
|
501
|
+
unless options_include_default?(options)
|
|
502
|
+
options[:default] = column.default
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
unless options.has_key?(:null)
|
|
506
|
+
options[:null] = column.null
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
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])}"
|
|
510
|
+
add_column_options!(change_column_sql, options)
|
|
511
|
+
execute(change_column_sql)
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
|
515
|
+
options = {}
|
|
516
|
+
if column = columns(table_name).find { |c| c.name == column_name.to_s }
|
|
517
|
+
options[:default] = column.default
|
|
518
|
+
options[:null] = column.null
|
|
519
|
+
else
|
|
520
|
+
raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
|
|
521
|
+
end
|
|
522
|
+
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
|
523
|
+
rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
|
|
524
|
+
add_column_options!(rename_column_sql, options)
|
|
525
|
+
execute(rename_column_sql)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
# Maps logical Rails types to MySQL-specific data types.
|
|
529
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
|
530
|
+
return super unless type.to_s == 'integer'
|
|
531
|
+
|
|
532
|
+
case limit
|
|
533
|
+
when 1; 'tinyint'
|
|
534
|
+
when 2; 'smallint'
|
|
535
|
+
when 3; 'mediumint'
|
|
536
|
+
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
|
|
537
|
+
when 5..8; 'bigint'
|
|
538
|
+
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
# SHOW VARIABLES LIKE 'name'
|
|
544
|
+
def show_variable(name)
|
|
545
|
+
variables = select_all("SHOW VARIABLES LIKE '#{name}'")
|
|
546
|
+
variables.first['Value'] unless variables.empty?
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Returns a table's primary key and belonging sequence.
|
|
550
|
+
def pk_and_sequence_for(table) #:nodoc:
|
|
551
|
+
keys = []
|
|
552
|
+
result = execute("describe #{quote_table_name(table)}")
|
|
553
|
+
result.each_hash do |h|
|
|
554
|
+
keys << h["Field"]if h["Key"] == "PRI"
|
|
555
|
+
end
|
|
556
|
+
result.free
|
|
557
|
+
keys.length == 1 ? [keys.first, nil] : nil
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# Returns just a table's primary key
|
|
561
|
+
def primary_key(table)
|
|
562
|
+
pk_and_sequence = pk_and_sequence_for(table)
|
|
563
|
+
pk_and_sequence && pk_and_sequence.first
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def case_sensitive_equality_operator
|
|
567
|
+
"= BINARY"
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
|
|
571
|
+
where_sql
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
private
|
|
575
|
+
def connect
|
|
576
|
+
encoding = @config[:encoding]
|
|
577
|
+
if encoding
|
|
578
|
+
@connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
if @config[:sslca] || @config[:sslkey]
|
|
582
|
+
@connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher])
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
@connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout]
|
|
586
|
+
@connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout]
|
|
587
|
+
@connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout]
|
|
588
|
+
|
|
589
|
+
@connection.real_connect(*@connection_options)
|
|
590
|
+
|
|
591
|
+
# reconnect must be set after real_connect is called, because real_connect sets it to false internally
|
|
592
|
+
@connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=)
|
|
593
|
+
|
|
594
|
+
configure_connection
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
def configure_connection
|
|
598
|
+
encoding = @config[:encoding]
|
|
599
|
+
execute("SET NAMES '#{encoding}'") if encoding
|
|
600
|
+
|
|
601
|
+
# By default, MySQL 'where id is null' selects the last inserted id.
|
|
602
|
+
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
|
603
|
+
execute("SET SQL_AUTO_IS_NULL=0")
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
def select(sql, name = nil)
|
|
607
|
+
@connection.query_with_result = true
|
|
608
|
+
result = execute(sql, name)
|
|
609
|
+
rows = result.all_hashes
|
|
610
|
+
result.free
|
|
611
|
+
rows
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def supports_views?
|
|
615
|
+
version[0] >= 5
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
def version
|
|
619
|
+
@version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
def column_for(table_name, column_name)
|
|
623
|
+
unless column = columns(table_name).find { |c| c.name == column_name.to_s }
|
|
624
|
+
raise "No such column: #{table_name}.#{column_name}"
|
|
625
|
+
end
|
|
626
|
+
column
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
end
|