activerecord 6.0.0 → 7.2.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -25
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +5 -6
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +171 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
data/lib/active_record/result.rb
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
###
|
|
5
|
+
# = Active Record \Result
|
|
6
|
+
#
|
|
5
7
|
# This class encapsulates a result returned from calling
|
|
6
8
|
# {#exec_query}[rdoc-ref:ConnectionAdapters::DatabaseStatements#exec_query]
|
|
7
9
|
# on any database connection adapter. For example:
|
|
8
10
|
#
|
|
9
|
-
# result = ActiveRecord::Base.
|
|
11
|
+
# result = ActiveRecord::Base.lease_connection.exec_query('SELECT id, title, body FROM posts')
|
|
10
12
|
# result # => #<ActiveRecord::Result:0xdeadbeef>
|
|
11
13
|
#
|
|
12
14
|
# # Get the column names of the result:
|
|
@@ -36,11 +38,22 @@ module ActiveRecord
|
|
|
36
38
|
|
|
37
39
|
attr_reader :columns, :rows, :column_types
|
|
38
40
|
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
+
def self.empty(async: false) # :nodoc:
|
|
42
|
+
if async
|
|
43
|
+
EMPTY_ASYNC
|
|
44
|
+
else
|
|
45
|
+
EMPTY
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def initialize(columns, rows, column_types = nil)
|
|
50
|
+
# We freeze the strings to prevent them getting duped when
|
|
51
|
+
# used as keys in ActiveRecord::Base's @attributes hash
|
|
52
|
+
@columns = columns.each(&:-@).freeze
|
|
41
53
|
@rows = rows
|
|
42
54
|
@hash_rows = nil
|
|
43
|
-
@column_types = column_types
|
|
55
|
+
@column_types = column_types || EMPTY_HASH
|
|
56
|
+
@column_indexes = nil
|
|
44
57
|
end
|
|
45
58
|
|
|
46
59
|
# Returns true if this result set includes the column named +name+
|
|
@@ -57,25 +70,14 @@ module ActiveRecord
|
|
|
57
70
|
# row as parameter.
|
|
58
71
|
#
|
|
59
72
|
# Returns an +Enumerator+ if no block is given.
|
|
60
|
-
def each
|
|
73
|
+
def each(&block)
|
|
61
74
|
if block_given?
|
|
62
|
-
hash_rows.each
|
|
75
|
+
hash_rows.each(&block)
|
|
63
76
|
else
|
|
64
77
|
hash_rows.to_enum { @rows.size }
|
|
65
78
|
end
|
|
66
79
|
end
|
|
67
80
|
|
|
68
|
-
def to_hash
|
|
69
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
70
|
-
`ActiveRecord::Result#to_hash` has been renamed to `to_a`.
|
|
71
|
-
`to_hash` is deprecated and will be removed in Rails 6.1.
|
|
72
|
-
MSG
|
|
73
|
-
to_a
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
alias :map! :map
|
|
77
|
-
alias :collect! :map
|
|
78
|
-
|
|
79
81
|
# Returns true if there are no records, otherwise false.
|
|
80
82
|
def empty?
|
|
81
83
|
rows.empty?
|
|
@@ -92,31 +94,38 @@ module ActiveRecord
|
|
|
92
94
|
hash_rows[idx]
|
|
93
95
|
end
|
|
94
96
|
|
|
95
|
-
# Returns the
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return nil if @rows.empty?
|
|
99
|
-
Hash[@columns.zip(@rows.first)]
|
|
97
|
+
# Returns the last record from the rows collection.
|
|
98
|
+
def last(n = nil)
|
|
99
|
+
n ? hash_rows.last(n) : hash_rows.last
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
def result # :nodoc:
|
|
103
|
+
self
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def cancel # :nodoc:
|
|
107
|
+
self
|
|
107
108
|
end
|
|
108
109
|
|
|
109
110
|
def cast_values(type_overrides = {}) # :nodoc:
|
|
110
111
|
if columns.one?
|
|
111
112
|
# Separated to avoid allocating an array per row
|
|
112
113
|
|
|
113
|
-
type =
|
|
114
|
+
type = if type_overrides.is_a?(Array)
|
|
115
|
+
type_overrides.first
|
|
116
|
+
else
|
|
117
|
+
column_type(columns.first, 0, type_overrides)
|
|
118
|
+
end
|
|
114
119
|
|
|
115
120
|
rows.map do |(value)|
|
|
116
121
|
type.deserialize(value)
|
|
117
122
|
end
|
|
118
123
|
else
|
|
119
|
-
types =
|
|
124
|
+
types = if type_overrides.is_a?(Array)
|
|
125
|
+
type_overrides
|
|
126
|
+
else
|
|
127
|
+
columns.map.with_index { |name, i| column_type(name, i, type_overrides) }
|
|
128
|
+
end
|
|
120
129
|
|
|
121
130
|
rows.map do |values|
|
|
122
131
|
Array.new(values.size) { |i| types[i].deserialize(values[i]) }
|
|
@@ -125,44 +134,55 @@ module ActiveRecord
|
|
|
125
134
|
end
|
|
126
135
|
|
|
127
136
|
def initialize_copy(other)
|
|
128
|
-
@columns = columns
|
|
137
|
+
@columns = columns
|
|
129
138
|
@rows = rows.dup
|
|
130
139
|
@column_types = column_types.dup
|
|
131
140
|
@hash_rows = nil
|
|
132
141
|
end
|
|
133
142
|
|
|
134
|
-
|
|
143
|
+
def freeze # :nodoc:
|
|
144
|
+
hash_rows.freeze
|
|
145
|
+
super
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def column_indexes # :nodoc:
|
|
149
|
+
@column_indexes ||= begin
|
|
150
|
+
index = 0
|
|
151
|
+
hash = {}
|
|
152
|
+
length = columns.length
|
|
153
|
+
while index < length
|
|
154
|
+
hash[columns[index]] = index
|
|
155
|
+
index += 1
|
|
156
|
+
end
|
|
157
|
+
hash
|
|
158
|
+
end
|
|
159
|
+
end
|
|
135
160
|
|
|
136
|
-
|
|
161
|
+
private
|
|
162
|
+
def column_type(name, index, type_overrides)
|
|
137
163
|
type_overrides.fetch(name) do
|
|
138
|
-
column_types.fetch(
|
|
164
|
+
column_types.fetch(index) do
|
|
165
|
+
column_types.fetch(name, Type.default_value)
|
|
166
|
+
end
|
|
139
167
|
end
|
|
140
168
|
end
|
|
141
169
|
|
|
142
170
|
def hash_rows
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
length = columns.length
|
|
149
|
-
|
|
150
|
-
@rows.map { |row|
|
|
151
|
-
# In the past we used Hash[columns.zip(row)]
|
|
152
|
-
# though elegant, the verbose way is much more efficient
|
|
153
|
-
# both time and memory wise cause it avoids a big array allocation
|
|
154
|
-
# this method is called a lot and needs to be micro optimised
|
|
155
|
-
hash = {}
|
|
156
|
-
|
|
157
|
-
index = 0
|
|
158
|
-
while index < length
|
|
159
|
-
hash[columns[index]] = row[index]
|
|
160
|
-
index += 1
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
hash
|
|
164
|
-
}
|
|
165
|
-
end
|
|
171
|
+
# We use transform_values to rows.
|
|
172
|
+
# This is faster because we avoid any reallocs and avoid hashing entirely.
|
|
173
|
+
@hash_rows ||= @rows.map do |row|
|
|
174
|
+
column_indexes.transform_values { |index| row[index] }
|
|
175
|
+
end
|
|
166
176
|
end
|
|
177
|
+
|
|
178
|
+
empty_array = [].freeze
|
|
179
|
+
EMPTY_HASH = {}.freeze
|
|
180
|
+
private_constant :EMPTY_HASH
|
|
181
|
+
|
|
182
|
+
EMPTY = new(empty_array, empty_array, EMPTY_HASH).freeze
|
|
183
|
+
private_constant :EMPTY
|
|
184
|
+
|
|
185
|
+
EMPTY_ASYNC = FutureResult.wrap(EMPTY).freeze
|
|
186
|
+
private_constant :EMPTY_ASYNC
|
|
167
187
|
end
|
|
168
188
|
end
|
|
@@ -1,24 +1,82 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/per_thread_registry"
|
|
4
|
-
|
|
5
3
|
module ActiveRecord
|
|
6
4
|
# This is a thread locals registry for Active Record. For example:
|
|
7
5
|
#
|
|
8
|
-
# ActiveRecord::RuntimeRegistry.
|
|
9
|
-
#
|
|
10
|
-
# returns the connection handler local to the current thread.
|
|
6
|
+
# ActiveRecord::RuntimeRegistry.sql_runtime
|
|
11
7
|
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
# returns the connection handler local to the current unit of execution (either thread of fiber).
|
|
9
|
+
module RuntimeRegistry # :nodoc:
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
def sql_runtime
|
|
13
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] ||= 0.0
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def sql_runtime=(runtime)
|
|
17
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def async_sql_runtime
|
|
21
|
+
ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] ||= 0.0
|
|
22
|
+
end
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
def async_sql_runtime=(runtime)
|
|
25
|
+
ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] = runtime
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def queries_count
|
|
29
|
+
ActiveSupport::IsolatedExecutionState[:active_record_queries_count] ||= 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def queries_count=(count)
|
|
33
|
+
ActiveSupport::IsolatedExecutionState[:active_record_queries_count] = count
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def cached_queries_count
|
|
37
|
+
ActiveSupport::IsolatedExecutionState[:active_record_cached_queries_count] ||= 0
|
|
38
|
+
end
|
|
18
39
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
|
40
|
+
def cached_queries_count=(count)
|
|
41
|
+
ActiveSupport::IsolatedExecutionState[:active_record_cached_queries_count] = count
|
|
22
42
|
end
|
|
43
|
+
|
|
44
|
+
def reset
|
|
45
|
+
reset_runtimes
|
|
46
|
+
reset_queries_count
|
|
47
|
+
reset_cached_queries_count
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def reset_runtimes
|
|
51
|
+
rt, self.sql_runtime = sql_runtime, 0.0
|
|
52
|
+
self.async_sql_runtime = 0.0
|
|
53
|
+
rt
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def reset_queries_count
|
|
57
|
+
qc = queries_count
|
|
58
|
+
self.queries_count = 0
|
|
59
|
+
qc
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def reset_cached_queries_count
|
|
63
|
+
qc = cached_queries_count
|
|
64
|
+
self.cached_queries_count = 0
|
|
65
|
+
qc
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record") do |name, start, finish, id, payload|
|
|
71
|
+
unless ["SCHEMA", "TRANSACTION"].include?(payload[:name])
|
|
72
|
+
ActiveRecord::RuntimeRegistry.queries_count += 1
|
|
73
|
+
ActiveRecord::RuntimeRegistry.cached_queries_count += 1 if payload[:cached]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
runtime = (finish - start) * 1_000.0
|
|
77
|
+
|
|
78
|
+
if payload[:async]
|
|
79
|
+
ActiveRecord::RuntimeRegistry.async_sql_runtime += (runtime - payload[:lock_wait])
|
|
23
80
|
end
|
|
81
|
+
ActiveRecord::RuntimeRegistry.sql_runtime += runtime
|
|
24
82
|
end
|
|
@@ -5,8 +5,8 @@ module ActiveRecord
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
module ClassMethods
|
|
8
|
-
# Accepts an array
|
|
9
|
-
#
|
|
8
|
+
# Accepts an array of SQL conditions and sanitizes them into a valid
|
|
9
|
+
# SQL fragment for a WHERE clause.
|
|
10
10
|
#
|
|
11
11
|
# sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
|
|
12
12
|
# # => "name='foo''bar' and group_id=4"
|
|
@@ -17,8 +17,19 @@ module ActiveRecord
|
|
|
17
17
|
# sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
|
|
18
18
|
# # => "name='foo''bar' and group_id='4'"
|
|
19
19
|
#
|
|
20
|
+
# This method will NOT sanitize an SQL string since it won't contain
|
|
21
|
+
# any conditions in it and will return the string as is.
|
|
22
|
+
#
|
|
20
23
|
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
|
|
21
24
|
# # => "name='foo''bar' and group_id='4'"
|
|
25
|
+
#
|
|
26
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
|
27
|
+
# and will directly use the database adapter's +quote+ method.
|
|
28
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
|
29
|
+
# to prevent query manipulation attacks.
|
|
30
|
+
#
|
|
31
|
+
# sanitize_sql_for_conditions(["role = ?", 0])
|
|
32
|
+
# # => "role = '0'"
|
|
22
33
|
def sanitize_sql_for_conditions(condition)
|
|
23
34
|
return nil if condition.blank?
|
|
24
35
|
|
|
@@ -29,8 +40,8 @@ module ActiveRecord
|
|
|
29
40
|
end
|
|
30
41
|
alias :sanitize_sql :sanitize_sql_for_conditions
|
|
31
42
|
|
|
32
|
-
# Accepts an array
|
|
33
|
-
#
|
|
43
|
+
# Accepts an array or hash of SQL conditions and sanitizes them into
|
|
44
|
+
# a valid SQL fragment for a SET clause.
|
|
34
45
|
#
|
|
35
46
|
# sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
|
|
36
47
|
# # => "name=NULL and group_id=4"
|
|
@@ -41,8 +52,19 @@ module ActiveRecord
|
|
|
41
52
|
# Post.sanitize_sql_for_assignment({ name: nil, group_id: 4 })
|
|
42
53
|
# # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
|
|
43
54
|
#
|
|
55
|
+
# This method will NOT sanitize an SQL string since it won't contain
|
|
56
|
+
# any conditions in it and will return the string as is.
|
|
57
|
+
#
|
|
44
58
|
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
|
|
45
59
|
# # => "name=NULL and group_id='4'"
|
|
60
|
+
#
|
|
61
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
|
62
|
+
# and will directly use the database adapter's +quote+ method.
|
|
63
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
|
64
|
+
# to prevent query manipulation attacks.
|
|
65
|
+
#
|
|
66
|
+
# sanitize_sql_for_assignment(["role = ?", 0])
|
|
67
|
+
# # => "role = '0'"
|
|
46
68
|
def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
|
|
47
69
|
case assignments
|
|
48
70
|
when Array; sanitize_sql_array(assignments)
|
|
@@ -54,7 +76,7 @@ module ActiveRecord
|
|
|
54
76
|
# Accepts an array, or string of SQL conditions and sanitizes
|
|
55
77
|
# them into a valid SQL fragment for an ORDER clause.
|
|
56
78
|
#
|
|
57
|
-
# sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
|
|
79
|
+
# sanitize_sql_for_order([Arel.sql("field(id, ?)"), [1,3,2]])
|
|
58
80
|
# # => "field(id, 1,3,2)"
|
|
59
81
|
#
|
|
60
82
|
# sanitize_sql_for_order("id ASC")
|
|
@@ -63,11 +85,11 @@ module ActiveRecord
|
|
|
63
85
|
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
|
64
86
|
disallow_raw_sql!(
|
|
65
87
|
[condition.first],
|
|
66
|
-
permit:
|
|
88
|
+
permit: adapter_class.column_name_with_order_matcher
|
|
67
89
|
)
|
|
68
90
|
|
|
69
91
|
# Ensure we aren't dealing with a subclass of String that might
|
|
70
|
-
# override methods we use (
|
|
92
|
+
# override methods we use (e.g. Arel::Nodes::SqlLiteral).
|
|
71
93
|
if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
|
|
72
94
|
condition = [String.new(condition.first), *condition[1..-1]]
|
|
73
95
|
end
|
|
@@ -92,26 +114,32 @@ module ActiveRecord
|
|
|
92
114
|
end
|
|
93
115
|
|
|
94
116
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
|
95
|
-
# LIKE statement. This method uses +escape_character+ to escape all
|
|
117
|
+
# LIKE statement. This method uses +escape_character+ to escape all
|
|
118
|
+
# occurrences of itself, "_" and "%".
|
|
96
119
|
#
|
|
97
|
-
# sanitize_sql_like("100%")
|
|
98
|
-
# # => "100\\%"
|
|
120
|
+
# sanitize_sql_like("100% true!")
|
|
121
|
+
# # => "100\\% true!"
|
|
99
122
|
#
|
|
100
123
|
# sanitize_sql_like("snake_cased_string")
|
|
101
124
|
# # => "snake\\_cased\\_string"
|
|
102
125
|
#
|
|
103
|
-
# sanitize_sql_like("100%", "!")
|
|
104
|
-
# # => "100!%"
|
|
126
|
+
# sanitize_sql_like("100% true!", "!")
|
|
127
|
+
# # => "100!% true!!"
|
|
105
128
|
#
|
|
106
129
|
# sanitize_sql_like("snake_cased_string", "!")
|
|
107
130
|
# # => "snake!_cased!_string"
|
|
108
131
|
def sanitize_sql_like(string, escape_character = "\\")
|
|
109
|
-
|
|
110
|
-
|
|
132
|
+
if string.include?(escape_character) && escape_character != "%" && escape_character != "_"
|
|
133
|
+
string = string.gsub(escape_character, '\0\0')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
string.gsub(/(?=[%_])/, escape_character)
|
|
111
137
|
end
|
|
112
138
|
|
|
113
139
|
# Accepts an array of conditions. The array has each value
|
|
114
|
-
# sanitized and interpolated into the SQL statement.
|
|
140
|
+
# sanitized and interpolated into the SQL statement. If using named bind
|
|
141
|
+
# variables in SQL statements where a colon is required verbatim use a
|
|
142
|
+
# backslash to escape.
|
|
115
143
|
#
|
|
116
144
|
# sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
|
|
117
145
|
# # => "name='foo''bar' and group_id=4"
|
|
@@ -119,88 +147,99 @@ module ActiveRecord
|
|
|
119
147
|
# sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
|
120
148
|
# # => "name='foo''bar' and group_id=4"
|
|
121
149
|
#
|
|
150
|
+
# sanitize_sql_array(["TO_TIMESTAMP(:date, 'YYYY/MM/DD HH12\\:MI\\:SS')", date: "foo"])
|
|
151
|
+
# # => "TO_TIMESTAMP('foo', 'YYYY/MM/DD HH12:MI:SS')"
|
|
152
|
+
#
|
|
122
153
|
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
|
|
123
154
|
# # => "name='foo''bar' and group_id='4'"
|
|
155
|
+
#
|
|
156
|
+
# Note that this sanitization method is not schema-aware, hence won't do any type casting
|
|
157
|
+
# and will directly use the database adapter's +quote+ method.
|
|
158
|
+
# For MySQL specifically this means that numeric parameters will be quoted as strings
|
|
159
|
+
# to prevent query manipulation attacks.
|
|
160
|
+
#
|
|
161
|
+
# sanitize_sql_array(["role = ?", 0])
|
|
162
|
+
# # => "role = '0'"
|
|
124
163
|
def sanitize_sql_array(ary)
|
|
125
164
|
statement, *values = ary
|
|
126
165
|
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
|
127
|
-
|
|
166
|
+
with_connection do |c|
|
|
167
|
+
replace_named_bind_variables(c, statement, values.first)
|
|
168
|
+
end
|
|
128
169
|
elsif statement.include?("?")
|
|
129
|
-
|
|
170
|
+
with_connection do |c|
|
|
171
|
+
replace_bind_variables(c, statement, values)
|
|
172
|
+
end
|
|
130
173
|
elsif statement.blank?
|
|
131
174
|
statement
|
|
132
175
|
else
|
|
133
|
-
|
|
176
|
+
with_connection do |c|
|
|
177
|
+
statement % values.collect { |value| c.quote_string(value.to_s) }
|
|
178
|
+
end
|
|
134
179
|
end
|
|
135
180
|
end
|
|
136
181
|
|
|
137
|
-
def disallow_raw_sql!(args, permit:
|
|
182
|
+
def disallow_raw_sql!(args, permit: adapter_class.column_name_matcher) # :nodoc:
|
|
138
183
|
unexpected = nil
|
|
139
184
|
args.each do |arg|
|
|
140
|
-
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
|
|
185
|
+
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s.strip)
|
|
141
186
|
(unexpected ||= []) << arg
|
|
142
187
|
end
|
|
143
188
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if allow_unsafe_raw_sql == :deprecated
|
|
147
|
-
ActiveSupport::Deprecation.warn(
|
|
189
|
+
if unexpected
|
|
190
|
+
raise(ActiveRecord::UnknownAttributeReference,
|
|
148
191
|
"Dangerous query method (method whose arguments are used as raw " \
|
|
149
192
|
"SQL) called with non-attribute argument(s): " \
|
|
150
|
-
"#{unexpected.map(&:inspect).join(", ")}.
|
|
151
|
-
"
|
|
152
|
-
"not be called with user-provided values, such as request " \
|
|
193
|
+
"#{unexpected.map(&:inspect).join(", ")}." \
|
|
194
|
+
"This method should not be called with user-provided values, such as request " \
|
|
153
195
|
"parameters or model attributes. Known-safe values can be passed " \
|
|
154
196
|
"by wrapping them in Arel.sql()."
|
|
155
197
|
)
|
|
156
|
-
else
|
|
157
|
-
raise(ActiveRecord::UnknownAttributeReference,
|
|
158
|
-
"Query method called with non-attribute argument(s): " +
|
|
159
|
-
unexpected.map(&:inspect).join(", ")
|
|
160
|
-
)
|
|
161
198
|
end
|
|
162
199
|
end
|
|
163
200
|
|
|
164
201
|
private
|
|
165
|
-
def replace_bind_variables(statement, values)
|
|
202
|
+
def replace_bind_variables(connection, statement, values)
|
|
166
203
|
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
|
167
204
|
bound = values.dup
|
|
168
|
-
c = connection
|
|
169
205
|
statement.gsub(/\?/) do
|
|
170
|
-
replace_bind_variable(bound.shift
|
|
206
|
+
replace_bind_variable(connection, bound.shift)
|
|
171
207
|
end
|
|
172
208
|
end
|
|
173
209
|
|
|
174
|
-
def replace_bind_variable(
|
|
210
|
+
def replace_bind_variable(connection, value)
|
|
175
211
|
if ActiveRecord::Relation === value
|
|
176
212
|
value.to_sql
|
|
177
213
|
else
|
|
178
|
-
quote_bound_value(
|
|
214
|
+
quote_bound_value(connection, value)
|
|
179
215
|
end
|
|
180
216
|
end
|
|
181
217
|
|
|
182
|
-
def replace_named_bind_variables(statement, bind_vars)
|
|
183
|
-
statement.gsub(/(
|
|
184
|
-
if $1 == ":" # skip
|
|
218
|
+
def replace_named_bind_variables(connection, statement, bind_vars)
|
|
219
|
+
statement.gsub(/([:\\]?):([a-zA-Z]\w*)/) do |match|
|
|
220
|
+
if $1 == ":" # skip PostgreSQL casts
|
|
185
221
|
match # return the whole match
|
|
222
|
+
elsif $1 == "\\" # escaped literal colon
|
|
223
|
+
match[1..-1] # return match with escaping backlash char removed
|
|
186
224
|
elsif bind_vars.include?(match = $2.to_sym)
|
|
187
|
-
replace_bind_variable(bind_vars[match])
|
|
225
|
+
replace_bind_variable(connection, bind_vars[match])
|
|
188
226
|
else
|
|
189
227
|
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
|
190
228
|
end
|
|
191
229
|
end
|
|
192
230
|
end
|
|
193
231
|
|
|
194
|
-
def quote_bound_value(
|
|
232
|
+
def quote_bound_value(connection, value)
|
|
195
233
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
|
196
|
-
|
|
197
|
-
if
|
|
198
|
-
|
|
234
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
|
235
|
+
if values.empty?
|
|
236
|
+
connection.quote(connection.cast_bound_value(nil))
|
|
199
237
|
else
|
|
200
|
-
|
|
238
|
+
values.map! { |v| connection.quote(connection.cast_bound_value(v)) }.join(",")
|
|
201
239
|
end
|
|
202
240
|
else
|
|
203
|
-
|
|
241
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
|
242
|
+
connection.quote(connection.cast_bound_value(value))
|
|
204
243
|
end
|
|
205
244
|
end
|
|
206
245
|
|
data/lib/active_record/schema.rb
CHANGED
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
|
10
10
|
#
|
|
11
11
|
# Usage:
|
|
12
12
|
#
|
|
13
|
-
# ActiveRecord::Schema.define do
|
|
13
|
+
# ActiveRecord::Schema[7.0].define do
|
|
14
14
|
# create_table :authors do |t|
|
|
15
15
|
# t.string :name, null: false
|
|
16
16
|
# end
|
|
@@ -30,32 +30,48 @@ module ActiveRecord
|
|
|
30
30
|
# ActiveRecord::Schema is only supported by database adapters that also
|
|
31
31
|
# support migrations, the two features being very similar.
|
|
32
32
|
class Schema < Migration::Current
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
module Definition
|
|
34
|
+
extend ActiveSupport::Concern
|
|
35
|
+
|
|
36
|
+
module ClassMethods
|
|
37
|
+
# Eval the given block. All methods available to the current connection
|
|
38
|
+
# adapter are available within the block, so you can easily use the
|
|
39
|
+
# database definition DSL to build up your schema (
|
|
40
|
+
# {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
|
|
41
|
+
# {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
|
|
42
|
+
#
|
|
43
|
+
# The +info+ hash is optional, and if given is used to define metadata
|
|
44
|
+
# about the current schema (currently, only the schema's version):
|
|
45
|
+
#
|
|
46
|
+
# ActiveRecord::Schema[7.0].define(version: 2038_01_19_000001) do
|
|
47
|
+
# ...
|
|
48
|
+
# end
|
|
49
|
+
def define(info = {}, &block)
|
|
50
|
+
new.define(info, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def define(info, &block) # :nodoc:
|
|
55
|
+
connection_pool.with_connection do |connection|
|
|
56
|
+
instance_eval(&block)
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
connection_pool.schema_migration.create_table
|
|
59
|
+
if info[:version].present?
|
|
60
|
+
connection.assume_migrated_upto_version(info[:version])
|
|
61
|
+
end
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
connection.assume_migrated_upto_version(info[:version])
|
|
63
|
+
connection_pool.internal_metadata.create_table_and_set_flags(connection_pool.migration_context.current_environment)
|
|
64
|
+
end
|
|
55
65
|
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
include Definition
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
def self.[](version)
|
|
71
|
+
@class_for_version ||= {}
|
|
72
|
+
@class_for_version[version] ||= Class.new(Migration::Compatibility.find(version)) do
|
|
73
|
+
include Definition
|
|
74
|
+
end
|
|
59
75
|
end
|
|
60
76
|
end
|
|
61
77
|
end
|