activerecord 1.0.0 → 4.0.0
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2102 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +213 -0
- data/examples/performance.rb +172 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record/aggregations.rb +180 -84
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +248 -0
- data/lib/active_record/associations/association_scope.rb +135 -0
- data/lib/active_record/associations/belongs_to_association.rb +92 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +35 -0
- data/lib/active_record/associations/builder/association.rb +108 -0
- data/lib/active_record/associations/builder/belongs_to.rb +98 -0
- data/lib/active_record/associations/builder/collection_association.rb +89 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +25 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +608 -0
- data/lib/active_record/associations/collection_proxy.rb +986 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +58 -39
- data/lib/active_record/associations/has_many_association.rb +116 -85
- data/lib/active_record/associations/has_many_through_association.rb +197 -0
- data/lib/active_record/associations/has_one_association.rb +102 -0
- data/lib/active_record/associations/has_one_through_association.rb +36 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +235 -0
- data/lib/active_record/associations/join_helper.rb +45 -0
- data/lib/active_record/associations/preloader/association.rb +121 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +63 -0
- data/lib/active_record/associations/preloader.rb +178 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +1437 -431
- data/lib/active_record/attribute_assignment.rb +201 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +70 -0
- data/lib/active_record/attribute_methods/dirty.rb +118 -0
- data/lib/active_record/attribute_methods/primary_key.rb +122 -0
- data/lib/active_record/attribute_methods/query.rb +40 -0
- data/lib/active_record/attribute_methods/read.rb +107 -0
- data/lib/active_record/attribute_methods/serialization.rb +162 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -0
- data/lib/active_record/attribute_methods/write.rb +63 -0
- data/lib/active_record/attribute_methods.rb +393 -0
- data/lib/active_record/autosave_association.rb +426 -0
- data/lib/active_record/base.rb +268 -930
- data/lib/active_record/callbacks.rb +203 -230
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +638 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +390 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +129 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +501 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +873 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +389 -275
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
- data/lib/active_record/connection_adapters/column.rb +318 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +517 -90
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +911 -138
- data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +624 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +463 -0
- data/lib/active_record/counter_cache.rb +122 -0
- data/lib/active_record/dynamic_matchers.rb +131 -0
- data/lib/active_record/errors.rb +213 -0
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +892 -138
- data/lib/active_record/inheritance.rb +200 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +47 -0
- data/lib/active_record/locking/optimistic.rb +181 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/log_subscriber.rb +82 -0
- data/lib/active_record/migration/command_recorder.rb +164 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +1015 -0
- data/lib/active_record/model_schema.rb +345 -0
- data/lib/active_record/nested_attributes.rb +546 -0
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +509 -0
- data/lib/active_record/query_cache.rb +56 -0
- data/lib/active_record/querying.rb +62 -0
- data/lib/active_record/railtie.rb +205 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +50 -0
- data/lib/active_record/railties/databases.rake +402 -0
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +30 -0
- data/lib/active_record/reflection.rb +544 -87
- data/lib/active_record/relation/batches.rb +93 -0
- data/lib/active_record/relation/calculations.rb +399 -0
- data/lib/active_record/relation/delegation.rb +125 -0
- data/lib/active_record/relation/finder_methods.rb +349 -0
- data/lib/active_record/relation/merger.rb +161 -0
- data/lib/active_record/relation/predicate_builder.rb +106 -0
- data/lib/active_record/relation/query_methods.rb +1044 -0
- data/lib/active_record/relation/spawn_methods.rb +73 -0
- data/lib/active_record/relation.rb +655 -0
- data/lib/active_record/result.rb +67 -0
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +168 -0
- data/lib/active_record/schema.rb +65 -0
- data/lib/active_record/schema_dumper.rb +204 -0
- data/lib/active_record/schema_migration.rb +39 -0
- data/lib/active_record/scoping/default.rb +146 -0
- data/lib/active_record/scoping/named.rb +175 -0
- data/lib/active_record/scoping.rb +82 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/serializers/xml_serializer.rb +197 -0
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +156 -0
- data/lib/active_record/tasks/database_tasks.rb +203 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/test_case.rb +96 -0
- data/lib/active_record/timestamp.rb +119 -0
- data/lib/active_record/transactions.rb +366 -69
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +49 -0
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +225 -0
- data/lib/active_record/validations.rb +64 -185
- data/lib/active_record/version.rb +11 -0
- data/lib/active_record.rb +149 -24
- data/lib/rails/generators/active_record/migration/migration_generator.rb +62 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +39 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
- data/lib/rails/generators/active_record.rb +23 -0
- metadata +261 -161
- data/CHANGELOG +0 -581
- data/README +0 -361
- data/RUNNING_UNIT_TESTS +0 -36
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.png +0 -0
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/install.rb +0 -60
- data/lib/active_record/associations/association_collection.rb +0 -70
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -107
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/observer.rb +0 -71
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/mysql.rb +0 -1117
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/abstract_unit.rb +0 -16
- data/test/aggregations_test.rb +0 -34
- data/test/all.sh +0 -8
- data/test/associations_test.rb +0 -477
- data/test/base_test.rb +0 -513
- data/test/class_inheritable_attributes_test.rb +0 -33
- data/test/connections/native_mysql/connection.rb +0 -24
- data/test/connections/native_postgresql/connection.rb +0 -24
- data/test/connections/native_sqlite/connection.rb +0 -24
- data/test/deprecated_associations_test.rb +0 -336
- data/test/finder_test.rb +0 -67
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/auto_id.rb +0 -4
- data/test/fixtures/column_name.rb +0 -3
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/company.rb +0 -37
- data/test/fixtures/company_in_module.rb +0 -33
- data/test/fixtures/course.rb +0 -3
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customer.rb +0 -30
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/db_definitions/postgresql.sql +0 -113
- data/test/fixtures/db_definitions/postgresql2.sql +0 -4
- data/test/fixtures/db_definitions/sqlite.sql +0 -85
- data/test/fixtures/db_definitions/sqlite2.sql +0 -4
- data/test/fixtures/default.rb +0 -2
- data/test/fixtures/developer.rb +0 -8
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/developers_projects/david_action_controller +0 -2
- data/test/fixtures/developers_projects/david_active_record +0 -2
- data/test/fixtures/developers_projects/jamis_active_record +0 -2
- data/test/fixtures/entrant.rb +0 -3
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movie.rb +0 -5
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/project.rb +0 -3
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/reply.rb +0 -21
- data/test/fixtures/subscriber.rb +0 -5
- data/test/fixtures/subscribers/first +0 -2
- data/test/fixtures/subscribers/second +0 -2
- data/test/fixtures/topic.rb +0 -20
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/fixtures_test.rb +0 -20
- data/test/inflector_test.rb +0 -104
- data/test/inheritance_test.rb +0 -125
- data/test/lifecycle_test.rb +0 -110
- data/test/modules_test.rb +0 -21
- data/test/multiple_db_test.rb +0 -46
- data/test/pk_test.rb +0 -57
- data/test/reflection_test.rb +0 -78
- data/test/thread_safety_test.rb +0 -33
- data/test/transactions_test.rb +0 -83
- data/test/unconnected_test.rb +0 -24
- data/test/validations_test.rb +0 -126
| @@ -1,131 +1,558 @@ | |
| 1 | 
            -
            require 'active_record/connection_adapters/ | 
| 2 | 
            -
            require ' | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
                 | 
| 1 | 
            +
            require 'active_record/connection_adapters/abstract_mysql_adapter'
         | 
| 2 | 
            +
            require 'active_record/connection_adapters/statement_pool'
         | 
| 3 | 
            +
            require 'active_support/core_ext/hash/keys'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            gem 'mysql', '~> 2.9'
         | 
| 6 | 
            +
            require 'mysql'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class Mysql
         | 
| 9 | 
            +
              class Time
         | 
| 10 | 
            +
                def to_date
         | 
| 11 | 
            +
                  Date.new(year, month, day)
         | 
| 12 | 
            +
                end
         | 
| 11 13 | 
             
              end
         | 
| 14 | 
            +
              class Stmt; include Enumerable end
         | 
| 15 | 
            +
              class Result; include Enumerable end
         | 
| 16 | 
            +
            end
         | 
| 12 17 |  | 
| 13 18 | 
             
            module ActiveRecord
         | 
| 14 | 
            -
               | 
| 15 | 
            -
                # Establishes a connection to the database that's used by all Active Record objects
         | 
| 16 | 
            -
                def  | 
| 17 | 
            -
                   | 
| 19 | 
            +
              module ConnectionHandling # :nodoc:
         | 
| 20 | 
            +
                # Establishes a connection to the database that's used by all Active Record objects.
         | 
| 21 | 
            +
                def mysql_connection(config)
         | 
| 22 | 
            +
                  config = config.symbolize_keys
         | 
| 18 23 | 
             
                  host     = config[:host]
         | 
| 19 24 | 
             
                  port     = config[:port]
         | 
| 20 25 | 
             
                  socket   = config[:socket]
         | 
| 21 | 
            -
                  username = config[:username]  | 
| 22 | 
            -
                  password = config[:password]
         | 
| 26 | 
            +
                  username = config[:username] ? config[:username].to_s : 'root'
         | 
| 27 | 
            +
                  password = config[:password].to_s
         | 
| 28 | 
            +
                  database = config[:database]
         | 
| 23 29 |  | 
| 24 | 
            -
                   | 
| 25 | 
            -
             | 
| 26 | 
            -
                  else
         | 
| 27 | 
            -
                    raise ArgumentError, "No database specified. Missing argument: database."
         | 
| 28 | 
            -
                  end
         | 
| 30 | 
            +
                  mysql = Mysql.init
         | 
| 31 | 
            +
                  mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey]
         | 
| 29 32 |  | 
| 30 | 
            -
                   | 
| 31 | 
            -
             | 
| 32 | 
            -
                   | 
| 33 | 
            +
                  default_flags = Mysql.const_defined?(:CLIENT_MULTI_RESULTS) ? Mysql::CLIENT_MULTI_RESULTS : 0
         | 
| 34 | 
            +
                  default_flags |= Mysql::CLIENT_FOUND_ROWS if Mysql.const_defined?(:CLIENT_FOUND_ROWS)
         | 
| 35 | 
            +
                  options = [host, username, password, database, port, socket, default_flags]
         | 
| 36 | 
            +
                  ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config)
         | 
| 33 37 | 
             
                end
         | 
| 34 38 | 
             
              end
         | 
| 35 39 |  | 
| 36 40 | 
             
              module ConnectionAdapters
         | 
| 37 | 
            -
                 | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 41 | 
            +
                # The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with
         | 
| 42 | 
            +
                # the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/).
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # Options:
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # * <tt>:host</tt> - Defaults to "localhost".
         | 
| 47 | 
            +
                # * <tt>:port</tt> - Defaults to 3306.
         | 
| 48 | 
            +
                # * <tt>:socket</tt> - Defaults to "/tmp/mysql.sock".
         | 
| 49 | 
            +
                # * <tt>:username</tt> - Defaults to "root"
         | 
| 50 | 
            +
                # * <tt>:password</tt> - Defaults to nothing.
         | 
| 51 | 
            +
                # * <tt>:database</tt> - The name of the database. No default, must be provided.
         | 
| 52 | 
            +
                # * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
         | 
| 53 | 
            +
                # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
         | 
| 54 | 
            +
                # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html)
         | 
| 55 | 
            +
                # * <tt>:variables</tt> - (Optional) A hash session variables to send as `SET @@SESSION.key = value` on each database connection. Use the value `:default` to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
         | 
| 56 | 
            +
                # * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
         | 
| 57 | 
            +
                # * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
         | 
| 58 | 
            +
                # * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
         | 
| 59 | 
            +
                # * <tt>:sslcapath</tt> - Necessary to use MySQL with an SSL connection.
         | 
| 60 | 
            +
                # * <tt>:sslcipher</tt> - Necessary to use MySQL with an SSL connection.
         | 
| 61 | 
            +
                #
         | 
| 62 | 
            +
                class MysqlAdapter < AbstractMysqlAdapter
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  class Column < AbstractMysqlAdapter::Column #:nodoc:
         | 
| 65 | 
            +
                    def self.string_to_time(value)
         | 
| 66 | 
            +
                      return super unless Mysql::Time === value
         | 
| 67 | 
            +
                      new_time(
         | 
| 68 | 
            +
                        value.year,
         | 
| 69 | 
            +
                        value.month,
         | 
| 70 | 
            +
                        value.day,
         | 
| 71 | 
            +
                        value.hour,
         | 
| 72 | 
            +
                        value.minute,
         | 
| 73 | 
            +
                        value.second,
         | 
| 74 | 
            +
                        value.second_part)
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    def self.string_to_dummy_time(v)
         | 
| 78 | 
            +
                      return super unless Mysql::Time === v
         | 
| 79 | 
            +
                      new_time(2000, 01, 01, v.hour, v.minute, v.second, v.second_part)
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    def self.string_to_date(v)
         | 
| 83 | 
            +
                      return super unless Mysql::Time === v
         | 
| 84 | 
            +
                      new_date(v.year, v.month, v.day)
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    def adapter
         | 
| 88 | 
            +
                      MysqlAdapter
         | 
| 89 | 
            +
                    end
         | 
| 40 90 | 
             
                  end
         | 
| 41 91 |  | 
| 42 | 
            -
                   | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 92 | 
            +
                  ADAPTER_NAME = 'MySQL'
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  class StatementPool < ConnectionAdapters::StatementPool
         | 
| 95 | 
            +
                    def initialize(connection, max = 1000)
         | 
| 96 | 
            +
                      super
         | 
| 97 | 
            +
                      @cache = Hash.new { |h,pid| h[pid] = {} }
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    def each(&block); cache.each(&block); end
         | 
| 101 | 
            +
                    def key?(key);    cache.key?(key); end
         | 
| 102 | 
            +
                    def [](key);      cache[key]; end
         | 
| 103 | 
            +
                    def length;       cache.length; end
         | 
| 104 | 
            +
                    def delete(key);  cache.delete(key); end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                    def []=(sql, key)
         | 
| 107 | 
            +
                      while @max <= cache.size
         | 
| 108 | 
            +
                        cache.shift.last[:stmt].close
         | 
| 109 | 
            +
                      end
         | 
| 110 | 
            +
                      cache[sql] = key
         | 
| 111 | 
            +
                    end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    def clear
         | 
| 114 | 
            +
                      cache.values.each do |hash|
         | 
| 115 | 
            +
                        hash[:stmt].close
         | 
| 116 | 
            +
                      end
         | 
| 117 | 
            +
                      cache.clear
         | 
| 118 | 
            +
                    end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                    private
         | 
| 121 | 
            +
                    def cache
         | 
| 122 | 
            +
                      @cache[Process.pid]
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  def initialize(connection, logger, connection_options, config)
         | 
| 127 | 
            +
                    super
         | 
| 128 | 
            +
                    @statements = StatementPool.new(@connection,
         | 
| 129 | 
            +
                                                    self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
         | 
| 130 | 
            +
                    @client_encoding = nil
         | 
| 131 | 
            +
                    connect
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  # Returns true, since this connection adapter supports prepared statement
         | 
| 135 | 
            +
                  # caching.
         | 
| 136 | 
            +
                  def supports_statement_cache?
         | 
| 137 | 
            +
                    true
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  # HELPER METHODS ===========================================
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  def each_hash(result) # :nodoc:
         | 
| 143 | 
            +
                    if block_given?
         | 
| 144 | 
            +
                      result.each_hash do |row|
         | 
| 145 | 
            +
                        row.symbolize_keys!
         | 
| 146 | 
            +
                        yield row
         | 
| 147 | 
            +
                      end
         | 
| 148 | 
            +
                    else
         | 
| 149 | 
            +
                      to_enum(:each_hash, result)
         | 
| 150 | 
            +
                    end
         | 
| 45 151 | 
             
                  end
         | 
| 46 152 |  | 
| 47 | 
            -
                  def  | 
| 48 | 
            -
                     | 
| 49 | 
            -
             | 
| 50 | 
            -
                    log(sql, name, @connection) { |connection| result = connection.query(sql) }
         | 
| 153 | 
            +
                  def new_column(field, default, type, null, collation, extra = "") # :nodoc:
         | 
| 154 | 
            +
                    Column.new(field, default, type, null, collation, strict_mode?, extra)
         | 
| 155 | 
            +
                  end
         | 
| 51 156 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
                     | 
| 54 | 
            -
                    columns
         | 
| 157 | 
            +
                  def error_number(exception) # :nodoc:
         | 
| 158 | 
            +
                    exception.errno if exception.respond_to?(:errno)
         | 
| 55 159 | 
             
                  end
         | 
| 56 160 |  | 
| 57 | 
            -
                   | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 161 | 
            +
                  # QUOTING ==================================================
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  def type_cast(value, column)
         | 
| 164 | 
            +
                    return super unless value == true || value == false
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    value ? 1 : 0
         | 
| 60 167 | 
             
                  end
         | 
| 61 168 |  | 
| 62 | 
            -
                  def  | 
| 63 | 
            -
                     | 
| 169 | 
            +
                  def quote_string(string) #:nodoc:
         | 
| 170 | 
            +
                    @connection.quote(string)
         | 
| 64 171 | 
             
                  end
         | 
| 65 172 |  | 
| 66 | 
            -
                   | 
| 67 | 
            -
             | 
| 68 | 
            -
                  
         | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 173 | 
            +
                  # CONNECTION MANAGEMENT ====================================
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  def active?
         | 
| 176 | 
            +
                    if @connection.respond_to?(:stat)
         | 
| 177 | 
            +
                      @connection.stat
         | 
| 178 | 
            +
                    else
         | 
| 179 | 
            +
                      @connection.query 'select 1'
         | 
| 180 | 
            +
                    end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                    # mysql-ruby doesn't raise an exception when stat fails.
         | 
| 183 | 
            +
                    if @connection.respond_to?(:errno)
         | 
| 184 | 
            +
                      @connection.errno.zero?
         | 
| 185 | 
            +
                    else
         | 
| 186 | 
            +
                      true
         | 
| 74 187 | 
             
                    end
         | 
| 188 | 
            +
                  rescue Mysql::Error
         | 
| 189 | 
            +
                    false
         | 
| 190 | 
            +
                  end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                  def reconnect!
         | 
| 193 | 
            +
                    super
         | 
| 194 | 
            +
                    disconnect!
         | 
| 195 | 
            +
                    connect
         | 
| 196 | 
            +
                  end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                  # Disconnects from the database if already connected. Otherwise, this
         | 
| 199 | 
            +
                  # method does nothing.
         | 
| 200 | 
            +
                  def disconnect!
         | 
| 201 | 
            +
                    super
         | 
| 202 | 
            +
                    @connection.close rescue nil
         | 
| 75 203 | 
             
                  end
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                  def  | 
| 78 | 
            -
                     | 
| 79 | 
            -
                       | 
| 80 | 
            -
             | 
| 81 | 
            -
                       | 
| 204 | 
            +
             | 
| 205 | 
            +
                  def reset!
         | 
| 206 | 
            +
                    if @connection.respond_to?(:change_user)
         | 
| 207 | 
            +
                      # See http://bugs.mysql.com/bug.php?id=33540 -- the workaround way to
         | 
| 208 | 
            +
                      # reset the connection is to change the user to the same user.
         | 
| 209 | 
            +
                      @connection.change_user(@config[:username], @config[:password], @config[:database])
         | 
| 210 | 
            +
                      configure_connection
         | 
| 82 211 | 
             
                    end
         | 
| 83 212 | 
             
                  end
         | 
| 84 | 
            -
             | 
| 85 | 
            -
                   | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
                     | 
| 89 | 
            -
             | 
| 213 | 
            +
             | 
| 214 | 
            +
                  # DATABASE STATEMENTS ======================================
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                  def select_rows(sql, name = nil)
         | 
| 217 | 
            +
                    @connection.query_with_result = true
         | 
| 218 | 
            +
                    rows = exec_query(sql, name).rows
         | 
| 219 | 
            +
                    @connection.more_results && @connection.next_result    # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
         | 
| 220 | 
            +
                    rows
         | 
| 221 | 
            +
                  end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                  # Clears the prepared statements cache.
         | 
| 224 | 
            +
                  def clear_cache!
         | 
| 225 | 
            +
                    @statements.clear
         | 
| 226 | 
            +
                  end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  # Taken from here:
         | 
| 229 | 
            +
                  #   https://github.com/tmtm/ruby-mysql/blob/master/lib/mysql/charset.rb
         | 
| 230 | 
            +
                  # Author: TOMITA Masahiro <tommy@tmtm.org>
         | 
| 231 | 
            +
                  ENCODINGS = {
         | 
| 232 | 
            +
                    "armscii8" => nil,
         | 
| 233 | 
            +
                    "ascii"    => Encoding::US_ASCII,
         | 
| 234 | 
            +
                    "big5"     => Encoding::Big5,
         | 
| 235 | 
            +
                    "binary"   => Encoding::ASCII_8BIT,
         | 
| 236 | 
            +
                    "cp1250"   => Encoding::Windows_1250,
         | 
| 237 | 
            +
                    "cp1251"   => Encoding::Windows_1251,
         | 
| 238 | 
            +
                    "cp1256"   => Encoding::Windows_1256,
         | 
| 239 | 
            +
                    "cp1257"   => Encoding::Windows_1257,
         | 
| 240 | 
            +
                    "cp850"    => Encoding::CP850,
         | 
| 241 | 
            +
                    "cp852"    => Encoding::CP852,
         | 
| 242 | 
            +
                    "cp866"    => Encoding::IBM866,
         | 
| 243 | 
            +
                    "cp932"    => Encoding::Windows_31J,
         | 
| 244 | 
            +
                    "dec8"     => nil,
         | 
| 245 | 
            +
                    "eucjpms"  => Encoding::EucJP_ms,
         | 
| 246 | 
            +
                    "euckr"    => Encoding::EUC_KR,
         | 
| 247 | 
            +
                    "gb2312"   => Encoding::EUC_CN,
         | 
| 248 | 
            +
                    "gbk"      => Encoding::GBK,
         | 
| 249 | 
            +
                    "geostd8"  => nil,
         | 
| 250 | 
            +
                    "greek"    => Encoding::ISO_8859_7,
         | 
| 251 | 
            +
                    "hebrew"   => Encoding::ISO_8859_8,
         | 
| 252 | 
            +
                    "hp8"      => nil,
         | 
| 253 | 
            +
                    "keybcs2"  => nil,
         | 
| 254 | 
            +
                    "koi8r"    => Encoding::KOI8_R,
         | 
| 255 | 
            +
                    "koi8u"    => Encoding::KOI8_U,
         | 
| 256 | 
            +
                    "latin1"   => Encoding::ISO_8859_1,
         | 
| 257 | 
            +
                    "latin2"   => Encoding::ISO_8859_2,
         | 
| 258 | 
            +
                    "latin5"   => Encoding::ISO_8859_9,
         | 
| 259 | 
            +
                    "latin7"   => Encoding::ISO_8859_13,
         | 
| 260 | 
            +
                    "macce"    => Encoding::MacCentEuro,
         | 
| 261 | 
            +
                    "macroman" => Encoding::MacRoman,
         | 
| 262 | 
            +
                    "sjis"     => Encoding::SHIFT_JIS,
         | 
| 263 | 
            +
                    "swe7"     => nil,
         | 
| 264 | 
            +
                    "tis620"   => Encoding::TIS_620,
         | 
| 265 | 
            +
                    "ucs2"     => Encoding::UTF_16BE,
         | 
| 266 | 
            +
                    "ujis"     => Encoding::EucJP_ms,
         | 
| 267 | 
            +
                    "utf8"     => Encoding::UTF_8,
         | 
| 268 | 
            +
                    "utf8mb4"  => Encoding::UTF_8,
         | 
| 269 | 
            +
                  }
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                  # Get the client encoding for this database
         | 
| 272 | 
            +
                  def client_encoding
         | 
| 273 | 
            +
                    return @client_encoding if @client_encoding
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                    result = exec_query(
         | 
| 276 | 
            +
                      "SHOW VARIABLES WHERE Variable_name = 'character_set_client'",
         | 
| 277 | 
            +
                      'SCHEMA')
         | 
| 278 | 
            +
                    @client_encoding = ENCODINGS[result.rows.last.last]
         | 
| 279 | 
            +
                  end
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                  def exec_query(sql, name = 'SQL', binds = [])
         | 
| 282 | 
            +
                    # If the configuration sets prepared_statements:false, binds will
         | 
| 283 | 
            +
                    # always be empty, since the bind variables will have been already
         | 
| 284 | 
            +
                    # substituted and removed from binds by BindVisitor, so this will
         | 
| 285 | 
            +
                    # effectively disable prepared statement usage completely.
         | 
| 286 | 
            +
                    if binds.empty?
         | 
| 287 | 
            +
                      result_set, affected_rows = exec_without_stmt(sql, name)
         | 
| 288 | 
            +
                    else
         | 
| 289 | 
            +
                      result_set, affected_rows = exec_stmt(sql, name, binds)
         | 
| 90 290 | 
             
                    end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                    yield affected_rows if block_given?
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                    result_set
         | 
| 91 295 | 
             
                  end
         | 
| 92 296 |  | 
| 93 | 
            -
                  def  | 
| 94 | 
            -
                     | 
| 297 | 
            +
                  def last_inserted_id(result)
         | 
| 298 | 
            +
                    @connection.insert_id
         | 
| 95 299 | 
             
                  end
         | 
| 96 | 
            -
             | 
| 97 | 
            -
                   | 
| 98 | 
            -
                     | 
| 99 | 
            -
                       | 
| 300 | 
            +
             | 
| 301 | 
            +
                  module Fields
         | 
| 302 | 
            +
                    class Type
         | 
| 303 | 
            +
                      def type; end
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                      def type_cast_for_write(value)
         | 
| 306 | 
            +
                        value
         | 
| 307 | 
            +
                      end
         | 
| 308 | 
            +
                    end
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                    class Identity < Type
         | 
| 311 | 
            +
                      def type_cast(value); value; end
         | 
| 100 312 | 
             
                    end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                    class Integer < Type
         | 
| 315 | 
            +
                      def type_cast(value)
         | 
| 316 | 
            +
                        return if value.nil?
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                        value.to_i rescue value ? 1 : 0
         | 
| 319 | 
            +
                      end
         | 
| 320 | 
            +
                    end
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                    class Date < Type
         | 
| 323 | 
            +
                      def type; :date; end
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                      def type_cast(value)
         | 
| 326 | 
            +
                        return if value.nil?
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                        # FIXME: probably we can improve this since we know it is mysql
         | 
| 329 | 
            +
                        # specific
         | 
| 330 | 
            +
                        ConnectionAdapters::Column.value_to_date value
         | 
| 331 | 
            +
                      end
         | 
| 332 | 
            +
                    end
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                    class DateTime < Type
         | 
| 335 | 
            +
                      def type; :datetime; end
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                      def type_cast(value)
         | 
| 338 | 
            +
                        return if value.nil?
         | 
| 339 | 
            +
             | 
| 340 | 
            +
                        # FIXME: probably we can improve this since we know it is mysql
         | 
| 341 | 
            +
                        # specific
         | 
| 342 | 
            +
                        ConnectionAdapters::Column.string_to_time value
         | 
| 343 | 
            +
                      end
         | 
| 344 | 
            +
                    end
         | 
| 345 | 
            +
             | 
| 346 | 
            +
                    class Time < Type
         | 
| 347 | 
            +
                      def type; :time; end
         | 
| 348 | 
            +
             | 
| 349 | 
            +
                      def type_cast(value)
         | 
| 350 | 
            +
                        return if value.nil?
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                        # FIXME: probably we can improve this since we know it is mysql
         | 
| 353 | 
            +
                        # specific
         | 
| 354 | 
            +
                        ConnectionAdapters::Column.string_to_dummy_time value
         | 
| 355 | 
            +
                      end
         | 
| 356 | 
            +
                    end
         | 
| 357 | 
            +
             | 
| 358 | 
            +
                    class Float < Type
         | 
| 359 | 
            +
                      def type; :float; end
         | 
| 360 | 
            +
             | 
| 361 | 
            +
                      def type_cast(value)
         | 
| 362 | 
            +
                        return if value.nil?
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                        value.to_f
         | 
| 365 | 
            +
                      end
         | 
| 366 | 
            +
                    end
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                    class Decimal < Type
         | 
| 369 | 
            +
                      def type_cast(value)
         | 
| 370 | 
            +
                        return if value.nil?
         | 
| 371 | 
            +
             | 
| 372 | 
            +
                        ConnectionAdapters::Column.value_to_decimal value
         | 
| 373 | 
            +
                      end
         | 
| 374 | 
            +
                    end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                    class Boolean < Type
         | 
| 377 | 
            +
                      def type_cast(value)
         | 
| 378 | 
            +
                        return if value.nil?
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                        ConnectionAdapters::Column.value_to_boolean value
         | 
| 381 | 
            +
                      end
         | 
| 382 | 
            +
                    end
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                    TYPES = {}
         | 
| 385 | 
            +
             | 
| 386 | 
            +
                    # Register an MySQL +type_id+ with a typecasting object in
         | 
| 387 | 
            +
                    # +type+.
         | 
| 388 | 
            +
                    def self.register_type(type_id, type)
         | 
| 389 | 
            +
                      TYPES[type_id] = type
         | 
| 390 | 
            +
                    end
         | 
| 391 | 
            +
             | 
| 392 | 
            +
                    def self.alias_type(new, old)
         | 
| 393 | 
            +
                      TYPES[new] = TYPES[old]
         | 
| 394 | 
            +
                    end
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                    register_type Mysql::Field::TYPE_TINY,    Fields::Boolean.new
         | 
| 397 | 
            +
                    register_type Mysql::Field::TYPE_LONG,    Fields::Integer.new
         | 
| 398 | 
            +
                    alias_type Mysql::Field::TYPE_LONGLONG,   Mysql::Field::TYPE_LONG
         | 
| 399 | 
            +
                    alias_type Mysql::Field::TYPE_NEWDECIMAL, Mysql::Field::TYPE_LONG
         | 
| 400 | 
            +
             | 
| 401 | 
            +
                    register_type Mysql::Field::TYPE_VAR_STRING, Fields::Identity.new
         | 
| 402 | 
            +
                    register_type Mysql::Field::TYPE_BLOB, Fields::Identity.new
         | 
| 403 | 
            +
                    register_type Mysql::Field::TYPE_DATE, Fields::Date.new
         | 
| 404 | 
            +
                    register_type Mysql::Field::TYPE_DATETIME, Fields::DateTime.new
         | 
| 405 | 
            +
                    register_type Mysql::Field::TYPE_TIME, Fields::Time.new
         | 
| 406 | 
            +
                    register_type Mysql::Field::TYPE_FLOAT, Fields::Float.new
         | 
| 407 | 
            +
             | 
| 408 | 
            +
                    Mysql::Field.constants.grep(/TYPE/).map { |class_name|
         | 
| 409 | 
            +
                      Mysql::Field.const_get class_name
         | 
| 410 | 
            +
                    }.reject { |const| TYPES.key? const }.each do |const|
         | 
| 411 | 
            +
                      register_type const, Fields::Identity.new
         | 
| 412 | 
            +
                    end
         | 
| 413 | 
            +
                  end
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                  def exec_without_stmt(sql, name = 'SQL') # :nodoc:
         | 
| 416 | 
            +
                    # Some queries, like SHOW CREATE TABLE don't work through the prepared
         | 
| 417 | 
            +
                    # statement API. For those queries, we need to use this method. :'(
         | 
| 418 | 
            +
                    log(sql, name) do
         | 
| 419 | 
            +
                      result = @connection.query(sql)
         | 
| 420 | 
            +
                      affected_rows = @connection.affected_rows
         | 
| 421 | 
            +
             | 
| 422 | 
            +
                      if result
         | 
| 423 | 
            +
                        types = {}
         | 
| 424 | 
            +
                        result.fetch_fields.each { |field|
         | 
| 425 | 
            +
                          if field.decimals > 0
         | 
| 426 | 
            +
                            types[field.name] = Fields::Decimal.new
         | 
| 427 | 
            +
                          else
         | 
| 428 | 
            +
                            types[field.name] = Fields::TYPES.fetch(field.type) {
         | 
| 429 | 
            +
                              Fields::Identity.new
         | 
| 430 | 
            +
                            }
         | 
| 431 | 
            +
                          end
         | 
| 432 | 
            +
                        }
         | 
| 433 | 
            +
                        result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
         | 
| 434 | 
            +
                        result.free
         | 
| 435 | 
            +
                      else
         | 
| 436 | 
            +
                        result_set = ActiveRecord::Result.new([], [])
         | 
| 437 | 
            +
                      end
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                      [result_set, affected_rows]
         | 
| 440 | 
            +
                    end
         | 
| 441 | 
            +
                  end
         | 
| 442 | 
            +
             | 
| 443 | 
            +
                  def execute_and_free(sql, name = nil)
         | 
| 444 | 
            +
                    result = execute(sql, name)
         | 
| 445 | 
            +
                    ret = yield result
         | 
| 446 | 
            +
                    result.free
         | 
| 447 | 
            +
                    ret
         | 
| 101 448 | 
             
                  end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                  def  | 
| 104 | 
            -
                     | 
| 105 | 
            -
                     | 
| 449 | 
            +
             | 
| 450 | 
            +
                  def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
         | 
| 451 | 
            +
                    super sql, name
         | 
| 452 | 
            +
                    id_value || @connection.insert_id
         | 
| 106 453 | 
             
                  end
         | 
| 107 | 
            -
                  
         | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 454 | 
            +
                  alias :create :insert_sql
         | 
| 455 | 
            +
             | 
| 456 | 
            +
                  def exec_delete(sql, name, binds)
         | 
| 457 | 
            +
                    affected_rows = 0
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                    exec_query(sql, name, binds) do |n|
         | 
| 460 | 
            +
                      affected_rows = n
         | 
| 461 | 
            +
                    end
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                    affected_rows
         | 
| 110 464 | 
             
                  end
         | 
| 111 | 
            -
                  
         | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 465 | 
            +
                  alias :exec_update :exec_delete
         | 
| 466 | 
            +
             | 
| 467 | 
            +
                  def begin_db_transaction #:nodoc:
         | 
| 468 | 
            +
                    exec_query "BEGIN"
         | 
| 469 | 
            +
                  rescue Mysql::Error
         | 
| 470 | 
            +
                    # Transactions aren't supported
         | 
| 114 471 | 
             
                  end
         | 
| 115 | 
            -
             | 
| 472 | 
            +
             | 
| 116 473 | 
             
                  private
         | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
                       | 
| 122 | 
            -
             | 
| 123 | 
            -
                       | 
| 474 | 
            +
             | 
| 475 | 
            +
                  def exec_stmt(sql, name, binds)
         | 
| 476 | 
            +
                    cache = {}
         | 
| 477 | 
            +
                    log(sql, name, binds) do
         | 
| 478 | 
            +
                      if binds.empty?
         | 
| 479 | 
            +
                        stmt = @connection.prepare(sql)
         | 
| 480 | 
            +
                      else
         | 
| 481 | 
            +
                        cache = @statements[sql] ||= {
         | 
| 482 | 
            +
                          :stmt => @connection.prepare(sql)
         | 
| 483 | 
            +
                        }
         | 
| 484 | 
            +
                        stmt = cache[:stmt]
         | 
| 485 | 
            +
                      end
         | 
| 486 | 
            +
             | 
| 487 | 
            +
                      begin
         | 
| 488 | 
            +
                        stmt.execute(*binds.map { |col, val| type_cast(val, col) })
         | 
| 489 | 
            +
                      rescue Mysql::Error => e
         | 
| 490 | 
            +
                        # Older versions of MySQL leave the prepared statement in a bad
         | 
| 491 | 
            +
                        # place when an error occurs. To support older mysql versions, we
         | 
| 492 | 
            +
                        # need to close the statement and delete the statement from the
         | 
| 493 | 
            +
                        # cache.
         | 
| 494 | 
            +
                        stmt.close
         | 
| 495 | 
            +
                        @statements.delete sql
         | 
| 496 | 
            +
                        raise e
         | 
| 497 | 
            +
                      end
         | 
| 498 | 
            +
             | 
| 499 | 
            +
                      cols = nil
         | 
| 500 | 
            +
                      if metadata = stmt.result_metadata
         | 
| 501 | 
            +
                        cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
         | 
| 502 | 
            +
                          field.name
         | 
| 503 | 
            +
                        }
         | 
| 504 | 
            +
                      end
         | 
| 505 | 
            +
             | 
| 506 | 
            +
                      result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
         | 
| 507 | 
            +
                      affected_rows = stmt.affected_rows
         | 
| 508 | 
            +
             | 
| 509 | 
            +
                      stmt.result_metadata.free if cols
         | 
| 510 | 
            +
                      stmt.free_result
         | 
| 511 | 
            +
                      stmt.close if binds.empty?
         | 
| 512 | 
            +
             | 
| 513 | 
            +
                      [result_set, affected_rows]
         | 
| 514 | 
            +
                    end
         | 
| 515 | 
            +
                  end
         | 
| 516 | 
            +
             | 
| 517 | 
            +
                  def connect
         | 
| 518 | 
            +
                    encoding = @config[:encoding]
         | 
| 519 | 
            +
                    if encoding
         | 
| 520 | 
            +
                      @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
         | 
| 521 | 
            +
                    end
         | 
| 522 | 
            +
             | 
| 523 | 
            +
                    if @config[:sslca] || @config[:sslkey]
         | 
| 524 | 
            +
                      @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher])
         | 
| 124 525 | 
             
                    end
         | 
| 526 | 
            +
             | 
| 527 | 
            +
                    @connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout]
         | 
| 528 | 
            +
                    @connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout]
         | 
| 529 | 
            +
                    @connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout]
         | 
| 530 | 
            +
             | 
| 531 | 
            +
                    @connection.real_connect(*@connection_options)
         | 
| 532 | 
            +
             | 
| 533 | 
            +
                    # reconnect must be set after real_connect is called, because real_connect sets it to false internally
         | 
| 534 | 
            +
                    @connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=)
         | 
| 535 | 
            +
             | 
| 536 | 
            +
                    configure_connection
         | 
| 537 | 
            +
                  end
         | 
| 538 | 
            +
             | 
| 539 | 
            +
                  # Many Rails applications monkey-patch a replacement of the configure_connection method
         | 
| 540 | 
            +
                  # and don't call 'super', so leave this here even though it looks superfluous.
         | 
| 541 | 
            +
                  def configure_connection
         | 
| 542 | 
            +
                    super
         | 
| 543 | 
            +
                  end
         | 
| 544 | 
            +
             | 
| 545 | 
            +
                  def select(sql, name = nil, binds = [])
         | 
| 546 | 
            +
                    @connection.query_with_result = true
         | 
| 547 | 
            +
                    rows = exec_query(sql, name, binds)
         | 
| 548 | 
            +
                    @connection.more_results && @connection.next_result    # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
         | 
| 549 | 
            +
                    rows
         | 
| 550 | 
            +
                  end
         | 
| 551 | 
            +
             | 
| 552 | 
            +
                  # Returns the version of the connected MySQL server.
         | 
| 553 | 
            +
                  def version
         | 
| 554 | 
            +
                    @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
         | 
| 555 | 
            +
                  end
         | 
| 125 556 | 
             
                end
         | 
| 126 557 | 
             
              end
         | 
| 127 558 | 
             
            end
         | 
| 128 | 
            -
             | 
| 129 | 
            -
            rescue LoadError
         | 
| 130 | 
            -
              # MySQL is not available, so neither should the adapter be
         | 
| 131 | 
            -
            end
         |