activerecord 5.2.8.1 → 6.1.6.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1255 -596
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +100 -41
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +55 -48
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +44 -34
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +69 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +333 -98
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +273 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +108 -36
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +200 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +28 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +145 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +116 -59
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +411 -80
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +476 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +115 -62
- data/lib/active_record/relation.rb +379 -115
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +4 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +116 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -1,17 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
gem "pg", ">= 0.18", "< 2.0"
|
3
|
+
gem "pg", "~> 1.1"
|
5
4
|
require "pg"
|
6
5
|
|
7
|
-
|
8
|
-
class ::PG::Connection
|
9
|
-
unless self.public_method_defined?(:async_exec_params)
|
10
|
-
remove_method :exec_params
|
11
|
-
alias exec_params async_exec
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
6
|
+
require "active_support/core_ext/object/try"
|
15
7
|
require "active_record/connection_adapters/abstract_adapter"
|
16
8
|
require "active_record/connection_adapters/statement_pool"
|
17
9
|
require "active_record/connection_adapters/postgresql/column"
|
@@ -31,9 +23,7 @@ module ActiveRecord
|
|
31
23
|
module ConnectionHandling # :nodoc:
|
32
24
|
# Establishes a connection to the database that's used by all Active Record objects
|
33
25
|
def postgresql_connection(config)
|
34
|
-
conn_params = config.symbolize_keys
|
35
|
-
|
36
|
-
conn_params.delete_if { |_, v| v.nil? }
|
26
|
+
conn_params = config.symbolize_keys.compact
|
37
27
|
|
38
28
|
# Map ActiveRecords param names to PGs.
|
39
29
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
@@ -43,14 +33,17 @@ module ActiveRecord
|
|
43
33
|
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
44
34
|
conn_params.slice!(*valid_conn_param_keys)
|
45
35
|
|
46
|
-
|
47
|
-
|
48
|
-
|
36
|
+
ConnectionAdapters::PostgreSQLAdapter.new(
|
37
|
+
ConnectionAdapters::PostgreSQLAdapter.new_client(conn_params),
|
38
|
+
logger,
|
39
|
+
conn_params,
|
40
|
+
config,
|
41
|
+
)
|
49
42
|
end
|
50
43
|
end
|
51
44
|
|
52
45
|
module ConnectionAdapters
|
53
|
-
# The PostgreSQL adapter works with the native C (https://
|
46
|
+
# The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
|
54
47
|
#
|
55
48
|
# Options:
|
56
49
|
#
|
@@ -78,7 +71,32 @@ module ActiveRecord
|
|
78
71
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
79
72
|
# See https://www.postgresql.org/docs/current/static/libpq-envars.html .
|
80
73
|
class PostgreSQLAdapter < AbstractAdapter
|
81
|
-
ADAPTER_NAME = "PostgreSQL"
|
74
|
+
ADAPTER_NAME = "PostgreSQL"
|
75
|
+
|
76
|
+
class << self
|
77
|
+
def new_client(conn_params)
|
78
|
+
PG.connect(conn_params)
|
79
|
+
rescue ::PG::Error => error
|
80
|
+
if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
|
81
|
+
raise ActiveRecord::NoDatabaseError
|
82
|
+
else
|
83
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# :singleton-method:
|
90
|
+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
91
|
+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
92
|
+
# but significantly increases the risk of data loss if the database
|
93
|
+
# crashes. As a result, this should not be used in production
|
94
|
+
# environments. If you would like all created tables to be unlogged in
|
95
|
+
# the test environment you can add the following line to your test.rb
|
96
|
+
# file:
|
97
|
+
#
|
98
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
99
|
+
class_attribute :create_unlogged_tables, default: false
|
82
100
|
|
83
101
|
NATIVE_DATABASE_TYPES = {
|
84
102
|
primary_key: "bigserial primary key",
|
@@ -138,6 +156,10 @@ module ActiveRecord
|
|
138
156
|
true
|
139
157
|
end
|
140
158
|
|
159
|
+
def supports_partitioned_indexes?
|
160
|
+
database_version >= 110_000
|
161
|
+
end
|
162
|
+
|
141
163
|
def supports_partial_index?
|
142
164
|
true
|
143
165
|
end
|
@@ -154,6 +176,10 @@ module ActiveRecord
|
|
154
176
|
true
|
155
177
|
end
|
156
178
|
|
179
|
+
def supports_check_constraints?
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
157
183
|
def supports_validate_constraints?
|
158
184
|
true
|
159
185
|
end
|
@@ -167,7 +193,7 @@ module ActiveRecord
|
|
167
193
|
end
|
168
194
|
|
169
195
|
def supports_json?
|
170
|
-
|
196
|
+
true
|
171
197
|
end
|
172
198
|
|
173
199
|
def supports_comments?
|
@@ -178,6 +204,17 @@ module ActiveRecord
|
|
178
204
|
true
|
179
205
|
end
|
180
206
|
|
207
|
+
def supports_insert_returning?
|
208
|
+
true
|
209
|
+
end
|
210
|
+
|
211
|
+
def supports_insert_on_conflict?
|
212
|
+
database_version >= 90500
|
213
|
+
end
|
214
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
215
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
216
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
217
|
+
|
181
218
|
def index_algorithms
|
182
219
|
{ concurrently: "CONCURRENTLY" }
|
183
220
|
end
|
@@ -190,11 +227,7 @@ module ActiveRecord
|
|
190
227
|
end
|
191
228
|
|
192
229
|
def next_key
|
193
|
-
"a#{@counter
|
194
|
-
end
|
195
|
-
|
196
|
-
def []=(sql, key)
|
197
|
-
super.tap { @counter += 1 }
|
230
|
+
"a#{@counter += 1}"
|
198
231
|
end
|
199
232
|
|
200
233
|
private
|
@@ -220,15 +253,8 @@ module ActiveRecord
|
|
220
253
|
@local_tz = nil
|
221
254
|
@max_identifier_length = nil
|
222
255
|
|
223
|
-
|
256
|
+
configure_connection
|
224
257
|
add_pg_encoders
|
225
|
-
@statements = StatementPool.new @connection,
|
226
|
-
self.class.type_cast_config_to_integer(config[:statement_limit])
|
227
|
-
|
228
|
-
if postgresql_version < 90100
|
229
|
-
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
|
230
|
-
end
|
231
|
-
|
232
258
|
add_pg_decoders
|
233
259
|
|
234
260
|
@type_map = Type::HashLookupTypeMap.new
|
@@ -237,15 +263,10 @@ module ActiveRecord
|
|
237
263
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
238
264
|
end
|
239
265
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def truncate(table_name, name = nil)
|
248
|
-
exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
|
266
|
+
def self.database_exists?(config)
|
267
|
+
!!ActiveRecord::Base.postgresql_connection(config)
|
268
|
+
rescue ActiveRecord::NoDatabaseError
|
269
|
+
false
|
249
270
|
end
|
250
271
|
|
251
272
|
# Is this connection alive and ready for queries?
|
@@ -264,6 +285,8 @@ module ActiveRecord
|
|
264
285
|
super
|
265
286
|
@connection.reset
|
266
287
|
configure_connection
|
288
|
+
rescue PG::ConnectionBad
|
289
|
+
connect
|
267
290
|
end
|
268
291
|
end
|
269
292
|
|
@@ -289,6 +312,7 @@ module ActiveRecord
|
|
289
312
|
end
|
290
313
|
|
291
314
|
def discard! # :nodoc:
|
315
|
+
super
|
292
316
|
@connection.socket_io.reopen(IO::NULL) rescue nil
|
293
317
|
@connection = nil
|
294
318
|
end
|
@@ -317,21 +341,31 @@ module ActiveRecord
|
|
317
341
|
true
|
318
342
|
end
|
319
343
|
|
320
|
-
def supports_ranges?
|
321
|
-
# Range datatypes weren't introduced until PostgreSQL 9.2
|
322
|
-
postgresql_version >= 90200
|
323
|
-
end
|
324
|
-
|
325
344
|
def supports_materialized_views?
|
326
|
-
|
345
|
+
true
|
327
346
|
end
|
328
347
|
|
329
348
|
def supports_foreign_tables?
|
330
|
-
|
349
|
+
true
|
331
350
|
end
|
332
351
|
|
333
352
|
def supports_pgcrypto_uuid?
|
334
|
-
|
353
|
+
database_version >= 90400
|
354
|
+
end
|
355
|
+
|
356
|
+
def supports_optimizer_hints?
|
357
|
+
unless defined?(@has_pg_hint_plan)
|
358
|
+
@has_pg_hint_plan = extension_available?("pg_hint_plan")
|
359
|
+
end
|
360
|
+
@has_pg_hint_plan
|
361
|
+
end
|
362
|
+
|
363
|
+
def supports_common_table_expressions?
|
364
|
+
true
|
365
|
+
end
|
366
|
+
|
367
|
+
def supports_lazy_transactions?
|
368
|
+
true
|
335
369
|
end
|
336
370
|
|
337
371
|
def get_advisory_lock(lock_id) # :nodoc:
|
@@ -360,9 +394,12 @@ module ActiveRecord
|
|
360
394
|
}
|
361
395
|
end
|
362
396
|
|
397
|
+
def extension_available?(name)
|
398
|
+
query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
399
|
+
end
|
400
|
+
|
363
401
|
def extension_enabled?(name)
|
364
|
-
|
365
|
-
res.cast_values.first
|
402
|
+
query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
366
403
|
end
|
367
404
|
|
368
405
|
def extensions
|
@@ -373,8 +410,6 @@ module ActiveRecord
|
|
373
410
|
def max_identifier_length
|
374
411
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
375
412
|
end
|
376
|
-
alias table_alias_length max_identifier_length
|
377
|
-
alias index_name_length max_identifier_length
|
378
413
|
|
379
414
|
# Set the authorized user for this session
|
380
415
|
def session_auth=(user)
|
@@ -386,25 +421,37 @@ module ActiveRecord
|
|
386
421
|
@use_insert_returning
|
387
422
|
end
|
388
423
|
|
389
|
-
def column_name_for_operation(operation, node) # :nodoc:
|
390
|
-
OPERATION_ALIASES.fetch(operation) { operation.downcase }
|
391
|
-
end
|
392
|
-
|
393
|
-
OPERATION_ALIASES = { # :nodoc:
|
394
|
-
"maximum" => "max",
|
395
|
-
"minimum" => "min",
|
396
|
-
"average" => "avg",
|
397
|
-
}
|
398
|
-
|
399
424
|
# Returns the version of the connected PostgreSQL server.
|
400
|
-
def
|
425
|
+
def get_database_version # :nodoc:
|
401
426
|
@connection.server_version
|
402
427
|
end
|
428
|
+
alias :postgresql_version :database_version
|
403
429
|
|
404
430
|
def default_index_type?(index) # :nodoc:
|
405
431
|
index.using == :btree || super
|
406
432
|
end
|
407
433
|
|
434
|
+
def build_insert_sql(insert) # :nodoc:
|
435
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
436
|
+
|
437
|
+
if insert.skip_duplicates?
|
438
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
439
|
+
elsif insert.update_duplicates?
|
440
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
441
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
442
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
443
|
+
end
|
444
|
+
|
445
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
446
|
+
sql
|
447
|
+
end
|
448
|
+
|
449
|
+
def check_version # :nodoc:
|
450
|
+
if database_version < 90300
|
451
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
408
455
|
private
|
409
456
|
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
410
457
|
VALUE_LIMIT_VIOLATION = "22001"
|
@@ -414,37 +461,46 @@ module ActiveRecord
|
|
414
461
|
UNIQUE_VIOLATION = "23505"
|
415
462
|
SERIALIZATION_FAILURE = "40001"
|
416
463
|
DEADLOCK_DETECTED = "40P01"
|
464
|
+
DUPLICATE_DATABASE = "42P04"
|
417
465
|
LOCK_NOT_AVAILABLE = "55P03"
|
418
466
|
QUERY_CANCELED = "57014"
|
419
467
|
|
420
|
-
def translate_exception(exception, message)
|
468
|
+
def translate_exception(exception, message:, sql:, binds:)
|
421
469
|
return exception unless exception.respond_to?(:result)
|
422
470
|
|
423
471
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
472
|
+
when nil
|
473
|
+
if exception.message.match?(/connection is closed/i)
|
474
|
+
ConnectionNotEstablished.new(exception)
|
475
|
+
else
|
476
|
+
super
|
477
|
+
end
|
424
478
|
when UNIQUE_VIOLATION
|
425
|
-
RecordNotUnique.new(message)
|
479
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
426
480
|
when FOREIGN_KEY_VIOLATION
|
427
|
-
InvalidForeignKey.new(message)
|
481
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
428
482
|
when VALUE_LIMIT_VIOLATION
|
429
|
-
ValueTooLong.new(message)
|
483
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
430
484
|
when NUMERIC_VALUE_OUT_OF_RANGE
|
431
|
-
RangeError.new(message)
|
485
|
+
RangeError.new(message, sql: sql, binds: binds)
|
432
486
|
when NOT_NULL_VIOLATION
|
433
|
-
NotNullViolation.new(message)
|
487
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
434
488
|
when SERIALIZATION_FAILURE
|
435
|
-
SerializationFailure.new(message)
|
489
|
+
SerializationFailure.new(message, sql: sql, binds: binds)
|
436
490
|
when DEADLOCK_DETECTED
|
437
|
-
Deadlocked.new(message)
|
491
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
492
|
+
when DUPLICATE_DATABASE
|
493
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
438
494
|
when LOCK_NOT_AVAILABLE
|
439
|
-
LockWaitTimeout.new(message)
|
495
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
440
496
|
when QUERY_CANCELED
|
441
|
-
QueryCanceled.new(message)
|
497
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
442
498
|
else
|
443
499
|
super
|
444
500
|
end
|
445
501
|
end
|
446
502
|
|
447
|
-
def get_oid_type(oid, fmod, column_name, sql_type = ""
|
503
|
+
def get_oid_type(oid, fmod, column_name, sql_type = "")
|
448
504
|
if !type_map.key?(oid)
|
449
505
|
load_additional_types([oid])
|
450
506
|
end
|
@@ -486,7 +542,7 @@ module ActiveRecord
|
|
486
542
|
m.register_type "uuid", OID::Uuid.new
|
487
543
|
m.register_type "xml", OID::Xml.new
|
488
544
|
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
489
|
-
m.register_type "macaddr", OID::
|
545
|
+
m.register_type "macaddr", OID::Macaddr.new
|
490
546
|
m.register_type "citext", OID::SpecializedString.new(:citext)
|
491
547
|
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
492
548
|
m.register_type "line", OID::SpecializedString.new(:line)
|
@@ -496,11 +552,6 @@ module ActiveRecord
|
|
496
552
|
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
497
553
|
m.register_type "circle", OID::SpecializedString.new(:circle)
|
498
554
|
|
499
|
-
m.register_type "interval" do |_, _, sql_type|
|
500
|
-
precision = extract_precision(sql_type)
|
501
|
-
OID::SpecializedString.new(:interval, precision: precision)
|
502
|
-
end
|
503
|
-
|
504
555
|
register_class_with_precision m, "time", Type::Time
|
505
556
|
register_class_with_precision m, "timestamp", OID::DateTime
|
506
557
|
|
@@ -524,6 +575,11 @@ module ActiveRecord
|
|
524
575
|
end
|
525
576
|
end
|
526
577
|
|
578
|
+
m.register_type "interval" do |*args, sql_type|
|
579
|
+
precision = extract_precision(sql_type)
|
580
|
+
OID::Interval.new(precision: precision)
|
581
|
+
end
|
582
|
+
|
527
583
|
load_additional_types
|
528
584
|
end
|
529
585
|
|
@@ -533,13 +589,13 @@ module ActiveRecord
|
|
533
589
|
# Quoted types
|
534
590
|
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
535
591
|
# The default 'now'::date is CURRENT_DATE
|
536
|
-
if $1 == "now"
|
592
|
+
if $1 == "now" && $2 == "date"
|
537
593
|
nil
|
538
594
|
else
|
539
|
-
$1.gsub("''"
|
595
|
+
$1.gsub("''", "'")
|
540
596
|
end
|
541
597
|
# Boolean types
|
542
|
-
when "true"
|
598
|
+
when "true", "false"
|
543
599
|
default
|
544
600
|
# Numeric types
|
545
601
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -565,21 +621,14 @@ module ActiveRecord
|
|
565
621
|
def load_additional_types(oids = nil)
|
566
622
|
initializer = OID::TypeMapInitializer.new(type_map)
|
567
623
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
SQL
|
574
|
-
else
|
575
|
-
query = <<-SQL
|
576
|
-
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
|
577
|
-
FROM pg_type as t
|
578
|
-
SQL
|
579
|
-
end
|
624
|
+
query = <<~SQL
|
625
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
626
|
+
FROM pg_type as t
|
627
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
628
|
+
SQL
|
580
629
|
|
581
630
|
if oids
|
582
|
-
query += "WHERE t.oid
|
631
|
+
query += "WHERE t.oid IN (%s)" % oids.join(", ")
|
583
632
|
else
|
584
633
|
query += initializer.query_conditions_for_initial_load
|
585
634
|
end
|
@@ -592,19 +641,31 @@ module ActiveRecord
|
|
592
641
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
593
642
|
|
594
643
|
def execute_and_clear(sql, name, binds, prepare: false)
|
595
|
-
if
|
596
|
-
|
597
|
-
|
644
|
+
if preventing_writes? && write_query?(sql)
|
645
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
646
|
+
end
|
647
|
+
|
648
|
+
if !prepare || without_prepared_statement?(binds)
|
598
649
|
result = exec_no_cache(sql, name, binds)
|
599
650
|
else
|
600
651
|
result = exec_cache(sql, name, binds)
|
601
652
|
end
|
602
|
-
|
603
|
-
|
653
|
+
begin
|
654
|
+
ret = yield result
|
655
|
+
ensure
|
656
|
+
result.clear
|
657
|
+
end
|
604
658
|
ret
|
605
659
|
end
|
606
660
|
|
607
661
|
def exec_no_cache(sql, name, binds)
|
662
|
+
materialize_transactions
|
663
|
+
mark_transaction_written_if_write(sql)
|
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
|
+
|
608
669
|
type_casted_binds = type_casted_binds(binds)
|
609
670
|
log(sql, name, binds, type_casted_binds) do
|
610
671
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -614,7 +675,11 @@ module ActiveRecord
|
|
614
675
|
end
|
615
676
|
|
616
677
|
def exec_cache(sql, name, binds)
|
617
|
-
|
678
|
+
materialize_transactions
|
679
|
+
mark_transaction_written_if_write(sql)
|
680
|
+
update_typemap_for_default_timezone
|
681
|
+
|
682
|
+
stmt_key = prepare_statement(sql, binds)
|
618
683
|
type_casted_binds = type_casted_binds(binds)
|
619
684
|
|
620
685
|
log(sql, name, binds, type_casted_binds, stmt_key) do
|
@@ -647,11 +712,10 @@ module ActiveRecord
|
|
647
712
|
#
|
648
713
|
# Check here for more details:
|
649
714
|
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
650
|
-
CACHED_PLAN_HEURISTIC = "cached plan must not change result type".freeze
|
651
715
|
def is_cached_plan_failure?(e)
|
652
716
|
pgerror = e.cause
|
653
|
-
|
654
|
-
|
717
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
718
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
655
719
|
rescue
|
656
720
|
false
|
657
721
|
end
|
@@ -668,7 +732,7 @@ module ActiveRecord
|
|
668
732
|
|
669
733
|
# Prepare the statement if it hasn't been prepared, return
|
670
734
|
# the statement key.
|
671
|
-
def prepare_statement(sql)
|
735
|
+
def prepare_statement(sql, binds)
|
672
736
|
@lock.synchronize do
|
673
737
|
sql_key = sql_key(sql)
|
674
738
|
unless @statements.key? sql_key
|
@@ -676,7 +740,7 @@ module ActiveRecord
|
|
676
740
|
begin
|
677
741
|
@connection.prepare nextkey, sql
|
678
742
|
rescue => e
|
679
|
-
raise translate_exception_class(e, sql)
|
743
|
+
raise translate_exception_class(e, sql, binds)
|
680
744
|
end
|
681
745
|
# Clear the queue
|
682
746
|
@connection.get_last_result
|
@@ -689,14 +753,10 @@ module ActiveRecord
|
|
689
753
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
690
754
|
# connected server's characteristics.
|
691
755
|
def connect
|
692
|
-
@connection =
|
756
|
+
@connection = self.class.new_client(@connection_parameters)
|
693
757
|
configure_connection
|
694
|
-
|
695
|
-
|
696
|
-
raise ActiveRecord::NoDatabaseError
|
697
|
-
else
|
698
|
-
raise
|
699
|
-
end
|
758
|
+
add_pg_encoders
|
759
|
+
add_pg_decoders
|
700
760
|
end
|
701
761
|
|
702
762
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -723,6 +783,9 @@ module ActiveRecord
|
|
723
783
|
end
|
724
784
|
end
|
725
785
|
|
786
|
+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
787
|
+
execute("SET intervalstyle = iso_8601", "SCHEMA")
|
788
|
+
|
726
789
|
# SET statements from :variables config hash
|
727
790
|
# https://www.postgresql.org/docs/current/static/sql-set.html
|
728
791
|
variables.map do |k, v|
|
@@ -754,7 +817,7 @@ module ActiveRecord
|
|
754
817
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
755
818
|
# - ::regclass is a function that gives the id for a table name
|
756
819
|
def column_definitions(table_name)
|
757
|
-
query(
|
820
|
+
query(<<~SQL, "SCHEMA")
|
758
821
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
759
822
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
760
823
|
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
@@ -765,7 +828,7 @@ module ActiveRecord
|
|
765
828
|
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
766
829
|
AND a.attnum > 0 AND NOT a.attisdropped
|
767
830
|
ORDER BY a.attnum
|
768
|
-
|
831
|
+
SQL
|
769
832
|
end
|
770
833
|
|
771
834
|
def extract_table_ref_from_insert_sql(sql)
|
@@ -777,10 +840,14 @@ module ActiveRecord
|
|
777
840
|
Arel::Visitors::PostgreSQL.new(self)
|
778
841
|
end
|
779
842
|
|
843
|
+
def build_statement_pool
|
844
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
845
|
+
end
|
846
|
+
|
780
847
|
def can_perform_case_insensitive_comparison_for?(column)
|
781
848
|
@case_insensitive_cache ||= {}
|
782
849
|
@case_insensitive_cache[column.sql_type] ||= begin
|
783
|
-
sql =
|
850
|
+
sql = <<~SQL
|
784
851
|
SELECT exists(
|
785
852
|
SELECT * FROM pg_proc
|
786
853
|
WHERE proname = 'lower'
|
@@ -792,7 +859,7 @@ module ActiveRecord
|
|
792
859
|
WHERE proname = 'lower'
|
793
860
|
AND castsource = #{quote column.sql_type}::regtype
|
794
861
|
)
|
795
|
-
|
862
|
+
SQL
|
796
863
|
execute_and_clear(sql, "SCHEMA", []) do |result|
|
797
864
|
result.getvalue(0, 0)
|
798
865
|
end
|
@@ -807,7 +874,22 @@ module ActiveRecord
|
|
807
874
|
@connection.type_map_for_queries = map
|
808
875
|
end
|
809
876
|
|
877
|
+
def update_typemap_for_default_timezone
|
878
|
+
if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
|
879
|
+
decoder_class = ActiveRecord::Base.default_timezone == :utc ?
|
880
|
+
PG::TextDecoder::TimestampUtc :
|
881
|
+
PG::TextDecoder::TimestampWithoutTimeZone
|
882
|
+
|
883
|
+
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
884
|
+
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
885
|
+
@default_timezone = ActiveRecord::Base.default_timezone
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
810
889
|
def add_pg_decoders
|
890
|
+
@default_timezone = nil
|
891
|
+
@timestamp_decoder = nil
|
892
|
+
|
811
893
|
coders_by_name = {
|
812
894
|
"int2" => PG::TextDecoder::Integer,
|
813
895
|
"int4" => PG::TextDecoder::Integer,
|
@@ -815,10 +897,14 @@ module ActiveRecord
|
|
815
897
|
"oid" => PG::TextDecoder::Integer,
|
816
898
|
"float4" => PG::TextDecoder::Float,
|
817
899
|
"float8" => PG::TextDecoder::Float,
|
900
|
+
"numeric" => PG::TextDecoder::Numeric,
|
818
901
|
"bool" => PG::TextDecoder::Boolean,
|
902
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
903
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
819
904
|
}
|
905
|
+
|
820
906
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
821
|
-
query =
|
907
|
+
query = <<~SQL % known_coder_types.join(", ")
|
822
908
|
SELECT t.oid, t.typname
|
823
909
|
FROM pg_type as t
|
824
910
|
WHERE t.typname IN (%s)
|
@@ -832,6 +918,15 @@ module ActiveRecord
|
|
832
918
|
map = PG::TypeMapByOid.new
|
833
919
|
coders.each { |coder| map.add_coder(coder) }
|
834
920
|
@connection.type_map_for_results = map
|
921
|
+
|
922
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
923
|
+
@type_map_for_results.default_type_map = map
|
924
|
+
@type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
|
925
|
+
@type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
|
926
|
+
|
927
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
928
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
929
|
+
update_typemap_for_default_timezone
|
835
930
|
end
|
836
931
|
|
837
932
|
def construct_coder(row, coder_class)
|
@@ -839,6 +934,14 @@ module ActiveRecord
|
|
839
934
|
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
840
935
|
end
|
841
936
|
|
937
|
+
class MoneyDecoder < PG::SimpleDecoder # :nodoc:
|
938
|
+
TYPE = OID::Money.new
|
939
|
+
|
940
|
+
def decode(value, tuple = nil, field = nil)
|
941
|
+
TYPE.deserialize(value)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
842
945
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
843
946
|
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
844
947
|
ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
|
@@ -851,6 +954,7 @@ module ActiveRecord
|
|
851
954
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
852
955
|
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
853
956
|
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
957
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
854
958
|
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
855
959
|
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
856
960
|
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
|