activerecord 5.2.3 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +898 -532
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +10 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +27 -28
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +48 -35
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +76 -47
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +21 -17
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- 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 +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- 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 +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +175 -187
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +308 -100
- data/lib/active_record/counter_cache.rb +8 -30
- 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/database_configurations.rb +272 -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 +3 -4
- data/lib/active_record/enum.rb +71 -17
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- 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 +197 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +113 -101
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +487 -199
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +108 -58
- data/lib/active_record/relation.rb +375 -104
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +6 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +51 -8
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +59 -117
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- 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/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/nodes.rb +70 -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/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/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- 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 +10 -1
- metadata +117 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
| @@ -1,17 +1,9 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
            gem "pg", ">= 0.18", "< 2.0"
         | 
| 3 | 
            +
            gem "pg", "~> 1.1"
         | 
| 5 4 | 
             
            require "pg"
         | 
| 6 5 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
            class ::PG::Connection
         | 
| 9 | 
            -
              unless self.public_method_defined?(:async_exec_params)
         | 
| 10 | 
            -
                remove_method :exec_params
         | 
| 11 | 
            -
                alias exec_params async_exec
         | 
| 12 | 
            -
              end
         | 
| 13 | 
            -
            end
         | 
| 14 | 
            -
             | 
| 6 | 
            +
            require "active_support/core_ext/object/try"
         | 
| 15 7 | 
             
            require "active_record/connection_adapters/abstract_adapter"
         | 
| 16 8 | 
             
            require "active_record/connection_adapters/statement_pool"
         | 
| 17 9 | 
             
            require "active_record/connection_adapters/postgresql/column"
         | 
| @@ -31,9 +23,7 @@ module ActiveRecord | |
| 31 23 | 
             
              module ConnectionHandling # :nodoc:
         | 
| 32 24 | 
             
                # Establishes a connection to the database that's used by all Active Record objects
         | 
| 33 25 | 
             
                def postgresql_connection(config)
         | 
| 34 | 
            -
                  conn_params = config.symbolize_keys
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                  conn_params.delete_if { |_, v| v.nil? }
         | 
| 26 | 
            +
                  conn_params = config.symbolize_keys.compact
         | 
| 37 27 |  | 
| 38 28 | 
             
                  # Map ActiveRecords param names to PGs.
         | 
| 39 29 | 
             
                  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
         | 
| @@ -43,14 +33,17 @@ module ActiveRecord | |
| 43 33 | 
             
                  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
         | 
| 44 34 | 
             
                  conn_params.slice!(*valid_conn_param_keys)
         | 
| 45 35 |  | 
| 46 | 
            -
                   | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 36 | 
            +
                  ConnectionAdapters::PostgreSQLAdapter.new(
         | 
| 37 | 
            +
                    ConnectionAdapters::PostgreSQLAdapter.new_client(conn_params),
         | 
| 38 | 
            +
                    logger,
         | 
| 39 | 
            +
                    conn_params,
         | 
| 40 | 
            +
                    config,
         | 
| 41 | 
            +
                  )
         | 
| 49 42 | 
             
                end
         | 
| 50 43 | 
             
              end
         | 
| 51 44 |  | 
| 52 45 | 
             
              module ConnectionAdapters
         | 
| 53 | 
            -
                # 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.
         | 
| 54 47 | 
             
                #
         | 
| 55 48 | 
             
                # Options:
         | 
| 56 49 | 
             
                #
         | 
| @@ -78,7 +71,32 @@ module ActiveRecord | |
| 78 71 | 
             
                # In addition, default connection parameters of libpq can be set per environment variables.
         | 
| 79 72 | 
             
                # See https://www.postgresql.org/docs/current/static/libpq-envars.html .
         | 
| 80 73 | 
             
                class PostgreSQLAdapter < AbstractAdapter
         | 
| 81 | 
            -
                  ADAPTER_NAME = "PostgreSQL" | 
| 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
         | 
| 82 100 |  | 
| 83 101 | 
             
                  NATIVE_DATABASE_TYPES = {
         | 
| 84 102 | 
             
                    primary_key: "bigserial primary key",
         | 
| @@ -138,6 +156,10 @@ module ActiveRecord | |
| 138 156 | 
             
                    true
         | 
| 139 157 | 
             
                  end
         | 
| 140 158 |  | 
| 159 | 
            +
                  def supports_partitioned_indexes?
         | 
| 160 | 
            +
                    database_version >= 110_000
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 141 163 | 
             
                  def supports_partial_index?
         | 
| 142 164 | 
             
                    true
         | 
| 143 165 | 
             
                  end
         | 
| @@ -154,6 +176,10 @@ module ActiveRecord | |
| 154 176 | 
             
                    true
         | 
| 155 177 | 
             
                  end
         | 
| 156 178 |  | 
| 179 | 
            +
                  def supports_check_constraints?
         | 
| 180 | 
            +
                    true
         | 
| 181 | 
            +
                  end
         | 
| 182 | 
            +
             | 
| 157 183 | 
             
                  def supports_validate_constraints?
         | 
| 158 184 | 
             
                    true
         | 
| 159 185 | 
             
                  end
         | 
| @@ -167,7 +193,7 @@ module ActiveRecord | |
| 167 193 | 
             
                  end
         | 
| 168 194 |  | 
| 169 195 | 
             
                  def supports_json?
         | 
| 170 | 
            -
                     | 
| 196 | 
            +
                    true
         | 
| 171 197 | 
             
                  end
         | 
| 172 198 |  | 
| 173 199 | 
             
                  def supports_comments?
         | 
| @@ -178,6 +204,17 @@ module ActiveRecord | |
| 178 204 | 
             
                    true
         | 
| 179 205 | 
             
                  end
         | 
| 180 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 | 
            +
             | 
| 181 218 | 
             
                  def index_algorithms
         | 
| 182 219 | 
             
                    { concurrently: "CONCURRENTLY" }
         | 
| 183 220 | 
             
                  end
         | 
| @@ -220,15 +257,8 @@ module ActiveRecord | |
| 220 257 | 
             
                    @local_tz = nil
         | 
| 221 258 | 
             
                    @max_identifier_length = nil
         | 
| 222 259 |  | 
| 223 | 
            -
                     | 
| 260 | 
            +
                    configure_connection
         | 
| 224 261 | 
             
                    add_pg_encoders
         | 
| 225 | 
            -
                    @statements = StatementPool.new @connection,
         | 
| 226 | 
            -
                                                    self.class.type_cast_config_to_integer(config[:statement_limit])
         | 
| 227 | 
            -
             | 
| 228 | 
            -
                    if postgresql_version < 90100
         | 
| 229 | 
            -
                      raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
         | 
| 230 | 
            -
                    end
         | 
| 231 | 
            -
             | 
| 232 262 | 
             
                    add_pg_decoders
         | 
| 233 263 |  | 
| 234 264 | 
             
                    @type_map = Type::HashLookupTypeMap.new
         | 
| @@ -237,15 +267,10 @@ module ActiveRecord | |
| 237 267 | 
             
                    @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
         | 
| 238 268 | 
             
                  end
         | 
| 239 269 |  | 
| 240 | 
            -
                   | 
| 241 | 
            -
             | 
| 242 | 
            -
             | 
| 243 | 
            -
             | 
| 244 | 
            -
                    end
         | 
| 245 | 
            -
                  end
         | 
| 246 | 
            -
             | 
| 247 | 
            -
                  def truncate(table_name, name = nil)
         | 
| 248 | 
            -
                    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
         | 
| 249 274 | 
             
                  end
         | 
| 250 275 |  | 
| 251 276 | 
             
                  # Is this connection alive and ready for queries?
         | 
| @@ -264,6 +289,8 @@ module ActiveRecord | |
| 264 289 | 
             
                      super
         | 
| 265 290 | 
             
                      @connection.reset
         | 
| 266 291 | 
             
                      configure_connection
         | 
| 292 | 
            +
                    rescue PG::ConnectionBad
         | 
| 293 | 
            +
                      connect
         | 
| 267 294 | 
             
                    end
         | 
| 268 295 | 
             
                  end
         | 
| 269 296 |  | 
| @@ -289,6 +316,7 @@ module ActiveRecord | |
| 289 316 | 
             
                  end
         | 
| 290 317 |  | 
| 291 318 | 
             
                  def discard! # :nodoc:
         | 
| 319 | 
            +
                    super
         | 
| 292 320 | 
             
                    @connection.socket_io.reopen(IO::NULL) rescue nil
         | 
| 293 321 | 
             
                    @connection = nil
         | 
| 294 322 | 
             
                  end
         | 
| @@ -317,21 +345,31 @@ module ActiveRecord | |
| 317 345 | 
             
                    true
         | 
| 318 346 | 
             
                  end
         | 
| 319 347 |  | 
| 320 | 
            -
                  def supports_ranges?
         | 
| 321 | 
            -
                    # Range datatypes weren't introduced until PostgreSQL 9.2
         | 
| 322 | 
            -
                    postgresql_version >= 90200
         | 
| 323 | 
            -
                  end
         | 
| 324 | 
            -
             | 
| 325 348 | 
             
                  def supports_materialized_views?
         | 
| 326 | 
            -
                     | 
| 349 | 
            +
                    true
         | 
| 327 350 | 
             
                  end
         | 
| 328 351 |  | 
| 329 352 | 
             
                  def supports_foreign_tables?
         | 
| 330 | 
            -
                     | 
| 353 | 
            +
                    true
         | 
| 331 354 | 
             
                  end
         | 
| 332 355 |  | 
| 333 356 | 
             
                  def supports_pgcrypto_uuid?
         | 
| 334 | 
            -
                     | 
| 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
         | 
| 335 373 | 
             
                  end
         | 
| 336 374 |  | 
| 337 375 | 
             
                  def get_advisory_lock(lock_id) # :nodoc:
         | 
| @@ -360,9 +398,12 @@ module ActiveRecord | |
| 360 398 | 
             
                    }
         | 
| 361 399 | 
             
                  end
         | 
| 362 400 |  | 
| 401 | 
            +
                  def extension_available?(name)
         | 
| 402 | 
            +
                    query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
         | 
| 403 | 
            +
                  end
         | 
| 404 | 
            +
             | 
| 363 405 | 
             
                  def extension_enabled?(name)
         | 
| 364 | 
            -
                     | 
| 365 | 
            -
                    res.cast_values.first
         | 
| 406 | 
            +
                    query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
         | 
| 366 407 | 
             
                  end
         | 
| 367 408 |  | 
| 368 409 | 
             
                  def extensions
         | 
| @@ -373,8 +414,6 @@ module ActiveRecord | |
| 373 414 | 
             
                  def max_identifier_length
         | 
| 374 415 | 
             
                    @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
         | 
| 375 416 | 
             
                  end
         | 
| 376 | 
            -
                  alias table_alias_length max_identifier_length
         | 
| 377 | 
            -
                  alias index_name_length max_identifier_length
         | 
| 378 417 |  | 
| 379 418 | 
             
                  # Set the authorized user for this session
         | 
| 380 419 | 
             
                  def session_auth=(user)
         | 
| @@ -386,25 +425,37 @@ module ActiveRecord | |
| 386 425 | 
             
                    @use_insert_returning
         | 
| 387 426 | 
             
                  end
         | 
| 388 427 |  | 
| 389 | 
            -
                  def column_name_for_operation(operation, node) # :nodoc:
         | 
| 390 | 
            -
                    OPERATION_ALIASES.fetch(operation) { operation.downcase }
         | 
| 391 | 
            -
                  end
         | 
| 392 | 
            -
             | 
| 393 | 
            -
                  OPERATION_ALIASES = { # :nodoc:
         | 
| 394 | 
            -
                    "maximum" => "max",
         | 
| 395 | 
            -
                    "minimum" => "min",
         | 
| 396 | 
            -
                    "average" => "avg",
         | 
| 397 | 
            -
                  }
         | 
| 398 | 
            -
             | 
| 399 428 | 
             
                  # Returns the version of the connected PostgreSQL server.
         | 
| 400 | 
            -
                  def  | 
| 429 | 
            +
                  def get_database_version # :nodoc:
         | 
| 401 430 | 
             
                    @connection.server_version
         | 
| 402 431 | 
             
                  end
         | 
| 432 | 
            +
                  alias :postgresql_version :database_version
         | 
| 403 433 |  | 
| 404 434 | 
             
                  def default_index_type?(index) # :nodoc:
         | 
| 405 435 | 
             
                    index.using == :btree || super
         | 
| 406 436 | 
             
                  end
         | 
| 407 437 |  | 
| 438 | 
            +
                  def build_insert_sql(insert) # :nodoc:
         | 
| 439 | 
            +
                    sql = +"INSERT #{insert.into} #{insert.values_list}"
         | 
| 440 | 
            +
             | 
| 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
         | 
| 448 | 
            +
             | 
| 449 | 
            +
                    sql << " RETURNING #{insert.returning}" if insert.returning
         | 
| 450 | 
            +
                    sql
         | 
| 451 | 
            +
                  end
         | 
| 452 | 
            +
             | 
| 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
         | 
| 458 | 
            +
             | 
| 408 459 | 
             
                  private
         | 
| 409 460 | 
             
                    # See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
         | 
| 410 461 | 
             
                    VALUE_LIMIT_VIOLATION = "22001"
         | 
| @@ -414,37 +465,46 @@ module ActiveRecord | |
| 414 465 | 
             
                    UNIQUE_VIOLATION      = "23505"
         | 
| 415 466 | 
             
                    SERIALIZATION_FAILURE = "40001"
         | 
| 416 467 | 
             
                    DEADLOCK_DETECTED     = "40P01"
         | 
| 468 | 
            +
                    DUPLICATE_DATABASE    = "42P04"
         | 
| 417 469 | 
             
                    LOCK_NOT_AVAILABLE    = "55P03"
         | 
| 418 470 | 
             
                    QUERY_CANCELED        = "57014"
         | 
| 419 471 |  | 
| 420 | 
            -
                    def translate_exception(exception, message)
         | 
| 472 | 
            +
                    def translate_exception(exception, message:, sql:, binds:)
         | 
| 421 473 | 
             
                      return exception unless exception.respond_to?(:result)
         | 
| 422 474 |  | 
| 423 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
         | 
| 424 482 | 
             
                      when UNIQUE_VIOLATION
         | 
| 425 | 
            -
                        RecordNotUnique.new(message)
         | 
| 483 | 
            +
                        RecordNotUnique.new(message, sql: sql, binds: binds)
         | 
| 426 484 | 
             
                      when FOREIGN_KEY_VIOLATION
         | 
| 427 | 
            -
                        InvalidForeignKey.new(message)
         | 
| 485 | 
            +
                        InvalidForeignKey.new(message, sql: sql, binds: binds)
         | 
| 428 486 | 
             
                      when VALUE_LIMIT_VIOLATION
         | 
| 429 | 
            -
                        ValueTooLong.new(message)
         | 
| 487 | 
            +
                        ValueTooLong.new(message, sql: sql, binds: binds)
         | 
| 430 488 | 
             
                      when NUMERIC_VALUE_OUT_OF_RANGE
         | 
| 431 | 
            -
                        RangeError.new(message)
         | 
| 489 | 
            +
                        RangeError.new(message, sql: sql, binds: binds)
         | 
| 432 490 | 
             
                      when NOT_NULL_VIOLATION
         | 
| 433 | 
            -
                        NotNullViolation.new(message)
         | 
| 491 | 
            +
                        NotNullViolation.new(message, sql: sql, binds: binds)
         | 
| 434 492 | 
             
                      when SERIALIZATION_FAILURE
         | 
| 435 | 
            -
                        SerializationFailure.new(message)
         | 
| 493 | 
            +
                        SerializationFailure.new(message, sql: sql, binds: binds)
         | 
| 436 494 | 
             
                      when DEADLOCK_DETECTED
         | 
| 437 | 
            -
                        Deadlocked.new(message)
         | 
| 495 | 
            +
                        Deadlocked.new(message, sql: sql, binds: binds)
         | 
| 496 | 
            +
                      when DUPLICATE_DATABASE
         | 
| 497 | 
            +
                        DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
         | 
| 438 498 | 
             
                      when LOCK_NOT_AVAILABLE
         | 
| 439 | 
            -
                        LockWaitTimeout.new(message)
         | 
| 499 | 
            +
                        LockWaitTimeout.new(message, sql: sql, binds: binds)
         | 
| 440 500 | 
             
                      when QUERY_CANCELED
         | 
| 441 | 
            -
                        QueryCanceled.new(message)
         | 
| 501 | 
            +
                        QueryCanceled.new(message, sql: sql, binds: binds)
         | 
| 442 502 | 
             
                      else
         | 
| 443 503 | 
             
                        super
         | 
| 444 504 | 
             
                      end
         | 
| 445 505 | 
             
                    end
         | 
| 446 506 |  | 
| 447 | 
            -
                    def get_oid_type(oid, fmod, column_name, sql_type = "" | 
| 507 | 
            +
                    def get_oid_type(oid, fmod, column_name, sql_type = "")
         | 
| 448 508 | 
             
                      if !type_map.key?(oid)
         | 
| 449 509 | 
             
                        load_additional_types([oid])
         | 
| 450 510 | 
             
                      end
         | 
| @@ -486,7 +546,7 @@ module ActiveRecord | |
| 486 546 | 
             
                      m.register_type "uuid", OID::Uuid.new
         | 
| 487 547 | 
             
                      m.register_type "xml", OID::Xml.new
         | 
| 488 548 | 
             
                      m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
         | 
| 489 | 
            -
                      m.register_type "macaddr", OID:: | 
| 549 | 
            +
                      m.register_type "macaddr", OID::Macaddr.new
         | 
| 490 550 | 
             
                      m.register_type "citext", OID::SpecializedString.new(:citext)
         | 
| 491 551 | 
             
                      m.register_type "ltree", OID::SpecializedString.new(:ltree)
         | 
| 492 552 | 
             
                      m.register_type "line", OID::SpecializedString.new(:line)
         | 
| @@ -496,11 +556,6 @@ module ActiveRecord | |
| 496 556 | 
             
                      m.register_type "polygon", OID::SpecializedString.new(:polygon)
         | 
| 497 557 | 
             
                      m.register_type "circle", OID::SpecializedString.new(:circle)
         | 
| 498 558 |  | 
| 499 | 
            -
                      m.register_type "interval" do |_, _, sql_type|
         | 
| 500 | 
            -
                        precision = extract_precision(sql_type)
         | 
| 501 | 
            -
                        OID::SpecializedString.new(:interval, precision: precision)
         | 
| 502 | 
            -
                      end
         | 
| 503 | 
            -
             | 
| 504 559 | 
             
                      register_class_with_precision m, "time", Type::Time
         | 
| 505 560 | 
             
                      register_class_with_precision m, "timestamp", OID::DateTime
         | 
| 506 561 |  | 
| @@ -524,6 +579,11 @@ module ActiveRecord | |
| 524 579 | 
             
                        end
         | 
| 525 580 | 
             
                      end
         | 
| 526 581 |  | 
| 582 | 
            +
                      m.register_type "interval" do |*args, sql_type|
         | 
| 583 | 
            +
                        precision = extract_precision(sql_type)
         | 
| 584 | 
            +
                        OID::Interval.new(precision: precision)
         | 
| 585 | 
            +
                      end
         | 
| 586 | 
            +
             | 
| 527 587 | 
             
                      load_additional_types
         | 
| 528 588 | 
             
                    end
         | 
| 529 589 |  | 
| @@ -533,13 +593,13 @@ module ActiveRecord | |
| 533 593 | 
             
                        # Quoted types
         | 
| 534 594 | 
             
                      when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
         | 
| 535 595 | 
             
                        # The default 'now'::date is CURRENT_DATE
         | 
| 536 | 
            -
                        if $1 == "now" | 
| 596 | 
            +
                        if $1 == "now" && $2 == "date"
         | 
| 537 597 | 
             
                          nil
         | 
| 538 598 | 
             
                        else
         | 
| 539 | 
            -
                          $1.gsub("''" | 
| 599 | 
            +
                          $1.gsub("''", "'")
         | 
| 540 600 | 
             
                        end
         | 
| 541 601 | 
             
                        # Boolean types
         | 
| 542 | 
            -
                      when "true" | 
| 602 | 
            +
                      when "true", "false"
         | 
| 543 603 | 
             
                        default
         | 
| 544 604 | 
             
                        # Numeric types
         | 
| 545 605 | 
             
                      when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
         | 
| @@ -565,21 +625,14 @@ module ActiveRecord | |
| 565 625 | 
             
                    def load_additional_types(oids = nil)
         | 
| 566 626 | 
             
                      initializer = OID::TypeMapInitializer.new(type_map)
         | 
| 567 627 |  | 
| 568 | 
            -
                       | 
| 569 | 
            -
                         | 
| 570 | 
            -
             | 
| 571 | 
            -
             | 
| 572 | 
            -
             | 
| 573 | 
            -
                        SQL
         | 
| 574 | 
            -
                      else
         | 
| 575 | 
            -
                        query = <<-SQL
         | 
| 576 | 
            -
                          SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
         | 
| 577 | 
            -
                          FROM pg_type as t
         | 
| 578 | 
            -
                        SQL
         | 
| 579 | 
            -
                      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
         | 
| 580 633 |  | 
| 581 634 | 
             
                      if oids
         | 
| 582 | 
            -
                        query += "WHERE t.oid | 
| 635 | 
            +
                        query += "WHERE t.oid IN (%s)" % oids.join(", ")
         | 
| 583 636 | 
             
                      else
         | 
| 584 637 | 
             
                        query += initializer.query_conditions_for_initial_load
         | 
| 585 638 | 
             
                      end
         | 
| @@ -592,6 +645,10 @@ module ActiveRecord | |
| 592 645 | 
             
                    FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
         | 
| 593 646 |  | 
| 594 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 | 
            +
             | 
| 595 652 | 
             
                      if without_prepared_statement?(binds)
         | 
| 596 653 | 
             
                        result = exec_no_cache(sql, name, [])
         | 
| 597 654 | 
             
                      elsif !prepare
         | 
| @@ -599,12 +656,22 @@ module ActiveRecord | |
| 599 656 | 
             
                      else
         | 
| 600 657 | 
             
                        result = exec_cache(sql, name, binds)
         | 
| 601 658 | 
             
                      end
         | 
| 602 | 
            -
                       | 
| 603 | 
            -
             | 
| 659 | 
            +
                      begin
         | 
| 660 | 
            +
                        ret = yield result
         | 
| 661 | 
            +
                      ensure
         | 
| 662 | 
            +
                        result.clear
         | 
| 663 | 
            +
                      end
         | 
| 604 664 | 
             
                      ret
         | 
| 605 665 | 
             
                    end
         | 
| 606 666 |  | 
| 607 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 | 
            +
             | 
| 608 675 | 
             
                      type_casted_binds = type_casted_binds(binds)
         | 
| 609 676 | 
             
                      log(sql, name, binds, type_casted_binds) do
         | 
| 610 677 | 
             
                        ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
         | 
| @@ -614,7 +681,11 @@ module ActiveRecord | |
| 614 681 | 
             
                    end
         | 
| 615 682 |  | 
| 616 683 | 
             
                    def exec_cache(sql, name, binds)
         | 
| 617 | 
            -
                       | 
| 684 | 
            +
                      materialize_transactions
         | 
| 685 | 
            +
                      mark_transaction_written_if_write(sql)
         | 
| 686 | 
            +
                      update_typemap_for_default_timezone
         | 
| 687 | 
            +
             | 
| 688 | 
            +
                      stmt_key = prepare_statement(sql, binds)
         | 
| 618 689 | 
             
                      type_casted_binds = type_casted_binds(binds)
         | 
| 619 690 |  | 
| 620 691 | 
             
                      log(sql, name, binds, type_casted_binds, stmt_key) do
         | 
| @@ -647,11 +718,10 @@ module ActiveRecord | |
| 647 718 | 
             
                    #
         | 
| 648 719 | 
             
                    # Check here for more details:
         | 
| 649 720 | 
             
                    # https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
         | 
| 650 | 
            -
                    CACHED_PLAN_HEURISTIC = "cached plan must not change result type".freeze
         | 
| 651 721 | 
             
                    def is_cached_plan_failure?(e)
         | 
| 652 722 | 
             
                      pgerror = e.cause
         | 
| 653 | 
            -
                       | 
| 654 | 
            -
             | 
| 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"
         | 
| 655 725 | 
             
                    rescue
         | 
| 656 726 | 
             
                      false
         | 
| 657 727 | 
             
                    end
         | 
| @@ -668,7 +738,7 @@ module ActiveRecord | |
| 668 738 |  | 
| 669 739 | 
             
                    # Prepare the statement if it hasn't been prepared, return
         | 
| 670 740 | 
             
                    # the statement key.
         | 
| 671 | 
            -
                    def prepare_statement(sql)
         | 
| 741 | 
            +
                    def prepare_statement(sql, binds)
         | 
| 672 742 | 
             
                      @lock.synchronize do
         | 
| 673 743 | 
             
                        sql_key = sql_key(sql)
         | 
| 674 744 | 
             
                        unless @statements.key? sql_key
         | 
| @@ -676,7 +746,7 @@ module ActiveRecord | |
| 676 746 | 
             
                          begin
         | 
| 677 747 | 
             
                            @connection.prepare nextkey, sql
         | 
| 678 748 | 
             
                          rescue => e
         | 
| 679 | 
            -
                            raise translate_exception_class(e, sql)
         | 
| 749 | 
            +
                            raise translate_exception_class(e, sql, binds)
         | 
| 680 750 | 
             
                          end
         | 
| 681 751 | 
             
                          # Clear the queue
         | 
| 682 752 | 
             
                          @connection.get_last_result
         | 
| @@ -689,14 +759,10 @@ module ActiveRecord | |
| 689 759 | 
             
                    # Connects to a PostgreSQL server and sets up the adapter depending on the
         | 
| 690 760 | 
             
                    # connected server's characteristics.
         | 
| 691 761 | 
             
                    def connect
         | 
| 692 | 
            -
                      @connection =  | 
| 762 | 
            +
                      @connection = self.class.new_client(@connection_parameters)
         | 
| 693 763 | 
             
                      configure_connection
         | 
| 694 | 
            -
             | 
| 695 | 
            -
                       | 
| 696 | 
            -
                        raise ActiveRecord::NoDatabaseError
         | 
| 697 | 
            -
                      else
         | 
| 698 | 
            -
                        raise
         | 
| 699 | 
            -
                      end
         | 
| 764 | 
            +
                      add_pg_encoders
         | 
| 765 | 
            +
                      add_pg_decoders
         | 
| 700 766 | 
             
                    end
         | 
| 701 767 |  | 
| 702 768 | 
             
                    # Configures the encoding, verbosity, schema search path, and time zone of the connection.
         | 
| @@ -723,6 +789,9 @@ module ActiveRecord | |
| 723 789 | 
             
                        end
         | 
| 724 790 | 
             
                      end
         | 
| 725 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 | 
            +
             | 
| 726 795 | 
             
                      # SET statements from :variables config hash
         | 
| 727 796 | 
             
                      # https://www.postgresql.org/docs/current/static/sql-set.html
         | 
| 728 797 | 
             
                      variables.map do |k, v|
         | 
| @@ -754,7 +823,7 @@ module ActiveRecord | |
| 754 823 | 
             
                    #  - format_type includes the column size constraint, e.g. varchar(50)
         | 
| 755 824 | 
             
                    #  - ::regclass is a function that gives the id for a table name
         | 
| 756 825 | 
             
                    def column_definitions(table_name)
         | 
| 757 | 
            -
                      query( | 
| 826 | 
            +
                      query(<<~SQL, "SCHEMA")
         | 
| 758 827 | 
             
                          SELECT a.attname, format_type(a.atttypid, a.atttypmod),
         | 
| 759 828 | 
             
                                 pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
         | 
| 760 829 | 
             
                                 c.collname, col_description(a.attrelid, a.attnum) AS comment
         | 
| @@ -765,7 +834,7 @@ module ActiveRecord | |
| 765 834 | 
             
                           WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
         | 
| 766 835 | 
             
                             AND a.attnum > 0 AND NOT a.attisdropped
         | 
| 767 836 | 
             
                           ORDER BY a.attnum
         | 
| 768 | 
            -
                       | 
| 837 | 
            +
                      SQL
         | 
| 769 838 | 
             
                    end
         | 
| 770 839 |  | 
| 771 840 | 
             
                    def extract_table_ref_from_insert_sql(sql)
         | 
| @@ -777,10 +846,14 @@ module ActiveRecord | |
| 777 846 | 
             
                      Arel::Visitors::PostgreSQL.new(self)
         | 
| 778 847 | 
             
                    end
         | 
| 779 848 |  | 
| 849 | 
            +
                    def build_statement_pool
         | 
| 850 | 
            +
                      StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
         | 
| 851 | 
            +
                    end
         | 
| 852 | 
            +
             | 
| 780 853 | 
             
                    def can_perform_case_insensitive_comparison_for?(column)
         | 
| 781 854 | 
             
                      @case_insensitive_cache ||= {}
         | 
| 782 855 | 
             
                      @case_insensitive_cache[column.sql_type] ||= begin
         | 
| 783 | 
            -
                        sql =  | 
| 856 | 
            +
                        sql = <<~SQL
         | 
| 784 857 | 
             
                          SELECT exists(
         | 
| 785 858 | 
             
                            SELECT * FROM pg_proc
         | 
| 786 859 | 
             
                            WHERE proname = 'lower'
         | 
| @@ -792,7 +865,7 @@ module ActiveRecord | |
| 792 865 | 
             
                            WHERE proname = 'lower'
         | 
| 793 866 | 
             
                              AND castsource = #{quote column.sql_type}::regtype
         | 
| 794 867 | 
             
                          )
         | 
| 795 | 
            -
                         | 
| 868 | 
            +
                        SQL
         | 
| 796 869 | 
             
                        execute_and_clear(sql, "SCHEMA", []) do |result|
         | 
| 797 870 | 
             
                          result.getvalue(0, 0)
         | 
| 798 871 | 
             
                        end
         | 
| @@ -807,7 +880,22 @@ module ActiveRecord | |
| 807 880 | 
             
                      @connection.type_map_for_queries = map
         | 
| 808 881 | 
             
                    end
         | 
| 809 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 | 
            +
             | 
| 810 895 | 
             
                    def add_pg_decoders
         | 
| 896 | 
            +
                      @default_timezone = nil
         | 
| 897 | 
            +
                      @timestamp_decoder = nil
         | 
| 898 | 
            +
             | 
| 811 899 | 
             
                      coders_by_name = {
         | 
| 812 900 | 
             
                        "int2" => PG::TextDecoder::Integer,
         | 
| 813 901 | 
             
                        "int4" => PG::TextDecoder::Integer,
         | 
| @@ -815,10 +903,14 @@ module ActiveRecord | |
| 815 903 | 
             
                        "oid" => PG::TextDecoder::Integer,
         | 
| 816 904 | 
             
                        "float4" => PG::TextDecoder::Float,
         | 
| 817 905 | 
             
                        "float8" => PG::TextDecoder::Float,
         | 
| 906 | 
            +
                        "numeric" => PG::TextDecoder::Numeric,
         | 
| 818 907 | 
             
                        "bool" => PG::TextDecoder::Boolean,
         | 
| 908 | 
            +
                        "timestamp" => PG::TextDecoder::TimestampUtc,
         | 
| 909 | 
            +
                        "timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
         | 
| 819 910 | 
             
                      }
         | 
| 911 | 
            +
             | 
| 820 912 | 
             
                      known_coder_types = coders_by_name.keys.map { |n| quote(n) }
         | 
| 821 | 
            -
                      query =  | 
| 913 | 
            +
                      query = <<~SQL % known_coder_types.join(", ")
         | 
| 822 914 | 
             
                        SELECT t.oid, t.typname
         | 
| 823 915 | 
             
                        FROM pg_type as t
         | 
| 824 916 | 
             
                        WHERE t.typname IN (%s)
         | 
| @@ -832,6 +924,15 @@ module ActiveRecord | |
| 832 924 | 
             
                      map = PG::TypeMapByOid.new
         | 
| 833 925 | 
             
                      coders.each { |coder| map.add_coder(coder) }
         | 
| 834 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
         | 
| 835 936 | 
             
                    end
         | 
| 836 937 |  | 
| 837 938 | 
             
                    def construct_coder(row, coder_class)
         | 
| @@ -839,6 +940,14 @@ module ActiveRecord | |
| 839 940 | 
             
                      coder_class.new(oid: row["oid"].to_i, name: row["typname"])
         | 
| 840 941 | 
             
                    end
         | 
| 841 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
         | 
| 949 | 
            +
                    end
         | 
| 950 | 
            +
             | 
| 842 951 | 
             
                    ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
         | 
| 843 952 | 
             
                    ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
         | 
| 844 953 | 
             
                    ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
         | 
| @@ -851,6 +960,7 @@ module ActiveRecord | |
| 851 960 | 
             
                    ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
         | 
| 852 961 | 
             
                    ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
         | 
| 853 962 | 
             
                    ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
         | 
| 963 | 
            +
                    ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
         | 
| 854 964 | 
             
                    ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
         | 
| 855 965 | 
             
                    ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
         | 
| 856 966 | 
             
                    ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
         |