activerecord 5.0.7.2 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +829 -2015
- data/MIT-LICENSE +3 -1
- data/README.rdoc +11 -9
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record.rb +37 -29
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +30 -18
- data/lib/active_record/associations.rb +1714 -1596
- data/lib/active_record/associations/alias_tracker.rb +36 -42
- data/lib/active_record/associations/association.rb +143 -68
- data/lib/active_record/associations/association_scope.rb +98 -94
- data/lib/active_record/associations/belongs_to_association.rb +76 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +27 -28
- data/lib/active_record/associations/builder/belongs_to.rb +52 -60
- data/lib/active_record/associations/builder/collection_association.rb +12 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
- data/lib/active_record/associations/builder/has_many.rb +10 -2
- data/lib/active_record/associations/builder/has_one.rb +35 -2
- data/lib/active_record/associations/builder/singular_association.rb +5 -1
- data/lib/active_record/associations/collection_association.rb +104 -259
- data/lib/active_record/associations/collection_proxy.rb +169 -125
- data/lib/active_record/associations/foreign_association.rb +22 -0
- data/lib/active_record/associations/has_many_association.rb +46 -31
- data/lib/active_record/associations/has_many_through_association.rb +66 -46
- data/lib/active_record/associations/has_one_association.rb +71 -52
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +169 -180
- data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/preloader.rb +97 -104
- data/lib/active_record/associations/preloader/association.rb +109 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/attribute_assignment.rb +55 -60
- data/lib/active_record/attribute_methods.rb +111 -141
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
- data/lib/active_record/attribute_methods/dirty.rb +172 -112
- data/lib/active_record/attribute_methods/primary_key.rb +88 -91
- data/lib/active_record/attribute_methods/query.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +18 -50
- data/lib/active_record/attribute_methods/serialization.rb +38 -10
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
- data/lib/active_record/attribute_methods/write.rb +25 -32
- data/lib/active_record/attributes.rb +69 -31
- data/lib/active_record/autosave_association.rb +102 -66
- data/lib/active_record/base.rb +16 -25
- data/lib/active_record/callbacks.rb +202 -43
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -12
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
- data/lib/active_record/connection_adapters/column.rb +55 -13
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
- data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +287 -45
- data/lib/active_record/core.rb +385 -181
- data/lib/active_record/counter_cache.rb +60 -28
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -87
- data/lib/active_record/enum.rb +122 -47
- data/lib/active_record/errors.rb +153 -22
- data/lib/active_record/explain.rb +13 -8
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +20 -22
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +246 -507
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +168 -95
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +114 -25
- data/lib/active_record/internal_metadata.rb +30 -24
- data/lib/active_record/legacy_yaml_adapter.rb +11 -5
- data/lib/active_record/locking/optimistic.rb +81 -85
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +68 -31
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/migration.rb +439 -342
- data/lib/active_record/migration/command_recorder.rb +152 -98
- data/lib/active_record/migration/compatibility.rb +229 -60
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/model_schema.rb +230 -122
- data/lib/active_record/nested_attributes.rb +213 -203
- data/lib/active_record/no_touching.rb +11 -2
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +471 -97
- data/lib/active_record/query_cache.rb +23 -12
- data/lib/active_record/querying.rb +43 -25
- data/lib/active_record/railtie.rb +155 -43
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +507 -195
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +245 -269
- data/lib/active_record/relation.rb +475 -324
- data/lib/active_record/relation/batches.rb +125 -72
- data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
- data/lib/active_record/relation/calculations.rb +267 -171
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +238 -248
- data/lib/active_record/relation/from_clause.rb +7 -9
- data/lib/active_record/relation/merger.rb +95 -77
- data/lib/active_record/relation/predicate_builder.rb +109 -110
- data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +654 -374
- data/lib/active_record/relation/record_fetch_warning.rb +8 -6
- data/lib/active_record/relation/spawn_methods.rb +15 -14
- data/lib/active_record/relation/where_clause.rb +171 -109
- data/lib/active_record/result.rb +88 -51
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +73 -100
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +101 -69
- data/lib/active_record/schema_migration.rb +16 -12
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +39 -30
- data/lib/active_record/secure_token.rb +19 -9
- data/lib/active_record/serialization.rb +7 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +80 -29
- data/lib/active_record/store.rb +122 -42
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +51 -39
- data/lib/active_record/tasks/database_tasks.rb +332 -115
- data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
- data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +26 -24
- data/lib/active_record/transactions.rb +121 -184
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +29 -17
- data/lib/active_record/type/adapter_specific_registry.rb +44 -48
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +20 -9
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +12 -1
- data/lib/active_record/type/type_map.rb +14 -17
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/type_caster/connection.rb +17 -13
- data/lib/active_record/type_caster/map.rb +10 -6
- data/lib/active_record/validations.rb +8 -5
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +4 -3
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +52 -45
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +54 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +22 -3
- data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
- 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 → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +141 -57
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute_decorators.rb +0 -67
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/relation/where_clause_factory.rb +0 -38
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,35 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
4
|
+
# :stopdoc:
|
2
5
|
module ConnectionAdapters
|
3
|
-
|
4
|
-
|
6
|
+
module PostgreSQL
|
7
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
8
|
+
undef to_yaml if method_defined?(:to_yaml)
|
5
9
|
|
6
|
-
|
7
|
-
super(type_metadata)
|
8
|
-
@type_metadata = type_metadata
|
9
|
-
@oid = oid
|
10
|
-
@fmod = fmod
|
11
|
-
@array = /\[\]$/ === type_metadata.sql_type
|
12
|
-
end
|
10
|
+
include Deduplicable
|
13
11
|
|
14
|
-
|
15
|
-
super.gsub(/\[\]$/, "".freeze)
|
16
|
-
end
|
12
|
+
attr_reader :oid, :fmod
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
def initialize(type_metadata, oid: nil, fmod: nil)
|
15
|
+
super(type_metadata)
|
16
|
+
@oid = oid
|
17
|
+
@fmod = fmod
|
18
|
+
end
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
def ==(other)
|
21
|
+
other.is_a?(TypeMetadata) &&
|
22
|
+
__getobj__ == other.__getobj__ &&
|
23
|
+
oid == other.oid &&
|
24
|
+
fmod == other.fmod
|
25
|
+
end
|
26
|
+
alias eql? ==
|
27
27
|
|
28
|
-
|
28
|
+
def hash
|
29
|
+
TypeMetadata.hash ^
|
30
|
+
__getobj__.hash ^
|
31
|
+
oid.hash ^
|
32
|
+
fmod.hash
|
33
|
+
end
|
29
34
|
|
30
|
-
|
31
|
-
|
35
|
+
private
|
36
|
+
def deduplicated
|
37
|
+
__setobj__(__getobj__.deduplicate)
|
38
|
+
super
|
39
|
+
end
|
32
40
|
end
|
33
41
|
end
|
42
|
+
PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
|
34
43
|
end
|
35
44
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module PostgreSQL
|
@@ -35,6 +37,11 @@ module ActiveRecord
|
|
35
37
|
end
|
36
38
|
|
37
39
|
protected
|
40
|
+
def parts
|
41
|
+
@parts ||= [@schema, @identifier].compact
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
38
45
|
def unquote(part)
|
39
46
|
if part && part.start_with?('"')
|
40
47
|
part[1..-2]
|
@@ -42,10 +49,6 @@ module ActiveRecord
|
|
42
49
|
part
|
43
50
|
end
|
44
51
|
end
|
45
|
-
|
46
|
-
def parts
|
47
|
-
@parts ||= [@schema, @identifier].compact
|
48
|
-
end
|
49
52
|
end
|
50
53
|
|
51
54
|
module Utils # :nodoc:
|
@@ -53,7 +56,7 @@ module ActiveRecord
|
|
53
56
|
|
54
57
|
# Returns an instance of <tt>ActiveRecord::ConnectionAdapters::PostgreSQL::Name</tt>
|
55
58
|
# extracted from +string+.
|
56
|
-
# +schema+ is nil if not specified in +string+.
|
59
|
+
# +schema+ is +nil+ if not specified in +string+.
|
57
60
|
# +schema+ and +identifier+ exclude surrounding quotes (regardless of whether provided in +string+)
|
58
61
|
# +string+ supports the range of schema/table references understood by PostgreSQL, for example:
|
59
62
|
#
|
@@ -64,7 +67,7 @@ module ActiveRecord
|
|
64
67
|
# * <tt>"schema_name".table_name</tt>
|
65
68
|
# * <tt>"schema.name"."table name"</tt>
|
66
69
|
def extract_schema_qualified_name(string)
|
67
|
-
schema, table = string.scan(/[^"
|
70
|
+
schema, table = string.scan(/[^".]+|"[^"]*"/)
|
68
71
|
if table.nil?
|
69
72
|
table = schema
|
70
73
|
schema = nil
|
@@ -1,28 +1,29 @@
|
|
1
|
-
#
|
2
|
-
gem "pg", ">= 0.18", "< 2.0"
|
3
|
-
require 'pg'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
3
|
+
gem "pg", "~> 1.1"
|
4
|
+
require "pg"
|
5
|
+
|
6
|
+
require "active_support/core_ext/object/try"
|
5
7
|
require "active_record/connection_adapters/abstract_adapter"
|
8
|
+
require "active_record/connection_adapters/statement_pool"
|
6
9
|
require "active_record/connection_adapters/postgresql/column"
|
7
10
|
require "active_record/connection_adapters/postgresql/database_statements"
|
8
11
|
require "active_record/connection_adapters/postgresql/explain_pretty_printer"
|
9
12
|
require "active_record/connection_adapters/postgresql/oid"
|
10
13
|
require "active_record/connection_adapters/postgresql/quoting"
|
11
14
|
require "active_record/connection_adapters/postgresql/referential_integrity"
|
15
|
+
require "active_record/connection_adapters/postgresql/schema_creation"
|
12
16
|
require "active_record/connection_adapters/postgresql/schema_definitions"
|
13
17
|
require "active_record/connection_adapters/postgresql/schema_dumper"
|
14
18
|
require "active_record/connection_adapters/postgresql/schema_statements"
|
15
19
|
require "active_record/connection_adapters/postgresql/type_metadata"
|
16
20
|
require "active_record/connection_adapters/postgresql/utils"
|
17
|
-
require "active_record/connection_adapters/statement_pool"
|
18
21
|
|
19
22
|
module ActiveRecord
|
20
23
|
module ConnectionHandling # :nodoc:
|
21
24
|
# Establishes a connection to the database that's used by all Active Record objects
|
22
25
|
def postgresql_connection(config)
|
23
|
-
conn_params = config.symbolize_keys
|
24
|
-
|
25
|
-
conn_params.delete_if { |_, v| v.nil? }
|
26
|
+
conn_params = config.symbolize_keys.compact
|
26
27
|
|
27
28
|
# Map ActiveRecords param names to PGs.
|
28
29
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
@@ -32,14 +33,17 @@ module ActiveRecord
|
|
32
33
|
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
33
34
|
conn_params.slice!(*valid_conn_param_keys)
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
ConnectionAdapters::PostgreSQLAdapter.new(
|
37
|
+
ConnectionAdapters::PostgreSQLAdapter.new_client(conn_params),
|
38
|
+
logger,
|
39
|
+
conn_params,
|
40
|
+
config,
|
41
|
+
)
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
41
45
|
module ConnectionAdapters
|
42
|
-
# The PostgreSQL adapter works with the native C (https://
|
46
|
+
# The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
|
43
47
|
#
|
44
48
|
# Options:
|
45
49
|
#
|
@@ -61,19 +65,44 @@ module ActiveRecord
|
|
61
65
|
# defaults to true.
|
62
66
|
#
|
63
67
|
# Any further options are used as connection parameters to libpq. See
|
64
|
-
#
|
68
|
+
# https://www.postgresql.org/docs/current/static/libpq-connect.html for the
|
65
69
|
# list of parameters.
|
66
70
|
#
|
67
71
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
68
|
-
# See
|
72
|
+
# See https://www.postgresql.org/docs/current/static/libpq-envars.html .
|
69
73
|
class PostgreSQLAdapter < AbstractAdapter
|
70
|
-
ADAPTER_NAME =
|
74
|
+
ADAPTER_NAME = "PostgreSQL"
|
75
|
+
|
76
|
+
class << self
|
77
|
+
def new_client(conn_params)
|
78
|
+
PG.connect(conn_params)
|
79
|
+
rescue ::PG::Error => error
|
80
|
+
if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
|
81
|
+
raise ActiveRecord::NoDatabaseError
|
82
|
+
else
|
83
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# :singleton-method:
|
90
|
+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
91
|
+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
92
|
+
# but significantly increases the risk of data loss if the database
|
93
|
+
# crashes. As a result, this should not be used in production
|
94
|
+
# environments. If you would like all created tables to be unlogged in
|
95
|
+
# the test environment you can add the following line to your test.rb
|
96
|
+
# file:
|
97
|
+
#
|
98
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
99
|
+
class_attribute :create_unlogged_tables, default: false
|
71
100
|
|
72
101
|
NATIVE_DATABASE_TYPES = {
|
73
|
-
primary_key: "
|
102
|
+
primary_key: "bigserial primary key",
|
74
103
|
string: { name: "character varying" },
|
75
104
|
text: { name: "text" },
|
76
|
-
integer: { name: "integer" },
|
105
|
+
integer: { name: "integer", limit: 4 },
|
77
106
|
float: { name: "float" },
|
78
107
|
decimal: { name: "decimal" },
|
79
108
|
datetime: { name: "timestamp" },
|
@@ -108,6 +137,8 @@ module ActiveRecord
|
|
108
137
|
bit: { name: "bit" },
|
109
138
|
bit_varying: { name: "bit varying" },
|
110
139
|
money: { name: "money" },
|
140
|
+
interval: { name: "interval" },
|
141
|
+
oid: { name: "oid" },
|
111
142
|
}
|
112
143
|
|
113
144
|
OID = PostgreSQL::OID #:nodoc:
|
@@ -116,19 +147,8 @@ module ActiveRecord
|
|
116
147
|
include PostgreSQL::ReferentialIntegrity
|
117
148
|
include PostgreSQL::SchemaStatements
|
118
149
|
include PostgreSQL::DatabaseStatements
|
119
|
-
include PostgreSQL::ColumnDumper
|
120
150
|
|
121
|
-
def
|
122
|
-
PostgreSQL::SchemaCreation.new self
|
123
|
-
end
|
124
|
-
|
125
|
-
def arel_visitor # :nodoc:
|
126
|
-
Arel::Visitors::PostgreSQL.new(self)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns true, since this connection adapter supports prepared statement
|
130
|
-
# caching.
|
131
|
-
def supports_statement_cache?
|
151
|
+
def supports_bulk_alter?
|
132
152
|
true
|
133
153
|
end
|
134
154
|
|
@@ -136,6 +156,10 @@ module ActiveRecord
|
|
136
156
|
true
|
137
157
|
end
|
138
158
|
|
159
|
+
def supports_partitioned_indexes?
|
160
|
+
database_version >= 110_000
|
161
|
+
end
|
162
|
+
|
139
163
|
def supports_partial_index?
|
140
164
|
true
|
141
165
|
end
|
@@ -152,6 +176,14 @@ module ActiveRecord
|
|
152
176
|
true
|
153
177
|
end
|
154
178
|
|
179
|
+
def supports_check_constraints?
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
183
|
+
def supports_validate_constraints?
|
184
|
+
true
|
185
|
+
end
|
186
|
+
|
155
187
|
def supports_views?
|
156
188
|
true
|
157
189
|
end
|
@@ -161,7 +193,7 @@ module ActiveRecord
|
|
161
193
|
end
|
162
194
|
|
163
195
|
def supports_json?
|
164
|
-
|
196
|
+
true
|
165
197
|
end
|
166
198
|
|
167
199
|
def supports_comments?
|
@@ -172,11 +204,22 @@ module ActiveRecord
|
|
172
204
|
true
|
173
205
|
end
|
174
206
|
|
207
|
+
def supports_insert_returning?
|
208
|
+
true
|
209
|
+
end
|
210
|
+
|
211
|
+
def supports_insert_on_conflict?
|
212
|
+
database_version >= 90500
|
213
|
+
end
|
214
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
215
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
216
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
217
|
+
|
175
218
|
def index_algorithms
|
176
|
-
{ concurrently:
|
219
|
+
{ concurrently: "CONCURRENTLY" }
|
177
220
|
end
|
178
221
|
|
179
|
-
class StatementPool < ConnectionAdapters::StatementPool
|
222
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
180
223
|
def initialize(connection, max)
|
181
224
|
super(max)
|
182
225
|
@connection = connection
|
@@ -192,9 +235,9 @@ module ActiveRecord
|
|
192
235
|
end
|
193
236
|
|
194
237
|
private
|
195
|
-
|
196
238
|
def dealloc(key)
|
197
239
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
240
|
+
rescue PG::Error
|
198
241
|
end
|
199
242
|
|
200
243
|
def connection_active?
|
@@ -214,35 +257,27 @@ module ActiveRecord
|
|
214
257
|
@local_tz = nil
|
215
258
|
@max_identifier_length = nil
|
216
259
|
|
217
|
-
|
260
|
+
configure_connection
|
218
261
|
add_pg_encoders
|
219
|
-
@statements = StatementPool.new @connection,
|
220
|
-
self.class.type_cast_config_to_integer(config[:statement_limit])
|
221
|
-
|
222
|
-
if postgresql_version < 90100
|
223
|
-
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
|
224
|
-
end
|
225
|
-
|
226
262
|
add_pg_decoders
|
227
263
|
|
228
264
|
@type_map = Type::HashLookupTypeMap.new
|
229
|
-
initialize_type_map
|
230
|
-
@local_tz = execute(
|
265
|
+
initialize_type_map
|
266
|
+
@local_tz = execute("SHOW TIME ZONE", "SCHEMA").first["TimeZone"]
|
231
267
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
232
268
|
end
|
233
269
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
def truncate(table_name, name = nil)
|
240
|
-
exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
|
270
|
+
def self.database_exists?(config)
|
271
|
+
!!ActiveRecord::Base.postgresql_connection(config)
|
272
|
+
rescue ActiveRecord::NoDatabaseError
|
273
|
+
false
|
241
274
|
end
|
242
275
|
|
243
276
|
# Is this connection alive and ready for queries?
|
244
277
|
def active?
|
245
|
-
@
|
278
|
+
@lock.synchronize do
|
279
|
+
@connection.query "SELECT 1"
|
280
|
+
end
|
246
281
|
true
|
247
282
|
rescue PG::Error
|
248
283
|
false
|
@@ -250,44 +285,48 @@ module ActiveRecord
|
|
250
285
|
|
251
286
|
# Close then reopen the connection.
|
252
287
|
def reconnect!
|
253
|
-
|
254
|
-
|
255
|
-
|
288
|
+
@lock.synchronize do
|
289
|
+
super
|
290
|
+
@connection.reset
|
291
|
+
configure_connection
|
292
|
+
rescue PG::ConnectionBad
|
293
|
+
connect
|
294
|
+
end
|
256
295
|
end
|
257
296
|
|
258
297
|
def reset!
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
@connection.
|
298
|
+
@lock.synchronize do
|
299
|
+
clear_cache!
|
300
|
+
reset_transaction
|
301
|
+
unless @connection.transaction_status == ::PG::PQTRANS_IDLE
|
302
|
+
@connection.query "ROLLBACK"
|
303
|
+
end
|
304
|
+
@connection.query "DISCARD ALL"
|
305
|
+
configure_connection
|
263
306
|
end
|
264
|
-
@connection.query 'DISCARD ALL'
|
265
|
-
configure_connection
|
266
307
|
end
|
267
308
|
|
268
309
|
# Disconnects from the database if already connected. Otherwise, this
|
269
310
|
# method does nothing.
|
270
311
|
def disconnect!
|
312
|
+
@lock.synchronize do
|
313
|
+
super
|
314
|
+
@connection.close rescue nil
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def discard! # :nodoc:
|
271
319
|
super
|
272
|
-
@connection.
|
320
|
+
@connection.socket_io.reopen(IO::NULL) rescue nil
|
321
|
+
@connection = nil
|
273
322
|
end
|
274
323
|
|
275
324
|
def native_database_types #:nodoc:
|
276
325
|
NATIVE_DATABASE_TYPES
|
277
326
|
end
|
278
327
|
|
279
|
-
# Returns true, since this connection adapter supports migrations.
|
280
|
-
def supports_migrations?
|
281
|
-
true
|
282
|
-
end
|
283
|
-
|
284
|
-
# Does PostgreSQL support finding primary key on non-Active Record tables?
|
285
|
-
def supports_primary_key? #:nodoc:
|
286
|
-
true
|
287
|
-
end
|
288
|
-
|
289
328
|
def set_standard_conforming_strings
|
290
|
-
execute(
|
329
|
+
execute("SET standard_conforming_strings = on", "SCHEMA")
|
291
330
|
end
|
292
331
|
|
293
332
|
def supports_ddl_transactions?
|
@@ -306,27 +345,45 @@ module ActiveRecord
|
|
306
345
|
true
|
307
346
|
end
|
308
347
|
|
309
|
-
|
310
|
-
|
311
|
-
postgresql_version >= 90200
|
348
|
+
def supports_materialized_views?
|
349
|
+
true
|
312
350
|
end
|
313
351
|
|
314
|
-
def
|
315
|
-
|
352
|
+
def supports_foreign_tables?
|
353
|
+
true
|
354
|
+
end
|
355
|
+
|
356
|
+
def supports_pgcrypto_uuid?
|
357
|
+
database_version >= 90400
|
358
|
+
end
|
359
|
+
|
360
|
+
def supports_optimizer_hints?
|
361
|
+
unless defined?(@has_pg_hint_plan)
|
362
|
+
@has_pg_hint_plan = extension_available?("pg_hint_plan")
|
363
|
+
end
|
364
|
+
@has_pg_hint_plan
|
365
|
+
end
|
366
|
+
|
367
|
+
def supports_common_table_expressions?
|
368
|
+
true
|
369
|
+
end
|
370
|
+
|
371
|
+
def supports_lazy_transactions?
|
372
|
+
true
|
316
373
|
end
|
317
374
|
|
318
375
|
def get_advisory_lock(lock_id) # :nodoc:
|
319
376
|
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
320
|
-
raise(ArgumentError, "
|
377
|
+
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
|
321
378
|
end
|
322
|
-
|
379
|
+
query_value("SELECT pg_try_advisory_lock(#{lock_id})")
|
323
380
|
end
|
324
381
|
|
325
382
|
def release_advisory_lock(lock_id) # :nodoc:
|
326
383
|
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
327
|
-
raise(ArgumentError, "
|
384
|
+
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
|
328
385
|
end
|
329
|
-
|
386
|
+
query_value("SELECT pg_advisory_unlock(#{lock_id})")
|
330
387
|
end
|
331
388
|
|
332
389
|
def enable_extension(name)
|
@@ -341,150 +398,168 @@ module ActiveRecord
|
|
341
398
|
}
|
342
399
|
end
|
343
400
|
|
401
|
+
def extension_available?(name)
|
402
|
+
query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
403
|
+
end
|
404
|
+
|
344
405
|
def extension_enabled?(name)
|
345
|
-
|
346
|
-
res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
|
347
|
-
'SCHEMA'
|
348
|
-
res.cast_values.first
|
349
|
-
end
|
406
|
+
query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
350
407
|
end
|
351
408
|
|
352
409
|
def extensions
|
353
|
-
|
354
|
-
exec_query("SELECT extname from pg_extension", "SCHEMA").cast_values
|
355
|
-
else
|
356
|
-
super
|
357
|
-
end
|
410
|
+
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
|
358
411
|
end
|
359
412
|
|
360
413
|
# Returns the configured supported identifier length supported by PostgreSQL
|
361
414
|
def max_identifier_length
|
362
|
-
@max_identifier_length ||=
|
415
|
+
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
363
416
|
end
|
364
|
-
alias table_alias_length max_identifier_length
|
365
|
-
alias index_name_length max_identifier_length
|
366
417
|
|
367
418
|
# Set the authorized user for this session
|
368
419
|
def session_auth=(user)
|
369
420
|
clear_cache!
|
370
|
-
|
421
|
+
execute("SET SESSION AUTHORIZATION #{user}")
|
371
422
|
end
|
372
423
|
|
373
424
|
def use_insert_returning?
|
374
425
|
@use_insert_returning
|
375
426
|
end
|
376
427
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
def update_table_definition(table_name, base) #:nodoc:
|
382
|
-
PostgreSQL::Table.new(table_name, base)
|
428
|
+
# Returns the version of the connected PostgreSQL server.
|
429
|
+
def get_database_version # :nodoc:
|
430
|
+
@connection.server_version
|
383
431
|
end
|
432
|
+
alias :postgresql_version :database_version
|
384
433
|
|
385
|
-
def
|
386
|
-
|
387
|
-
super(oid)
|
434
|
+
def default_index_type?(index) # :nodoc:
|
435
|
+
index.using == :btree || super
|
388
436
|
end
|
389
437
|
|
390
|
-
def
|
391
|
-
|
392
|
-
end
|
438
|
+
def build_insert_sql(insert) # :nodoc:
|
439
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
393
440
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
441
|
+
if insert.skip_duplicates?
|
442
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
443
|
+
elsif insert.update_duplicates?
|
444
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
445
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
446
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
447
|
+
end
|
399
448
|
|
400
|
-
|
401
|
-
|
402
|
-
@connection.server_version
|
449
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
450
|
+
sql
|
403
451
|
end
|
404
452
|
|
405
|
-
|
453
|
+
def check_version # :nodoc:
|
454
|
+
if database_version < 90300
|
455
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
456
|
+
end
|
457
|
+
end
|
406
458
|
|
407
|
-
|
459
|
+
private
|
460
|
+
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
408
461
|
VALUE_LIMIT_VIOLATION = "22001"
|
462
|
+
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
463
|
+
NOT_NULL_VIOLATION = "23502"
|
409
464
|
FOREIGN_KEY_VIOLATION = "23503"
|
410
465
|
UNIQUE_VIOLATION = "23505"
|
466
|
+
SERIALIZATION_FAILURE = "40001"
|
467
|
+
DEADLOCK_DETECTED = "40P01"
|
468
|
+
DUPLICATE_DATABASE = "42P04"
|
469
|
+
LOCK_NOT_AVAILABLE = "55P03"
|
470
|
+
QUERY_CANCELED = "57014"
|
411
471
|
|
412
|
-
def translate_exception(exception, message)
|
472
|
+
def translate_exception(exception, message:, sql:, binds:)
|
413
473
|
return exception unless exception.respond_to?(:result)
|
414
474
|
|
415
475
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
476
|
+
when nil
|
477
|
+
if exception.message.match?(/connection is closed/i)
|
478
|
+
ConnectionNotEstablished.new(exception)
|
479
|
+
else
|
480
|
+
super
|
481
|
+
end
|
416
482
|
when UNIQUE_VIOLATION
|
417
|
-
RecordNotUnique.new(message)
|
483
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
418
484
|
when FOREIGN_KEY_VIOLATION
|
419
|
-
InvalidForeignKey.new(message)
|
485
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
420
486
|
when VALUE_LIMIT_VIOLATION
|
421
|
-
ValueTooLong.new(message)
|
487
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
488
|
+
when NUMERIC_VALUE_OUT_OF_RANGE
|
489
|
+
RangeError.new(message, sql: sql, binds: binds)
|
490
|
+
when NOT_NULL_VIOLATION
|
491
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
492
|
+
when SERIALIZATION_FAILURE
|
493
|
+
SerializationFailure.new(message, sql: sql, binds: binds)
|
494
|
+
when DEADLOCK_DETECTED
|
495
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
496
|
+
when DUPLICATE_DATABASE
|
497
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
498
|
+
when LOCK_NOT_AVAILABLE
|
499
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
500
|
+
when QUERY_CANCELED
|
501
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
422
502
|
else
|
423
503
|
super
|
424
504
|
end
|
425
505
|
end
|
426
506
|
|
427
|
-
|
428
|
-
|
429
|
-
def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
|
507
|
+
def get_oid_type(oid, fmod, column_name, sql_type = "")
|
430
508
|
if !type_map.key?(oid)
|
431
|
-
load_additional_types(
|
509
|
+
load_additional_types([oid])
|
432
510
|
end
|
433
511
|
|
434
512
|
type_map.fetch(oid, fmod, sql_type) {
|
435
513
|
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
|
436
|
-
Type
|
514
|
+
Type.default_value.tap do |cast_type|
|
437
515
|
type_map.register_type(oid, cast_type)
|
438
516
|
end
|
439
517
|
}
|
440
518
|
end
|
441
519
|
|
442
|
-
def initialize_type_map(m
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
m.
|
447
|
-
m.register_type
|
448
|
-
m.alias_type
|
449
|
-
m.register_type
|
450
|
-
register_class_with_limit m,
|
451
|
-
m.alias_type
|
452
|
-
m.alias_type
|
453
|
-
m.alias_type
|
454
|
-
m.register_type
|
455
|
-
register_class_with_limit m,
|
456
|
-
register_class_with_limit m,
|
457
|
-
m.alias_type
|
458
|
-
m.register_type
|
459
|
-
|
460
|
-
m.register_type
|
461
|
-
m.register_type
|
462
|
-
m.register_type
|
463
|
-
m.register_type
|
464
|
-
m.register_type
|
465
|
-
m.register_type
|
466
|
-
m.register_type
|
467
|
-
m.register_type
|
468
|
-
m.register_type
|
469
|
-
m.register_type
|
470
|
-
m.register_type
|
471
|
-
m.register_type
|
472
|
-
m.register_type
|
473
|
-
m.register_type
|
474
|
-
m.register_type
|
475
|
-
m.register_type
|
476
|
-
m.register_type
|
477
|
-
m.register_type
|
478
|
-
m.register_type
|
479
|
-
m.register_type
|
480
|
-
|
481
|
-
|
482
|
-
m
|
483
|
-
|
484
|
-
|
485
|
-
register_class_with_precision m, 'timestamp', OID::DateTime
|
486
|
-
|
487
|
-
m.register_type 'numeric' do |_, fmod, sql_type|
|
520
|
+
def initialize_type_map(m = type_map)
|
521
|
+
m.register_type "int2", Type::Integer.new(limit: 2)
|
522
|
+
m.register_type "int4", Type::Integer.new(limit: 4)
|
523
|
+
m.register_type "int8", Type::Integer.new(limit: 8)
|
524
|
+
m.register_type "oid", OID::Oid.new
|
525
|
+
m.register_type "float4", Type::Float.new
|
526
|
+
m.alias_type "float8", "float4"
|
527
|
+
m.register_type "text", Type::Text.new
|
528
|
+
register_class_with_limit m, "varchar", Type::String
|
529
|
+
m.alias_type "char", "varchar"
|
530
|
+
m.alias_type "name", "varchar"
|
531
|
+
m.alias_type "bpchar", "varchar"
|
532
|
+
m.register_type "bool", Type::Boolean.new
|
533
|
+
register_class_with_limit m, "bit", OID::Bit
|
534
|
+
register_class_with_limit m, "varbit", OID::BitVarying
|
535
|
+
m.alias_type "timestamptz", "timestamp"
|
536
|
+
m.register_type "date", OID::Date.new
|
537
|
+
|
538
|
+
m.register_type "money", OID::Money.new
|
539
|
+
m.register_type "bytea", OID::Bytea.new
|
540
|
+
m.register_type "point", OID::Point.new
|
541
|
+
m.register_type "hstore", OID::Hstore.new
|
542
|
+
m.register_type "json", Type::Json.new
|
543
|
+
m.register_type "jsonb", OID::Jsonb.new
|
544
|
+
m.register_type "cidr", OID::Cidr.new
|
545
|
+
m.register_type "inet", OID::Inet.new
|
546
|
+
m.register_type "uuid", OID::Uuid.new
|
547
|
+
m.register_type "xml", OID::Xml.new
|
548
|
+
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
549
|
+
m.register_type "macaddr", OID::Macaddr.new
|
550
|
+
m.register_type "citext", OID::SpecializedString.new(:citext)
|
551
|
+
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
552
|
+
m.register_type "line", OID::SpecializedString.new(:line)
|
553
|
+
m.register_type "lseg", OID::SpecializedString.new(:lseg)
|
554
|
+
m.register_type "box", OID::SpecializedString.new(:box)
|
555
|
+
m.register_type "path", OID::SpecializedString.new(:path)
|
556
|
+
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
557
|
+
m.register_type "circle", OID::SpecializedString.new(:circle)
|
558
|
+
|
559
|
+
register_class_with_precision m, "time", Type::Time
|
560
|
+
register_class_with_precision m, "timestamp", OID::DateTime
|
561
|
+
|
562
|
+
m.register_type "numeric" do |_, fmod, sql_type|
|
488
563
|
precision = extract_precision(sql_type)
|
489
564
|
scale = extract_scale(sql_type)
|
490
565
|
|
@@ -504,78 +579,65 @@ module ActiveRecord
|
|
504
579
|
end
|
505
580
|
end
|
506
581
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
def extract_limit(sql_type) # :nodoc:
|
511
|
-
case sql_type
|
512
|
-
when /^bigint/i, /^int8/i
|
513
|
-
8
|
514
|
-
when /^smallint/i
|
515
|
-
2
|
516
|
-
else
|
517
|
-
super
|
582
|
+
m.register_type "interval" do |*args, sql_type|
|
583
|
+
precision = extract_precision(sql_type)
|
584
|
+
OID::Interval.new(precision: precision)
|
518
585
|
end
|
586
|
+
|
587
|
+
load_additional_types
|
519
588
|
end
|
520
589
|
|
521
590
|
# Extracts the value from a PostgreSQL column default definition.
|
522
|
-
def extract_value_from_default(default)
|
591
|
+
def extract_value_from_default(default)
|
523
592
|
case default
|
524
593
|
# Quoted types
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
594
|
+
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
595
|
+
# The default 'now'::date is CURRENT_DATE
|
596
|
+
if $1 == "now" && $2 == "date"
|
597
|
+
nil
|
598
|
+
else
|
599
|
+
$1.gsub("''", "'")
|
600
|
+
end
|
532
601
|
# Boolean types
|
533
|
-
|
534
|
-
|
602
|
+
when "true", "false"
|
603
|
+
default
|
535
604
|
# Numeric types
|
536
|
-
|
537
|
-
|
605
|
+
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
606
|
+
$1
|
538
607
|
# Object identifier types
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
608
|
+
when /\A-?\d+\z/
|
609
|
+
$1
|
610
|
+
else
|
611
|
+
# Anything else is blank, some user type, or some function
|
612
|
+
# and we can't know the value of that, so return nil.
|
613
|
+
nil
|
545
614
|
end
|
546
615
|
end
|
547
616
|
|
548
|
-
def extract_default_function(default_value, default)
|
617
|
+
def extract_default_function(default_value, default)
|
549
618
|
default if has_default_function?(default_value, default)
|
550
619
|
end
|
551
620
|
|
552
|
-
def has_default_function?(default_value, default)
|
553
|
-
!default_value &&
|
621
|
+
def has_default_function?(default_value, default)
|
622
|
+
!default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
554
623
|
end
|
555
624
|
|
556
|
-
def load_additional_types(
|
625
|
+
def load_additional_types(oids = nil)
|
557
626
|
initializer = OID::TypeMapInitializer.new(type_map)
|
558
627
|
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
SQL
|
565
|
-
else
|
566
|
-
query = <<-SQL
|
567
|
-
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
|
568
|
-
FROM pg_type as t
|
569
|
-
SQL
|
570
|
-
end
|
628
|
+
query = <<~SQL
|
629
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
630
|
+
FROM pg_type as t
|
631
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
632
|
+
SQL
|
571
633
|
|
572
634
|
if oids
|
573
|
-
query += "WHERE t.oid
|
635
|
+
query += "WHERE t.oid IN (%s)" % oids.join(", ")
|
574
636
|
else
|
575
|
-
query += initializer.query_conditions_for_initial_load
|
637
|
+
query += initializer.query_conditions_for_initial_load
|
576
638
|
end
|
577
639
|
|
578
|
-
execute_and_clear(query,
|
640
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
579
641
|
initializer.run(records)
|
580
642
|
end
|
581
643
|
end
|
@@ -583,6 +645,10 @@ module ActiveRecord
|
|
583
645
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
584
646
|
|
585
647
|
def execute_and_clear(sql, name, binds, prepare: false)
|
648
|
+
if preventing_writes? && write_query?(sql)
|
649
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
650
|
+
end
|
651
|
+
|
586
652
|
if without_prepared_statement?(binds)
|
587
653
|
result = exec_no_cache(sql, name, [])
|
588
654
|
elsif !prepare
|
@@ -590,22 +656,42 @@ module ActiveRecord
|
|
590
656
|
else
|
591
657
|
result = exec_cache(sql, name, binds)
|
592
658
|
end
|
593
|
-
|
594
|
-
|
659
|
+
begin
|
660
|
+
ret = yield result
|
661
|
+
ensure
|
662
|
+
result.clear
|
663
|
+
end
|
595
664
|
ret
|
596
665
|
end
|
597
666
|
|
598
667
|
def exec_no_cache(sql, name, binds)
|
668
|
+
materialize_transactions
|
669
|
+
mark_transaction_written_if_write(sql)
|
670
|
+
|
671
|
+
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
672
|
+
# made since we established the connection
|
673
|
+
update_typemap_for_default_timezone
|
674
|
+
|
599
675
|
type_casted_binds = type_casted_binds(binds)
|
600
|
-
log(sql, name, binds, type_casted_binds)
|
676
|
+
log(sql, name, binds, type_casted_binds) do
|
677
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
678
|
+
@connection.exec_params(sql, type_casted_binds)
|
679
|
+
end
|
680
|
+
end
|
601
681
|
end
|
602
682
|
|
603
683
|
def exec_cache(sql, name, binds)
|
604
|
-
|
684
|
+
materialize_transactions
|
685
|
+
mark_transaction_written_if_write(sql)
|
686
|
+
update_typemap_for_default_timezone
|
687
|
+
|
688
|
+
stmt_key = prepare_statement(sql, binds)
|
605
689
|
type_casted_binds = type_casted_binds(binds)
|
606
690
|
|
607
691
|
log(sql, name, binds, type_casted_binds, stmt_key) do
|
608
|
-
|
692
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
693
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
694
|
+
end
|
609
695
|
end
|
610
696
|
rescue ActiveRecord::StatementInvalid => e
|
611
697
|
raise unless is_cached_plan_failure?(e)
|
@@ -615,8 +701,10 @@ module ActiveRecord
|
|
615
701
|
if in_transaction?
|
616
702
|
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
617
703
|
else
|
618
|
-
|
619
|
-
|
704
|
+
@lock.synchronize do
|
705
|
+
# outside of transactions we can simply flush this query and retry
|
706
|
+
@statements.delete sql_key(sql)
|
707
|
+
end
|
620
708
|
retry
|
621
709
|
end
|
622
710
|
end
|
@@ -629,12 +717,11 @@ module ActiveRecord
|
|
629
717
|
# ActiveRecord::PreparedStatementCacheExpired
|
630
718
|
#
|
631
719
|
# Check here for more details:
|
632
|
-
#
|
633
|
-
CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
|
720
|
+
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
634
721
|
def is_cached_plan_failure?(e)
|
635
722
|
pgerror = e.cause
|
636
|
-
|
637
|
-
|
723
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
724
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
638
725
|
rescue
|
639
726
|
false
|
640
727
|
end
|
@@ -651,33 +738,31 @@ module ActiveRecord
|
|
651
738
|
|
652
739
|
# Prepare the statement if it hasn't been prepared, return
|
653
740
|
# the statement key.
|
654
|
-
def prepare_statement(sql)
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
741
|
+
def prepare_statement(sql, binds)
|
742
|
+
@lock.synchronize do
|
743
|
+
sql_key = sql_key(sql)
|
744
|
+
unless @statements.key? sql_key
|
745
|
+
nextkey = @statements.next_key
|
746
|
+
begin
|
747
|
+
@connection.prepare nextkey, sql
|
748
|
+
rescue => e
|
749
|
+
raise translate_exception_class(e, sql, binds)
|
750
|
+
end
|
751
|
+
# Clear the queue
|
752
|
+
@connection.get_last_result
|
753
|
+
@statements[sql_key] = nextkey
|
662
754
|
end
|
663
|
-
|
664
|
-
@connection.get_last_result
|
665
|
-
@statements[sql_key] = nextkey
|
755
|
+
@statements[sql_key]
|
666
756
|
end
|
667
|
-
@statements[sql_key]
|
668
757
|
end
|
669
758
|
|
670
759
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
671
760
|
# connected server's characteristics.
|
672
761
|
def connect
|
673
|
-
@connection =
|
762
|
+
@connection = self.class.new_client(@connection_parameters)
|
674
763
|
configure_connection
|
675
|
-
|
676
|
-
|
677
|
-
raise ActiveRecord::NoDatabaseError
|
678
|
-
else
|
679
|
-
raise
|
680
|
-
end
|
764
|
+
add_pg_encoders
|
765
|
+
add_pg_decoders
|
681
766
|
end
|
682
767
|
|
683
768
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -686,39 +771,39 @@ module ActiveRecord
|
|
686
771
|
if @config[:encoding]
|
687
772
|
@connection.set_client_encoding(@config[:encoding])
|
688
773
|
end
|
689
|
-
self.client_min_messages = @config[:min_messages] ||
|
774
|
+
self.client_min_messages = @config[:min_messages] || "warning"
|
690
775
|
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
691
776
|
|
692
777
|
# Use standard-conforming strings so we don't have to do the E'...' dance.
|
693
778
|
set_standard_conforming_strings
|
694
779
|
|
780
|
+
variables = @config.fetch(:variables, {}).stringify_keys
|
781
|
+
|
695
782
|
# If using Active Record's time zone support configure the connection to return
|
696
783
|
# TIMESTAMP WITH ZONE types in UTC.
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
784
|
+
unless variables["timezone"]
|
785
|
+
if ActiveRecord::Base.default_timezone == :utc
|
786
|
+
variables["timezone"] = "UTC"
|
787
|
+
elsif @local_tz
|
788
|
+
variables["timezone"] = @local_tz
|
789
|
+
end
|
702
790
|
end
|
703
791
|
|
792
|
+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
793
|
+
execute("SET intervalstyle = iso_8601", "SCHEMA")
|
794
|
+
|
704
795
|
# SET statements from :variables config hash
|
705
|
-
#
|
706
|
-
variables = @config[:variables] || {}
|
796
|
+
# https://www.postgresql.org/docs/current/static/sql-set.html
|
707
797
|
variables.map do |k, v|
|
708
|
-
if v ==
|
798
|
+
if v == ":default" || v == :default
|
709
799
|
# Sets the value to the global or compile default
|
710
|
-
execute("SET SESSION #{k} TO DEFAULT",
|
800
|
+
execute("SET SESSION #{k} TO DEFAULT", "SCHEMA")
|
711
801
|
elsif !v.nil?
|
712
|
-
execute("SET SESSION #{k} TO #{quote(v)}",
|
802
|
+
execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA")
|
713
803
|
end
|
714
804
|
end
|
715
805
|
end
|
716
806
|
|
717
|
-
# Returns the current ID of a table's sequence.
|
718
|
-
def last_insert_id_result(sequence_name) # :nodoc:
|
719
|
-
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
|
720
|
-
end
|
721
|
-
|
722
807
|
# Returns the list of a table's column names, data types, and default values.
|
723
808
|
#
|
724
809
|
# The underlying query is roughly:
|
@@ -737,34 +822,38 @@ module ActiveRecord
|
|
737
822
|
# Query implementation notes:
|
738
823
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
739
824
|
# - ::regclass is a function that gives the id for a table name
|
740
|
-
def column_definitions(table_name)
|
741
|
-
query(
|
825
|
+
def column_definitions(table_name)
|
826
|
+
query(<<~SQL, "SCHEMA")
|
742
827
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
743
828
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
WHERE a.attrelid =
|
829
|
+
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
830
|
+
FROM pg_attribute a
|
831
|
+
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
832
|
+
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
833
|
+
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
834
|
+
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
750
835
|
AND a.attnum > 0 AND NOT a.attisdropped
|
751
836
|
ORDER BY a.attnum
|
752
|
-
|
837
|
+
SQL
|
753
838
|
end
|
754
839
|
|
755
|
-
def extract_table_ref_from_insert_sql(sql)
|
840
|
+
def extract_table_ref_from_insert_sql(sql)
|
756
841
|
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
757
842
|
$1.strip if $1
|
758
843
|
end
|
759
844
|
|
760
|
-
def
|
761
|
-
PostgreSQL
|
845
|
+
def arel_visitor
|
846
|
+
Arel::Visitors::PostgreSQL.new(self)
|
847
|
+
end
|
848
|
+
|
849
|
+
def build_statement_pool
|
850
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
762
851
|
end
|
763
852
|
|
764
853
|
def can_perform_case_insensitive_comparison_for?(column)
|
765
854
|
@case_insensitive_cache ||= {}
|
766
855
|
@case_insensitive_cache[column.sql_type] ||= begin
|
767
|
-
sql =
|
856
|
+
sql = <<~SQL
|
768
857
|
SELECT exists(
|
769
858
|
SELECT * FROM pg_proc
|
770
859
|
WHERE proname = 'lower'
|
@@ -776,7 +865,7 @@ module ActiveRecord
|
|
776
865
|
WHERE proname = 'lower'
|
777
866
|
AND castsource = #{quote column.sql_type}::regtype
|
778
867
|
)
|
779
|
-
|
868
|
+
SQL
|
780
869
|
execute_and_clear(sql, "SCHEMA", []) do |result|
|
781
870
|
result.getvalue(0, 0)
|
782
871
|
end
|
@@ -788,40 +877,75 @@ module ActiveRecord
|
|
788
877
|
map[Integer] = PG::TextEncoder::Integer.new
|
789
878
|
map[TrueClass] = PG::TextEncoder::Boolean.new
|
790
879
|
map[FalseClass] = PG::TextEncoder::Boolean.new
|
791
|
-
map[Float] = PG::TextEncoder::Float.new
|
792
880
|
@connection.type_map_for_queries = map
|
793
881
|
end
|
794
882
|
|
883
|
+
def update_typemap_for_default_timezone
|
884
|
+
if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
|
885
|
+
decoder_class = ActiveRecord::Base.default_timezone == :utc ?
|
886
|
+
PG::TextDecoder::TimestampUtc :
|
887
|
+
PG::TextDecoder::TimestampWithoutTimeZone
|
888
|
+
|
889
|
+
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
890
|
+
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
891
|
+
@default_timezone = ActiveRecord::Base.default_timezone
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
795
895
|
def add_pg_decoders
|
896
|
+
@default_timezone = nil
|
897
|
+
@timestamp_decoder = nil
|
898
|
+
|
796
899
|
coders_by_name = {
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
900
|
+
"int2" => PG::TextDecoder::Integer,
|
901
|
+
"int4" => PG::TextDecoder::Integer,
|
902
|
+
"int8" => PG::TextDecoder::Integer,
|
903
|
+
"oid" => PG::TextDecoder::Integer,
|
904
|
+
"float4" => PG::TextDecoder::Float,
|
905
|
+
"float8" => PG::TextDecoder::Float,
|
906
|
+
"numeric" => PG::TextDecoder::Numeric,
|
907
|
+
"bool" => PG::TextDecoder::Boolean,
|
908
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
909
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
804
910
|
}
|
911
|
+
|
805
912
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
806
|
-
query =
|
913
|
+
query = <<~SQL % known_coder_types.join(", ")
|
807
914
|
SELECT t.oid, t.typname
|
808
915
|
FROM pg_type as t
|
809
916
|
WHERE t.typname IN (%s)
|
810
917
|
SQL
|
811
918
|
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
812
919
|
result
|
813
|
-
.map { |row| construct_coder(row, coders_by_name[row[
|
920
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
814
921
|
.compact
|
815
922
|
end
|
816
923
|
|
817
924
|
map = PG::TypeMapByOid.new
|
818
925
|
coders.each { |coder| map.add_coder(coder) }
|
819
926
|
@connection.type_map_for_results = map
|
927
|
+
|
928
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
929
|
+
@type_map_for_results.default_type_map = map
|
930
|
+
@type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
|
931
|
+
@type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
|
932
|
+
|
933
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
934
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
935
|
+
update_typemap_for_default_timezone
|
820
936
|
end
|
821
937
|
|
822
938
|
def construct_coder(row, coder_class)
|
823
939
|
return unless coder_class
|
824
|
-
coder_class.new(oid: row[
|
940
|
+
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
941
|
+
end
|
942
|
+
|
943
|
+
class MoneyDecoder < PG::SimpleDecoder # :nodoc:
|
944
|
+
TYPE = OID::Money.new
|
945
|
+
|
946
|
+
def decode(value, tuple = nil, field = nil)
|
947
|
+
TYPE.deserialize(value)
|
948
|
+
end
|
825
949
|
end
|
826
950
|
|
827
951
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
@@ -830,16 +954,17 @@ module ActiveRecord
|
|
830
954
|
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
|
831
955
|
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
|
832
956
|
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
|
957
|
+
ActiveRecord::Type.register(:date, OID::Date, adapter: :postgresql)
|
833
958
|
ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
|
834
959
|
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
|
835
960
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
836
961
|
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
837
962
|
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
838
|
-
ActiveRecord::Type.register(:
|
963
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
839
964
|
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
840
965
|
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
841
|
-
ActiveRecord::Type.register(:point, OID::
|
842
|
-
ActiveRecord::Type.register(:legacy_point, OID::
|
966
|
+
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
|
967
|
+
ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql)
|
843
968
|
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
|
844
969
|
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
|
845
970
|
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
|