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