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