activerecord 4.2.11.3 → 5.0.0.beta1
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 +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +9 -14
- data/lib/active_record/type/time.rb +3 -21
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
|
4
|
+
attr_reader :oid, :fmod, :array
|
5
|
+
|
6
|
+
def initialize(type_metadata, oid: nil, fmod: nil)
|
7
|
+
super(type_metadata)
|
8
|
+
@type_metadata = type_metadata
|
9
|
+
@oid = oid
|
10
|
+
@fmod = fmod
|
11
|
+
@array = /\[\]$/ === type_metadata.sql_type
|
12
|
+
end
|
13
|
+
|
14
|
+
def sql_type
|
15
|
+
super.gsub(/\[\]$/, "".freeze)
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
other.is_a?(PostgreSQLTypeMetadata) &&
|
20
|
+
attributes_for_hash == other.attributes_for_hash
|
21
|
+
end
|
22
|
+
alias eql? ==
|
23
|
+
|
24
|
+
def hash
|
25
|
+
attributes_for_hash.hash
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def attributes_for_hash
|
31
|
+
[self.class, @type_metadata, oid, fmod]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,31 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'active_record/connection_adapters/postgresql/utils'
|
5
|
-
require 'active_record/connection_adapters/postgresql/column'
|
6
|
-
require 'active_record/connection_adapters/postgresql/oid'
|
7
|
-
require 'active_record/connection_adapters/postgresql/quoting'
|
8
|
-
require 'active_record/connection_adapters/postgresql/referential_integrity'
|
9
|
-
require 'active_record/connection_adapters/postgresql/schema_definitions'
|
10
|
-
require 'active_record/connection_adapters/postgresql/schema_statements'
|
11
|
-
require 'active_record/connection_adapters/postgresql/database_statements'
|
12
|
-
|
13
|
-
require 'arel/visitors/bind_visitor'
|
14
|
-
|
15
|
-
# Make sure we're using pg high enough for PGResult#values
|
16
|
-
gem 'pg', '~> 0.15'
|
1
|
+
# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
|
2
|
+
gem 'pg', '~> 0.18'
|
17
3
|
require 'pg'
|
18
4
|
|
5
|
+
require "active_record/connection_adapters/abstract_adapter"
|
6
|
+
require "active_record/connection_adapters/postgresql/column"
|
7
|
+
require "active_record/connection_adapters/postgresql/database_statements"
|
8
|
+
require "active_record/connection_adapters/postgresql/oid"
|
9
|
+
require "active_record/connection_adapters/postgresql/quoting"
|
10
|
+
require "active_record/connection_adapters/postgresql/referential_integrity"
|
11
|
+
require "active_record/connection_adapters/postgresql/schema_definitions"
|
12
|
+
require "active_record/connection_adapters/postgresql/schema_dumper"
|
13
|
+
require "active_record/connection_adapters/postgresql/schema_statements"
|
14
|
+
require "active_record/connection_adapters/postgresql/type_metadata"
|
15
|
+
require "active_record/connection_adapters/postgresql/utils"
|
16
|
+
require "active_record/connection_adapters/statement_pool"
|
17
|
+
|
19
18
|
require 'ipaddr'
|
20
19
|
|
21
20
|
module ActiveRecord
|
22
21
|
module ConnectionHandling # :nodoc:
|
23
|
-
VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
|
24
|
-
:client_encoding, :options, :application_name, :fallback_application_name,
|
25
|
-
:keepalives, :keepalives_idle, :keepalives_interval, :keepalives_count,
|
26
|
-
:tty, :sslmode, :requiressl, :sslcompression, :sslcert, :sslkey,
|
27
|
-
:sslrootcert, :sslcrl, :requirepeer, :krbsrvname, :gsslib, :service]
|
28
|
-
|
29
22
|
# Establishes a connection to the database that's used by all Active Record objects
|
30
23
|
def postgresql_connection(config)
|
31
24
|
conn_params = config.symbolize_keys
|
@@ -37,7 +30,8 @@ module ActiveRecord
|
|
37
30
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
38
31
|
|
39
32
|
# Forward only valid config params to PGconn.connect.
|
40
|
-
|
33
|
+
valid_conn_param_keys = PGconn.conndefaults_hash.keys + [:requiressl]
|
34
|
+
conn_params.slice!(*valid_conn_param_keys)
|
41
35
|
|
42
36
|
# The postgres drivers don't allow the creation of an unconnected PGconn object,
|
43
37
|
# so just pass a nil connection object for the time being.
|
@@ -68,17 +62,16 @@ module ActiveRecord
|
|
68
62
|
# defaults to true.
|
69
63
|
#
|
70
64
|
# Any further options are used as connection parameters to libpq. See
|
71
|
-
# http://www.postgresql.org/docs/
|
65
|
+
# http://www.postgresql.org/docs/current/static/libpq-connect.html for the
|
72
66
|
# list of parameters.
|
73
67
|
#
|
74
68
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
75
|
-
# See http://www.postgresql.org/docs/
|
69
|
+
# See http://www.postgresql.org/docs/current/static/libpq-envars.html .
|
76
70
|
class PostgreSQLAdapter < AbstractAdapter
|
77
71
|
ADAPTER_NAME = 'PostgreSQL'.freeze
|
78
72
|
|
79
73
|
NATIVE_DATABASE_TYPES = {
|
80
74
|
primary_key: "serial primary key",
|
81
|
-
bigserial: "bigserial",
|
82
75
|
string: { name: "character varying" },
|
83
76
|
text: { name: "text" },
|
84
77
|
integer: { name: "integer" },
|
@@ -95,7 +88,6 @@ module ActiveRecord
|
|
95
88
|
int8range: { name: "int8range" },
|
96
89
|
binary: { name: "bytea" },
|
97
90
|
boolean: { name: "boolean" },
|
98
|
-
bigint: { name: "bigint" },
|
99
91
|
xml: { name: "xml" },
|
100
92
|
tsvector: { name: "tsvector" },
|
101
93
|
hstore: { name: "hstore" },
|
@@ -108,6 +100,12 @@ module ActiveRecord
|
|
108
100
|
ltree: { name: "ltree" },
|
109
101
|
citext: { name: "citext" },
|
110
102
|
point: { name: "point" },
|
103
|
+
line: { name: "line" },
|
104
|
+
lseg: { name: "lseg" },
|
105
|
+
box: { name: "box" },
|
106
|
+
path: { name: "path" },
|
107
|
+
polygon: { name: "polygon" },
|
108
|
+
circle: { name: "circle" },
|
111
109
|
bit: { name: "bit" },
|
112
110
|
bit_varying: { name: "bit varying" },
|
113
111
|
money: { name: "money" },
|
@@ -119,27 +117,14 @@ module ActiveRecord
|
|
119
117
|
include PostgreSQL::ReferentialIntegrity
|
120
118
|
include PostgreSQL::SchemaStatements
|
121
119
|
include PostgreSQL::DatabaseStatements
|
120
|
+
include PostgreSQL::ColumnDumper
|
122
121
|
include Savepoints
|
123
122
|
|
124
123
|
def schema_creation # :nodoc:
|
125
124
|
PostgreSQL::SchemaCreation.new self
|
126
125
|
end
|
127
126
|
|
128
|
-
#
|
129
|
-
# AbstractAdapter
|
130
|
-
def prepare_column_options(column, types) # :nodoc:
|
131
|
-
spec = super
|
132
|
-
spec[:array] = 'true' if column.respond_to?(:array) && column.array
|
133
|
-
spec[:default] = "\"#{column.default_function}\"" if column.default_function
|
134
|
-
spec
|
135
|
-
end
|
136
|
-
|
137
|
-
# Adds +:array+ as a valid migration key
|
138
|
-
def migration_keys
|
139
|
-
super + [:array]
|
140
|
-
end
|
141
|
-
|
142
|
-
# Returns +true+, since this connection adapter supports prepared statement
|
127
|
+
# Returns true, since this connection adapter supports prepared statement
|
143
128
|
# caching.
|
144
129
|
def supports_statement_cache?
|
145
130
|
true
|
@@ -165,52 +150,35 @@ module ActiveRecord
|
|
165
150
|
true
|
166
151
|
end
|
167
152
|
|
153
|
+
def supports_datetime_with_precision?
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
def supports_json?
|
158
|
+
postgresql_version >= 90200
|
159
|
+
end
|
160
|
+
|
168
161
|
def index_algorithms
|
169
162
|
{ concurrently: 'CONCURRENTLY' }
|
170
163
|
end
|
171
164
|
|
172
165
|
class StatementPool < ConnectionAdapters::StatementPool
|
173
166
|
def initialize(connection, max)
|
174
|
-
super
|
167
|
+
super(max)
|
168
|
+
@connection = connection
|
175
169
|
@counter = 0
|
176
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
177
170
|
end
|
178
171
|
|
179
|
-
def each(&block); cache.each(&block); end
|
180
|
-
def key?(key); cache.key?(key); end
|
181
|
-
def [](key); cache[key]; end
|
182
|
-
def length; cache.length; end
|
183
|
-
|
184
172
|
def next_key
|
185
173
|
"a#{@counter + 1}"
|
186
174
|
end
|
187
175
|
|
188
176
|
def []=(sql, key)
|
189
|
-
|
190
|
-
dealloc(cache.shift.last)
|
191
|
-
end
|
192
|
-
@counter += 1
|
193
|
-
cache[sql] = key
|
194
|
-
end
|
195
|
-
|
196
|
-
def clear
|
197
|
-
cache.each_value do |stmt_key|
|
198
|
-
dealloc stmt_key
|
199
|
-
end
|
200
|
-
cache.clear
|
201
|
-
end
|
202
|
-
|
203
|
-
def delete(sql_key)
|
204
|
-
dealloc cache[sql_key]
|
205
|
-
cache.delete sql_key
|
177
|
+
super.tap { @counter += 1 }
|
206
178
|
end
|
207
179
|
|
208
180
|
private
|
209
181
|
|
210
|
-
def cache
|
211
|
-
@cache[Process.pid]
|
212
|
-
end
|
213
|
-
|
214
182
|
def dealloc(key)
|
215
183
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
216
184
|
end
|
@@ -224,22 +192,24 @@ module ActiveRecord
|
|
224
192
|
|
225
193
|
# Initializes and connects a PostgreSQL adapter.
|
226
194
|
def initialize(connection, logger, connection_parameters, config)
|
227
|
-
super(connection, logger)
|
195
|
+
super(connection, logger, config)
|
228
196
|
|
229
197
|
@visitor = Arel::Visitors::PostgreSQL.new self
|
230
198
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
231
199
|
@prepared_statements = true
|
200
|
+
@visitor.extend(DetermineIfPreparableVisitor)
|
232
201
|
else
|
233
202
|
@prepared_statements = false
|
234
203
|
end
|
235
204
|
|
236
|
-
@connection_parameters
|
205
|
+
@connection_parameters = connection_parameters
|
237
206
|
|
238
207
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
239
208
|
@local_tz = nil
|
240
209
|
@table_alias_length = nil
|
241
210
|
|
242
211
|
connect
|
212
|
+
add_pg_encoders
|
243
213
|
@statements = StatementPool.new @connection,
|
244
214
|
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })
|
245
215
|
|
@@ -247,6 +217,8 @@ module ActiveRecord
|
|
247
217
|
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
|
248
218
|
end
|
249
219
|
|
220
|
+
add_pg_decoders
|
221
|
+
|
250
222
|
@type_map = Type::HashLookupTypeMap.new
|
251
223
|
initialize_type_map(type_map)
|
252
224
|
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
|
@@ -316,6 +288,10 @@ module ActiveRecord
|
|
316
288
|
true
|
317
289
|
end
|
318
290
|
|
291
|
+
def supports_advisory_locks?
|
292
|
+
true
|
293
|
+
end
|
294
|
+
|
319
295
|
def supports_explain?
|
320
296
|
true
|
321
297
|
end
|
@@ -334,6 +310,20 @@ module ActiveRecord
|
|
334
310
|
postgresql_version >= 90300
|
335
311
|
end
|
336
312
|
|
313
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
314
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
315
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
316
|
+
end
|
317
|
+
select_value("SELECT pg_try_advisory_lock(#{lock_id});")
|
318
|
+
end
|
319
|
+
|
320
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
321
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
322
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
323
|
+
end
|
324
|
+
select_value("SELECT pg_advisory_unlock(#{lock_id})")
|
325
|
+
end
|
326
|
+
|
337
327
|
def enable_extension(name)
|
338
328
|
exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
|
339
329
|
reload_type_map
|
@@ -407,7 +397,7 @@ module ActiveRecord
|
|
407
397
|
@connection.server_version
|
408
398
|
end
|
409
399
|
|
410
|
-
# See http://www.postgresql.org/docs/
|
400
|
+
# See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
411
401
|
FOREIGN_KEY_VIOLATION = "23503"
|
412
402
|
UNIQUE_VIOLATION = "23505"
|
413
403
|
|
@@ -416,9 +406,9 @@ module ActiveRecord
|
|
416
406
|
|
417
407
|
case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
|
418
408
|
when UNIQUE_VIOLATION
|
419
|
-
RecordNotUnique.new(message
|
409
|
+
RecordNotUnique.new(message)
|
420
410
|
when FOREIGN_KEY_VIOLATION
|
421
|
-
InvalidForeignKey.new(message
|
411
|
+
InvalidForeignKey.new(message)
|
422
412
|
else
|
423
413
|
super
|
424
414
|
end
|
@@ -440,11 +430,11 @@ module ActiveRecord
|
|
440
430
|
end
|
441
431
|
|
442
432
|
def initialize_type_map(m) # :nodoc:
|
443
|
-
register_class_with_limit m, 'int2',
|
444
|
-
register_class_with_limit m, 'int4',
|
445
|
-
register_class_with_limit m, 'int8',
|
433
|
+
register_class_with_limit m, 'int2', Type::Integer
|
434
|
+
register_class_with_limit m, 'int4', Type::Integer
|
435
|
+
register_class_with_limit m, 'int8', Type::Integer
|
446
436
|
m.alias_type 'oid', 'int2'
|
447
|
-
m.register_type 'float4',
|
437
|
+
m.register_type 'float4', Type::Float.new
|
448
438
|
m.alias_type 'float8', 'float4'
|
449
439
|
m.register_type 'text', Type::Text.new
|
450
440
|
register_class_with_limit m, 'varchar', Type::String
|
@@ -455,8 +445,7 @@ module ActiveRecord
|
|
455
445
|
register_class_with_limit m, 'bit', OID::Bit
|
456
446
|
register_class_with_limit m, 'varbit', OID::BitVarying
|
457
447
|
m.alias_type 'timestamptz', 'timestamp'
|
458
|
-
m.register_type 'date',
|
459
|
-
m.register_type 'time', OID::Time.new
|
448
|
+
m.register_type 'date', Type::Date.new
|
460
449
|
|
461
450
|
m.register_type 'money', OID::Money.new
|
462
451
|
m.register_type 'bytea', OID::Bytea.new
|
@@ -472,20 +461,18 @@ module ActiveRecord
|
|
472
461
|
m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
|
473
462
|
m.register_type 'citext', OID::SpecializedString.new(:citext)
|
474
463
|
m.register_type 'ltree', OID::SpecializedString.new(:ltree)
|
464
|
+
m.register_type 'line', OID::SpecializedString.new(:line)
|
465
|
+
m.register_type 'lseg', OID::SpecializedString.new(:lseg)
|
466
|
+
m.register_type 'box', OID::SpecializedString.new(:box)
|
467
|
+
m.register_type 'path', OID::SpecializedString.new(:path)
|
468
|
+
m.register_type 'polygon', OID::SpecializedString.new(:polygon)
|
469
|
+
m.register_type 'circle', OID::SpecializedString.new(:circle)
|
475
470
|
|
476
471
|
# FIXME: why are we keeping these types as strings?
|
477
472
|
m.alias_type 'interval', 'varchar'
|
478
|
-
|
479
|
-
m
|
480
|
-
m
|
481
|
-
m.alias_type 'circle', 'varchar'
|
482
|
-
m.alias_type 'lseg', 'varchar'
|
483
|
-
m.alias_type 'box', 'varchar'
|
484
|
-
|
485
|
-
m.register_type 'timestamp' do |_, _, sql_type|
|
486
|
-
precision = extract_precision(sql_type)
|
487
|
-
OID::DateTime.new(precision: precision)
|
488
|
-
end
|
473
|
+
|
474
|
+
register_class_with_precision m, 'time', Type::Time
|
475
|
+
register_class_with_precision m, 'timestamp', OID::DateTime
|
489
476
|
|
490
477
|
m.register_type 'numeric' do |_, fmod, sql_type|
|
491
478
|
precision = extract_precision(sql_type)
|
@@ -522,13 +509,13 @@ module ActiveRecord
|
|
522
509
|
end
|
523
510
|
|
524
511
|
# Extracts the value from a PostgreSQL column default definition.
|
525
|
-
def extract_value_from_default(
|
512
|
+
def extract_value_from_default(default) # :nodoc:
|
526
513
|
case default
|
527
514
|
# Quoted types
|
528
515
|
when /\A[\(B]?'(.*)'::/m
|
529
|
-
$1.gsub(
|
516
|
+
$1.gsub("''".freeze, "'".freeze)
|
530
517
|
# Boolean types
|
531
|
-
when 'true', 'false'
|
518
|
+
when 'true'.freeze, 'false'.freeze
|
532
519
|
default
|
533
520
|
# Numeric types
|
534
521
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -580,29 +567,33 @@ module ActiveRecord
|
|
580
567
|
|
581
568
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
582
569
|
|
583
|
-
def execute_and_clear(sql, name, binds)
|
584
|
-
|
585
|
-
|
570
|
+
def execute_and_clear(sql, name, binds, prepare: false)
|
571
|
+
if without_prepared_statement?(binds)
|
572
|
+
result = exec_no_cache(sql, name, [])
|
573
|
+
elsif !prepare
|
574
|
+
result = exec_no_cache(sql, name, binds)
|
575
|
+
else
|
576
|
+
result = exec_cache(sql, name, binds)
|
577
|
+
end
|
586
578
|
ret = yield result
|
587
579
|
result.clear
|
588
580
|
ret
|
589
581
|
end
|
590
582
|
|
591
583
|
def exec_no_cache(sql, name, binds)
|
592
|
-
|
584
|
+
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
585
|
+
log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) }
|
593
586
|
end
|
594
587
|
|
595
588
|
def exec_cache(sql, name, binds)
|
596
589
|
stmt_key = prepare_statement(sql)
|
597
|
-
type_casted_binds = binds.map { |
|
598
|
-
[col, type_cast(val, col)]
|
599
|
-
}
|
590
|
+
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
600
591
|
|
601
|
-
log(sql, name,
|
602
|
-
@connection.exec_prepared(stmt_key, type_casted_binds
|
592
|
+
log(sql, name, binds, stmt_key) do
|
593
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
603
594
|
end
|
604
595
|
rescue ActiveRecord::StatementInvalid => e
|
605
|
-
pgerror = e.
|
596
|
+
pgerror = e.cause
|
606
597
|
|
607
598
|
# Get the PG code for the failure. Annoyingly, the code for
|
608
599
|
# prepared statements whose return value may have changed is
|
@@ -658,7 +649,7 @@ module ActiveRecord
|
|
658
649
|
configure_connection
|
659
650
|
rescue ::PG::Error => error
|
660
651
|
if error.message.include?("does not exist")
|
661
|
-
raise ActiveRecord::NoDatabaseError
|
652
|
+
raise ActiveRecord::NoDatabaseError
|
662
653
|
else
|
663
654
|
raise
|
664
655
|
end
|
@@ -686,7 +677,7 @@ module ActiveRecord
|
|
686
677
|
end
|
687
678
|
|
688
679
|
# SET statements from :variables config hash
|
689
|
-
# http://www.postgresql.org/docs/
|
680
|
+
# http://www.postgresql.org/docs/current/static/sql-set.html
|
690
681
|
variables = @config[:variables] || {}
|
691
682
|
variables.map do |k, v|
|
692
683
|
if v == ':default' || v == :default
|
@@ -730,9 +721,11 @@ module ActiveRecord
|
|
730
721
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
731
722
|
# - ::regclass is a function that gives the id for a table name
|
732
723
|
def column_definitions(table_name) # :nodoc:
|
733
|
-
|
724
|
+
query(<<-end_sql, 'SCHEMA')
|
734
725
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
735
|
-
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
|
726
|
+
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
727
|
+
(SELECT c.collname FROM pg_collation c, pg_type t
|
728
|
+
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation)
|
736
729
|
FROM pg_attribute a LEFT JOIN pg_attrdef d
|
737
730
|
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
738
731
|
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
|
@@ -742,13 +735,92 @@ module ActiveRecord
|
|
742
735
|
end
|
743
736
|
|
744
737
|
def extract_table_ref_from_insert_sql(sql) # :nodoc:
|
745
|
-
sql[/into\s
|
738
|
+
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
746
739
|
$1.strip if $1
|
747
740
|
end
|
748
741
|
|
749
|
-
def create_table_definition(name, temporary, options, as = nil) # :nodoc:
|
750
|
-
PostgreSQL::TableDefinition.new
|
742
|
+
def create_table_definition(name, temporary = false, options = nil, as = nil) # :nodoc:
|
743
|
+
PostgreSQL::TableDefinition.new(name, temporary, options, as)
|
744
|
+
end
|
745
|
+
|
746
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
747
|
+
@case_insensitive_cache ||= {}
|
748
|
+
@case_insensitive_cache[column.sql_type] ||= begin
|
749
|
+
sql = <<-end_sql
|
750
|
+
SELECT exists(
|
751
|
+
SELECT * FROM pg_proc
|
752
|
+
INNER JOIN pg_cast
|
753
|
+
ON casttarget::text::oidvector = proargtypes
|
754
|
+
WHERE proname = 'lower'
|
755
|
+
AND castsource = '#{column.sql_type}'::regtype::oid
|
756
|
+
)
|
757
|
+
end_sql
|
758
|
+
execute_and_clear(sql, "SCHEMA", []) do |result|
|
759
|
+
result.getvalue(0, 0)
|
760
|
+
end
|
761
|
+
end
|
751
762
|
end
|
763
|
+
|
764
|
+
def add_pg_encoders
|
765
|
+
map = PG::TypeMapByClass.new
|
766
|
+
map[Integer] = PG::TextEncoder::Integer.new
|
767
|
+
map[TrueClass] = PG::TextEncoder::Boolean.new
|
768
|
+
map[FalseClass] = PG::TextEncoder::Boolean.new
|
769
|
+
map[Float] = PG::TextEncoder::Float.new
|
770
|
+
@connection.type_map_for_queries = map
|
771
|
+
end
|
772
|
+
|
773
|
+
def add_pg_decoders
|
774
|
+
coders_by_name = {
|
775
|
+
'int2' => PG::TextDecoder::Integer,
|
776
|
+
'int4' => PG::TextDecoder::Integer,
|
777
|
+
'int8' => PG::TextDecoder::Integer,
|
778
|
+
'oid' => PG::TextDecoder::Integer,
|
779
|
+
'float4' => PG::TextDecoder::Float,
|
780
|
+
'float8' => PG::TextDecoder::Float,
|
781
|
+
'bool' => PG::TextDecoder::Boolean,
|
782
|
+
}
|
783
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
784
|
+
query = <<-SQL % known_coder_types.join(", ")
|
785
|
+
SELECT t.oid, t.typname
|
786
|
+
FROM pg_type as t
|
787
|
+
WHERE t.typname IN (%s)
|
788
|
+
SQL
|
789
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
790
|
+
result
|
791
|
+
.map { |row| construct_coder(row, coders_by_name[row['typname']]) }
|
792
|
+
.compact
|
793
|
+
end
|
794
|
+
|
795
|
+
map = PG::TypeMapByOid.new
|
796
|
+
coders.each { |coder| map.add_coder(coder) }
|
797
|
+
@connection.type_map_for_results = map
|
798
|
+
end
|
799
|
+
|
800
|
+
def construct_coder(row, coder_class)
|
801
|
+
return unless coder_class
|
802
|
+
coder_class.new(oid: row['oid'].to_i, name: row['typname'])
|
803
|
+
end
|
804
|
+
|
805
|
+
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
806
|
+
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
807
|
+
ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
|
808
|
+
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
|
809
|
+
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
|
810
|
+
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
|
811
|
+
ActiveRecord::Type.register(:date_time, OID::DateTime, adapter: :postgresql)
|
812
|
+
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
|
813
|
+
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
814
|
+
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
815
|
+
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
816
|
+
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
|
817
|
+
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
818
|
+
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
819
|
+
ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
|
820
|
+
ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
|
821
|
+
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
|
822
|
+
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
|
823
|
+
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
|
752
824
|
end
|
753
825
|
end
|
754
826
|
end
|