activerecord 4.2.11.3 → 5.0.7.2
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 +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- 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/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- 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 +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -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 -4
- 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 +31 -17
- 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 +56 -19
- 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 +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- 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/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- 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 +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- 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 +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -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/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- 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 +15 -14
- data/lib/active_record/type/time.rb +10 -16
- 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 +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- 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
|
@@ -19,9 +19,9 @@ module ActiveRecord
|
|
19
19
|
|
20
20
|
def quoted
|
21
21
|
if schema
|
22
|
-
|
22
|
+
PG::Connection.quote_ident(schema) << SEPARATOR << PG::Connection.quote_ident(identifier)
|
23
23
|
else
|
24
|
-
|
24
|
+
PG::Connection.quote_ident(identifier)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -1,31 +1,23 @@
|
|
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", "< 2.0"
|
17
3
|
require 'pg'
|
18
4
|
|
19
|
-
require
|
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/explain_pretty_printer"
|
9
|
+
require "active_record/connection_adapters/postgresql/oid"
|
10
|
+
require "active_record/connection_adapters/postgresql/quoting"
|
11
|
+
require "active_record/connection_adapters/postgresql/referential_integrity"
|
12
|
+
require "active_record/connection_adapters/postgresql/schema_definitions"
|
13
|
+
require "active_record/connection_adapters/postgresql/schema_dumper"
|
14
|
+
require "active_record/connection_adapters/postgresql/schema_statements"
|
15
|
+
require "active_record/connection_adapters/postgresql/type_metadata"
|
16
|
+
require "active_record/connection_adapters/postgresql/utils"
|
17
|
+
require "active_record/connection_adapters/statement_pool"
|
20
18
|
|
21
19
|
module ActiveRecord
|
22
20
|
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
21
|
# Establishes a connection to the database that's used by all Active Record objects
|
30
22
|
def postgresql_connection(config)
|
31
23
|
conn_params = config.symbolize_keys
|
@@ -36,10 +28,11 @@ module ActiveRecord
|
|
36
28
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
37
29
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
38
30
|
|
39
|
-
# Forward only valid config params to
|
40
|
-
|
31
|
+
# Forward only valid config params to PG::Connection.connect.
|
32
|
+
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
33
|
+
conn_params.slice!(*valid_conn_param_keys)
|
41
34
|
|
42
|
-
# The postgres drivers don't allow the creation of an unconnected
|
35
|
+
# The postgres drivers don't allow the creation of an unconnected PG::Connection object,
|
43
36
|
# so just pass a nil connection object for the time being.
|
44
37
|
ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
|
45
38
|
end
|
@@ -68,17 +61,16 @@ module ActiveRecord
|
|
68
61
|
# defaults to true.
|
69
62
|
#
|
70
63
|
# Any further options are used as connection parameters to libpq. See
|
71
|
-
# http://www.postgresql.org/docs/
|
64
|
+
# http://www.postgresql.org/docs/current/static/libpq-connect.html for the
|
72
65
|
# list of parameters.
|
73
66
|
#
|
74
67
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
75
|
-
# See http://www.postgresql.org/docs/
|
68
|
+
# See http://www.postgresql.org/docs/current/static/libpq-envars.html .
|
76
69
|
class PostgreSQLAdapter < AbstractAdapter
|
77
70
|
ADAPTER_NAME = 'PostgreSQL'.freeze
|
78
71
|
|
79
72
|
NATIVE_DATABASE_TYPES = {
|
80
73
|
primary_key: "serial primary key",
|
81
|
-
bigserial: "bigserial",
|
82
74
|
string: { name: "character varying" },
|
83
75
|
text: { name: "text" },
|
84
76
|
integer: { name: "integer" },
|
@@ -95,7 +87,6 @@ module ActiveRecord
|
|
95
87
|
int8range: { name: "int8range" },
|
96
88
|
binary: { name: "bytea" },
|
97
89
|
boolean: { name: "boolean" },
|
98
|
-
bigint: { name: "bigint" },
|
99
90
|
xml: { name: "xml" },
|
100
91
|
tsvector: { name: "tsvector" },
|
101
92
|
hstore: { name: "hstore" },
|
@@ -108,6 +99,12 @@ module ActiveRecord
|
|
108
99
|
ltree: { name: "ltree" },
|
109
100
|
citext: { name: "citext" },
|
110
101
|
point: { name: "point" },
|
102
|
+
line: { name: "line" },
|
103
|
+
lseg: { name: "lseg" },
|
104
|
+
box: { name: "box" },
|
105
|
+
path: { name: "path" },
|
106
|
+
polygon: { name: "polygon" },
|
107
|
+
circle: { name: "circle" },
|
111
108
|
bit: { name: "bit" },
|
112
109
|
bit_varying: { name: "bit varying" },
|
113
110
|
money: { name: "money" },
|
@@ -119,27 +116,17 @@ module ActiveRecord
|
|
119
116
|
include PostgreSQL::ReferentialIntegrity
|
120
117
|
include PostgreSQL::SchemaStatements
|
121
118
|
include PostgreSQL::DatabaseStatements
|
122
|
-
include
|
119
|
+
include PostgreSQL::ColumnDumper
|
123
120
|
|
124
121
|
def schema_creation # :nodoc:
|
125
122
|
PostgreSQL::SchemaCreation.new self
|
126
123
|
end
|
127
124
|
|
128
|
-
|
129
|
-
|
130
|
-
def prepare_column_options(column, types) # :nodoc:
|
131
|
-
spec = super
|
132
|
-
spec[:array] = 'true' if column.respond_to?(:array) && column.array
|
133
|
-
spec[:default] = "\"#{column.default_function}\"" if column.default_function
|
134
|
-
spec
|
135
|
-
end
|
136
|
-
|
137
|
-
# Adds +:array+ as a valid migration key
|
138
|
-
def migration_keys
|
139
|
-
super + [:array]
|
125
|
+
def arel_visitor # :nodoc:
|
126
|
+
Arel::Visitors::PostgreSQL.new(self)
|
140
127
|
end
|
141
128
|
|
142
|
-
# Returns
|
129
|
+
# Returns true, since this connection adapter supports prepared statement
|
143
130
|
# caching.
|
144
131
|
def supports_statement_cache?
|
145
132
|
true
|
@@ -153,6 +140,10 @@ module ActiveRecord
|
|
153
140
|
true
|
154
141
|
end
|
155
142
|
|
143
|
+
def supports_expression_index?
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
156
147
|
def supports_transaction_isolation?
|
157
148
|
true
|
158
149
|
end
|
@@ -165,88 +156,75 @@ module ActiveRecord
|
|
165
156
|
true
|
166
157
|
end
|
167
158
|
|
159
|
+
def supports_datetime_with_precision?
|
160
|
+
true
|
161
|
+
end
|
162
|
+
|
163
|
+
def supports_json?
|
164
|
+
postgresql_version >= 90200
|
165
|
+
end
|
166
|
+
|
167
|
+
def supports_comments?
|
168
|
+
true
|
169
|
+
end
|
170
|
+
|
171
|
+
def supports_savepoints?
|
172
|
+
true
|
173
|
+
end
|
174
|
+
|
168
175
|
def index_algorithms
|
169
176
|
{ concurrently: 'CONCURRENTLY' }
|
170
177
|
end
|
171
178
|
|
172
179
|
class StatementPool < ConnectionAdapters::StatementPool
|
173
180
|
def initialize(connection, max)
|
174
|
-
super
|
181
|
+
super(max)
|
182
|
+
@connection = connection
|
175
183
|
@counter = 0
|
176
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
177
184
|
end
|
178
185
|
|
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
186
|
def next_key
|
185
187
|
"a#{@counter + 1}"
|
186
188
|
end
|
187
189
|
|
188
190
|
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
|
191
|
+
super.tap { @counter += 1 }
|
206
192
|
end
|
207
193
|
|
208
194
|
private
|
209
195
|
|
210
|
-
def cache
|
211
|
-
@cache[Process.pid]
|
212
|
-
end
|
213
|
-
|
214
196
|
def dealloc(key)
|
215
197
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
216
198
|
end
|
217
199
|
|
218
200
|
def connection_active?
|
219
|
-
@connection.status ==
|
220
|
-
rescue
|
201
|
+
@connection.status == PG::CONNECTION_OK
|
202
|
+
rescue PG::Error
|
221
203
|
false
|
222
204
|
end
|
223
205
|
end
|
224
206
|
|
225
207
|
# Initializes and connects a PostgreSQL adapter.
|
226
208
|
def initialize(connection, logger, connection_parameters, config)
|
227
|
-
super(connection, logger)
|
209
|
+
super(connection, logger, config)
|
228
210
|
|
229
|
-
@
|
230
|
-
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
231
|
-
@prepared_statements = true
|
232
|
-
else
|
233
|
-
@prepared_statements = false
|
234
|
-
end
|
235
|
-
|
236
|
-
@connection_parameters, @config = connection_parameters, config
|
211
|
+
@connection_parameters = connection_parameters
|
237
212
|
|
238
213
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
239
214
|
@local_tz = nil
|
240
|
-
@
|
215
|
+
@max_identifier_length = nil
|
241
216
|
|
242
217
|
connect
|
218
|
+
add_pg_encoders
|
243
219
|
@statements = StatementPool.new @connection,
|
244
|
-
self.class.type_cast_config_to_integer(config
|
220
|
+
self.class.type_cast_config_to_integer(config[:statement_limit])
|
245
221
|
|
246
|
-
if postgresql_version <
|
247
|
-
raise "Your version of PostgreSQL (#{postgresql_version}) is too old
|
222
|
+
if postgresql_version < 90100
|
223
|
+
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
|
248
224
|
end
|
249
225
|
|
226
|
+
add_pg_decoders
|
227
|
+
|
250
228
|
@type_map = Type::HashLookupTypeMap.new
|
251
229
|
initialize_type_map(type_map)
|
252
230
|
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
|
@@ -266,7 +244,7 @@ module ActiveRecord
|
|
266
244
|
def active?
|
267
245
|
@connection.query 'SELECT 1'
|
268
246
|
true
|
269
|
-
rescue
|
247
|
+
rescue PG::Error
|
270
248
|
false
|
271
249
|
end
|
272
250
|
|
@@ -316,13 +294,16 @@ module ActiveRecord
|
|
316
294
|
true
|
317
295
|
end
|
318
296
|
|
297
|
+
def supports_advisory_locks?
|
298
|
+
true
|
299
|
+
end
|
300
|
+
|
319
301
|
def supports_explain?
|
320
302
|
true
|
321
303
|
end
|
322
304
|
|
323
|
-
# Returns true if pg > 9.1
|
324
305
|
def supports_extensions?
|
325
|
-
|
306
|
+
true
|
326
307
|
end
|
327
308
|
|
328
309
|
# Range datatypes weren't introduced until PostgreSQL 9.2
|
@@ -334,6 +315,20 @@ module ActiveRecord
|
|
334
315
|
postgresql_version >= 90300
|
335
316
|
end
|
336
317
|
|
318
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
319
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
320
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
321
|
+
end
|
322
|
+
select_value("SELECT pg_try_advisory_lock(#{lock_id});")
|
323
|
+
end
|
324
|
+
|
325
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
326
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
327
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
328
|
+
end
|
329
|
+
select_value("SELECT pg_advisory_unlock(#{lock_id})")
|
330
|
+
end
|
331
|
+
|
337
332
|
def enable_extension(name)
|
338
333
|
exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
|
339
334
|
reload_type_map
|
@@ -363,9 +358,11 @@ module ActiveRecord
|
|
363
358
|
end
|
364
359
|
|
365
360
|
# Returns the configured supported identifier length supported by PostgreSQL
|
366
|
-
def
|
367
|
-
@
|
361
|
+
def max_identifier_length
|
362
|
+
@max_identifier_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
|
368
363
|
end
|
364
|
+
alias table_alias_length max_identifier_length
|
365
|
+
alias index_name_length max_identifier_length
|
369
366
|
|
370
367
|
# Set the authorized user for this session
|
371
368
|
def session_auth=(user)
|
@@ -400,25 +397,28 @@ module ActiveRecord
|
|
400
397
|
"average" => "avg",
|
401
398
|
}
|
402
399
|
|
403
|
-
|
400
|
+
# Returns the version of the connected PostgreSQL server.
|
401
|
+
def postgresql_version
|
402
|
+
@connection.server_version
|
403
|
+
end
|
404
404
|
|
405
|
-
|
406
|
-
def postgresql_version
|
407
|
-
@connection.server_version
|
408
|
-
end
|
405
|
+
protected
|
409
406
|
|
410
|
-
# See http://www.postgresql.org/docs/
|
407
|
+
# See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
408
|
+
VALUE_LIMIT_VIOLATION = "22001"
|
411
409
|
FOREIGN_KEY_VIOLATION = "23503"
|
412
410
|
UNIQUE_VIOLATION = "23505"
|
413
411
|
|
414
412
|
def translate_exception(exception, message)
|
415
413
|
return exception unless exception.respond_to?(:result)
|
416
414
|
|
417
|
-
case exception.result.try(:error_field,
|
415
|
+
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
418
416
|
when UNIQUE_VIOLATION
|
419
|
-
RecordNotUnique.new(message
|
417
|
+
RecordNotUnique.new(message)
|
420
418
|
when FOREIGN_KEY_VIOLATION
|
421
|
-
InvalidForeignKey.new(message
|
419
|
+
InvalidForeignKey.new(message)
|
420
|
+
when VALUE_LIMIT_VIOLATION
|
421
|
+
ValueTooLong.new(message)
|
422
422
|
else
|
423
423
|
super
|
424
424
|
end
|
@@ -440,11 +440,11 @@ module ActiveRecord
|
|
440
440
|
end
|
441
441
|
|
442
442
|
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',
|
443
|
+
register_class_with_limit m, 'int2', Type::Integer
|
444
|
+
register_class_with_limit m, 'int4', Type::Integer
|
445
|
+
register_class_with_limit m, 'int8', Type::Integer
|
446
446
|
m.alias_type 'oid', 'int2'
|
447
|
-
m.register_type 'float4',
|
447
|
+
m.register_type 'float4', Type::Float.new
|
448
448
|
m.alias_type 'float8', 'float4'
|
449
449
|
m.register_type 'text', Type::Text.new
|
450
450
|
register_class_with_limit m, 'varchar', Type::String
|
@@ -455,8 +455,7 @@ module ActiveRecord
|
|
455
455
|
register_class_with_limit m, 'bit', OID::Bit
|
456
456
|
register_class_with_limit m, 'varbit', OID::BitVarying
|
457
457
|
m.alias_type 'timestamptz', 'timestamp'
|
458
|
-
m.register_type 'date',
|
459
|
-
m.register_type 'time', OID::Time.new
|
458
|
+
m.register_type 'date', Type::Date.new
|
460
459
|
|
461
460
|
m.register_type 'money', OID::Money.new
|
462
461
|
m.register_type 'bytea', OID::Bytea.new
|
@@ -472,20 +471,18 @@ module ActiveRecord
|
|
472
471
|
m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
|
473
472
|
m.register_type 'citext', OID::SpecializedString.new(:citext)
|
474
473
|
m.register_type 'ltree', OID::SpecializedString.new(:ltree)
|
474
|
+
m.register_type 'line', OID::SpecializedString.new(:line)
|
475
|
+
m.register_type 'lseg', OID::SpecializedString.new(:lseg)
|
476
|
+
m.register_type 'box', OID::SpecializedString.new(:box)
|
477
|
+
m.register_type 'path', OID::SpecializedString.new(:path)
|
478
|
+
m.register_type 'polygon', OID::SpecializedString.new(:polygon)
|
479
|
+
m.register_type 'circle', OID::SpecializedString.new(:circle)
|
475
480
|
|
476
481
|
# FIXME: why are we keeping these types as strings?
|
477
482
|
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
|
483
|
+
|
484
|
+
register_class_with_precision m, 'time', Type::Time
|
485
|
+
register_class_with_precision m, 'timestamp', OID::DateTime
|
489
486
|
|
490
487
|
m.register_type 'numeric' do |_, fmod, sql_type|
|
491
488
|
precision = extract_precision(sql_type)
|
@@ -522,13 +519,18 @@ module ActiveRecord
|
|
522
519
|
end
|
523
520
|
|
524
521
|
# Extracts the value from a PostgreSQL column default definition.
|
525
|
-
def extract_value_from_default(
|
522
|
+
def extract_value_from_default(default) # :nodoc:
|
526
523
|
case default
|
527
524
|
# Quoted types
|
528
|
-
when /\A[\(B]?'(.*)'
|
529
|
-
|
525
|
+
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
526
|
+
# The default 'now'::date is CURRENT_DATE
|
527
|
+
if $1 == "now".freeze && $2 == "date".freeze
|
528
|
+
nil
|
529
|
+
else
|
530
|
+
$1.gsub("''".freeze, "'".freeze)
|
531
|
+
end
|
530
532
|
# Boolean types
|
531
|
-
when 'true', 'false'
|
533
|
+
when 'true'.freeze, 'false'.freeze
|
532
534
|
default
|
533
535
|
# Numeric types
|
534
536
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -548,7 +550,7 @@ module ActiveRecord
|
|
548
550
|
end
|
549
551
|
|
550
552
|
def has_default_function?(default_value, default) # :nodoc:
|
551
|
-
!default_value && (%r{\w+\(.*\)} === default)
|
553
|
+
!default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
|
552
554
|
end
|
553
555
|
|
554
556
|
def load_additional_types(type_map, oids = nil) # :nodoc:
|
@@ -580,47 +582,67 @@ module ActiveRecord
|
|
580
582
|
|
581
583
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
582
584
|
|
583
|
-
def execute_and_clear(sql, name, binds)
|
584
|
-
|
585
|
-
|
585
|
+
def execute_and_clear(sql, name, binds, prepare: false)
|
586
|
+
if without_prepared_statement?(binds)
|
587
|
+
result = exec_no_cache(sql, name, [])
|
588
|
+
elsif !prepare
|
589
|
+
result = exec_no_cache(sql, name, binds)
|
590
|
+
else
|
591
|
+
result = exec_cache(sql, name, binds)
|
592
|
+
end
|
586
593
|
ret = yield result
|
587
594
|
result.clear
|
588
595
|
ret
|
589
596
|
end
|
590
597
|
|
591
598
|
def exec_no_cache(sql, name, binds)
|
592
|
-
|
599
|
+
type_casted_binds = type_casted_binds(binds)
|
600
|
+
log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
|
593
601
|
end
|
594
602
|
|
595
603
|
def exec_cache(sql, name, binds)
|
596
604
|
stmt_key = prepare_statement(sql)
|
597
|
-
type_casted_binds = binds
|
598
|
-
[col, type_cast(val, col)]
|
599
|
-
}
|
605
|
+
type_casted_binds = type_casted_binds(binds)
|
600
606
|
|
601
|
-
log(sql, name, type_casted_binds, stmt_key) do
|
602
|
-
@connection.exec_prepared(stmt_key, type_casted_binds
|
607
|
+
log(sql, name, binds, type_casted_binds, stmt_key) do
|
608
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
603
609
|
end
|
604
610
|
rescue ActiveRecord::StatementInvalid => e
|
605
|
-
|
606
|
-
|
607
|
-
#
|
608
|
-
#
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
rescue
|
614
|
-
raise e
|
615
|
-
end
|
616
|
-
if FEATURE_NOT_SUPPORTED == code
|
611
|
+
raise unless is_cached_plan_failure?(e)
|
612
|
+
|
613
|
+
# Nothing we can do if we are in a transaction because all commands
|
614
|
+
# will raise InFailedSQLTransaction
|
615
|
+
if in_transaction?
|
616
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
617
|
+
else
|
618
|
+
# outside of transactions we can simply flush this query and retry
|
617
619
|
@statements.delete sql_key(sql)
|
618
620
|
retry
|
619
|
-
else
|
620
|
-
raise e
|
621
621
|
end
|
622
622
|
end
|
623
623
|
|
624
|
+
# Annoyingly, the code for prepared statements whose return value may
|
625
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
626
|
+
#
|
627
|
+
# This covers various different error types so we need to do additional
|
628
|
+
# work to classify the exception definitively as a
|
629
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
630
|
+
#
|
631
|
+
# Check here for more details:
|
632
|
+
# http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
633
|
+
CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
|
634
|
+
def is_cached_plan_failure?(e)
|
635
|
+
pgerror = e.cause
|
636
|
+
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
637
|
+
code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
|
638
|
+
rescue
|
639
|
+
false
|
640
|
+
end
|
641
|
+
|
642
|
+
def in_transaction?
|
643
|
+
open_transactions > 0
|
644
|
+
end
|
645
|
+
|
624
646
|
# Returns the statement identifier for the client side cache
|
625
647
|
# of statements
|
626
648
|
def sql_key(sql)
|
@@ -648,17 +670,11 @@ module ActiveRecord
|
|
648
670
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
649
671
|
# connected server's characteristics.
|
650
672
|
def connect
|
651
|
-
@connection =
|
652
|
-
|
653
|
-
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
|
654
|
-
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
|
655
|
-
# should know about this but can't detect it there, so deal with it here.
|
656
|
-
OID::Money.precision = (postgresql_version >= 80300) ? 19 : 10
|
657
|
-
|
673
|
+
@connection = PG.connect(@connection_parameters)
|
658
674
|
configure_connection
|
659
675
|
rescue ::PG::Error => error
|
660
676
|
if error.message.include?("does not exist")
|
661
|
-
raise ActiveRecord::NoDatabaseError
|
677
|
+
raise ActiveRecord::NoDatabaseError
|
662
678
|
else
|
663
679
|
raise
|
664
680
|
end
|
@@ -686,7 +702,7 @@ module ActiveRecord
|
|
686
702
|
end
|
687
703
|
|
688
704
|
# SET statements from :variables config hash
|
689
|
-
# http://www.postgresql.org/docs/
|
705
|
+
# http://www.postgresql.org/docs/current/static/sql-set.html
|
690
706
|
variables = @config[:variables] || {}
|
691
707
|
variables.map do |k, v|
|
692
708
|
if v == ':default' || v == :default
|
@@ -699,22 +715,14 @@ module ActiveRecord
|
|
699
715
|
end
|
700
716
|
|
701
717
|
# Returns the current ID of a table's sequence.
|
702
|
-
def
|
703
|
-
Integer(last_insert_id_value(sequence_name))
|
704
|
-
end
|
705
|
-
|
706
|
-
def last_insert_id_value(sequence_name)
|
707
|
-
last_insert_id_result(sequence_name).rows.first.first
|
708
|
-
end
|
709
|
-
|
710
|
-
def last_insert_id_result(sequence_name) #:nodoc:
|
718
|
+
def last_insert_id_result(sequence_name) # :nodoc:
|
711
719
|
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
|
712
720
|
end
|
713
721
|
|
714
722
|
# Returns the list of a table's column names, data types, and default values.
|
715
723
|
#
|
716
724
|
# The underlying query is roughly:
|
717
|
-
# SELECT column.name, column.type, default.value
|
725
|
+
# SELECT column.name, column.type, default.value, column.comment
|
718
726
|
# FROM column LEFT JOIN default
|
719
727
|
# ON column.table_id = default.table_id
|
720
728
|
# AND column.num = default.column_num
|
@@ -730,9 +738,12 @@ module ActiveRecord
|
|
730
738
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
731
739
|
# - ::regclass is a function that gives the id for a table name
|
732
740
|
def column_definitions(table_name) # :nodoc:
|
733
|
-
|
741
|
+
query(<<-end_sql, 'SCHEMA')
|
734
742
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
735
|
-
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
|
743
|
+
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
744
|
+
(SELECT c.collname FROM pg_collation c, pg_type t
|
745
|
+
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
|
746
|
+
col_description(a.attrelid, a.attnum) AS comment
|
736
747
|
FROM pg_attribute a LEFT JOIN pg_attrdef d
|
737
748
|
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
738
749
|
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
|
@@ -742,13 +753,96 @@ module ActiveRecord
|
|
742
753
|
end
|
743
754
|
|
744
755
|
def extract_table_ref_from_insert_sql(sql) # :nodoc:
|
745
|
-
sql[/into\s
|
756
|
+
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
746
757
|
$1.strip if $1
|
747
758
|
end
|
748
759
|
|
749
|
-
def create_table_definition(
|
750
|
-
PostgreSQL::TableDefinition.new
|
760
|
+
def create_table_definition(*args) # :nodoc:
|
761
|
+
PostgreSQL::TableDefinition.new(*args)
|
762
|
+
end
|
763
|
+
|
764
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
765
|
+
@case_insensitive_cache ||= {}
|
766
|
+
@case_insensitive_cache[column.sql_type] ||= begin
|
767
|
+
sql = <<-end_sql
|
768
|
+
SELECT exists(
|
769
|
+
SELECT * FROM pg_proc
|
770
|
+
WHERE proname = 'lower'
|
771
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
772
|
+
) OR exists(
|
773
|
+
SELECT * FROM pg_proc
|
774
|
+
INNER JOIN pg_cast
|
775
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
776
|
+
WHERE proname = 'lower'
|
777
|
+
AND castsource = #{quote column.sql_type}::regtype
|
778
|
+
)
|
779
|
+
end_sql
|
780
|
+
execute_and_clear(sql, "SCHEMA", []) do |result|
|
781
|
+
result.getvalue(0, 0)
|
782
|
+
end
|
783
|
+
end
|
751
784
|
end
|
785
|
+
|
786
|
+
def add_pg_encoders
|
787
|
+
map = PG::TypeMapByClass.new
|
788
|
+
map[Integer] = PG::TextEncoder::Integer.new
|
789
|
+
map[TrueClass] = PG::TextEncoder::Boolean.new
|
790
|
+
map[FalseClass] = PG::TextEncoder::Boolean.new
|
791
|
+
map[Float] = PG::TextEncoder::Float.new
|
792
|
+
@connection.type_map_for_queries = map
|
793
|
+
end
|
794
|
+
|
795
|
+
def add_pg_decoders
|
796
|
+
coders_by_name = {
|
797
|
+
'int2' => PG::TextDecoder::Integer,
|
798
|
+
'int4' => PG::TextDecoder::Integer,
|
799
|
+
'int8' => PG::TextDecoder::Integer,
|
800
|
+
'oid' => PG::TextDecoder::Integer,
|
801
|
+
'float4' => PG::TextDecoder::Float,
|
802
|
+
'float8' => PG::TextDecoder::Float,
|
803
|
+
'bool' => PG::TextDecoder::Boolean,
|
804
|
+
}
|
805
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
806
|
+
query = <<-SQL % known_coder_types.join(", ")
|
807
|
+
SELECT t.oid, t.typname
|
808
|
+
FROM pg_type as t
|
809
|
+
WHERE t.typname IN (%s)
|
810
|
+
SQL
|
811
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
812
|
+
result
|
813
|
+
.map { |row| construct_coder(row, coders_by_name[row['typname']]) }
|
814
|
+
.compact
|
815
|
+
end
|
816
|
+
|
817
|
+
map = PG::TypeMapByOid.new
|
818
|
+
coders.each { |coder| map.add_coder(coder) }
|
819
|
+
@connection.type_map_for_results = map
|
820
|
+
end
|
821
|
+
|
822
|
+
def construct_coder(row, coder_class)
|
823
|
+
return unless coder_class
|
824
|
+
coder_class.new(oid: row['oid'].to_i, name: row['typname'])
|
825
|
+
end
|
826
|
+
|
827
|
+
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
828
|
+
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
829
|
+
ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
|
830
|
+
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
|
831
|
+
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
|
832
|
+
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
|
833
|
+
ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
|
834
|
+
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
|
835
|
+
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
836
|
+
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
837
|
+
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
838
|
+
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
|
839
|
+
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
840
|
+
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
841
|
+
ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
|
842
|
+
ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
|
843
|
+
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
|
844
|
+
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
|
845
|
+
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
|
752
846
|
end
|
753
847
|
end
|
754
848
|
end
|