activerecord 5.2.3
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 +7 -0
- data/CHANGELOG.md +937 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +217 -0
- data/examples/performance.rb +185 -0
- data/examples/simple.rb +15 -0
- data/lib/active_record.rb +188 -0
- data/lib/active_record/aggregations.rb +283 -0
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations.rb +1860 -0
- data/lib/active_record/associations/alias_tracker.rb +81 -0
- data/lib/active_record/associations/association.rb +299 -0
- data/lib/active_record/associations/association_scope.rb +168 -0
- data/lib/active_record/associations/belongs_to_association.rb +130 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
- data/lib/active_record/associations/builder/association.rb +140 -0
- data/lib/active_record/associations/builder/belongs_to.rb +163 -0
- data/lib/active_record/associations/builder/collection_association.rb +82 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +135 -0
- data/lib/active_record/associations/builder/has_many.rb +17 -0
- data/lib/active_record/associations/builder/has_one.rb +30 -0
- data/lib/active_record/associations/builder/singular_association.rb +42 -0
- data/lib/active_record/associations/collection_association.rb +513 -0
- data/lib/active_record/associations/collection_proxy.rb +1131 -0
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +144 -0
- data/lib/active_record/associations/has_many_through_association.rb +227 -0
- data/lib/active_record/associations/has_one_association.rb +120 -0
- data/lib/active_record/associations/has_one_through_association.rb +45 -0
- data/lib/active_record/associations/join_dependency.rb +262 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +60 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/preloader.rb +193 -0
- data/lib/active_record/associations/preloader/association.rb +131 -0
- data/lib/active_record/associations/preloader/through_association.rb +107 -0
- data/lib/active_record/associations/singular_association.rb +73 -0
- data/lib/active_record/associations/through_association.rb +121 -0
- data/lib/active_record/attribute_assignment.rb +88 -0
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods.rb +492 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +78 -0
- data/lib/active_record/attribute_methods/dirty.rb +150 -0
- data/lib/active_record/attribute_methods/primary_key.rb +143 -0
- data/lib/active_record/attribute_methods/query.rb +42 -0
- data/lib/active_record/attribute_methods/read.rb +85 -0
- data/lib/active_record/attribute_methods/serialization.rb +90 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
- data/lib/active_record/attribute_methods/write.rb +68 -0
- data/lib/active_record/attributes.rb +266 -0
- data/lib/active_record/autosave_association.rb +498 -0
- data/lib/active_record/base.rb +329 -0
- data/lib/active_record/callbacks.rb +353 -0
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +50 -0
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1068 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +72 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +540 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +145 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +200 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +685 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1396 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +628 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +887 -0
- data/lib/active_record/connection_adapters/column.rb +91 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +863 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +118 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +573 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
- data/lib/active_record/connection_handling.rb +145 -0
- data/lib/active_record/core.rb +559 -0
- data/lib/active_record/counter_cache.rb +218 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +122 -0
- data/lib/active_record/enum.rb +244 -0
- data/lib/active_record/errors.rb +380 -0
- data/lib/active_record/explain.rb +50 -0
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +34 -0
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixtures.rb +1065 -0
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +283 -0
- data/lib/active_record/integration.rb +155 -0
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +48 -0
- data/lib/active_record/locking/optimistic.rb +198 -0
- data/lib/active_record/locking/pessimistic.rb +89 -0
- data/lib/active_record/log_subscriber.rb +137 -0
- data/lib/active_record/migration.rb +1378 -0
- data/lib/active_record/migration/command_recorder.rb +240 -0
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/model_schema.rb +521 -0
- data/lib/active_record/nested_attributes.rb +600 -0
- data/lib/active_record/no_touching.rb +58 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +763 -0
- data/lib/active_record/query_cache.rb +45 -0
- data/lib/active_record/querying.rb +70 -0
- data/lib/active_record/railtie.rb +226 -0
- data/lib/active_record/railties/console_sandbox.rb +7 -0
- data/lib/active_record/railties/controller_runtime.rb +56 -0
- data/lib/active_record/railties/databases.rake +377 -0
- data/lib/active_record/readonly_attributes.rb +24 -0
- data/lib/active_record/reflection.rb +1044 -0
- data/lib/active_record/relation.rb +629 -0
- data/lib/active_record/relation/batches.rb +287 -0
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +417 -0
- data/lib/active_record/relation/delegation.rb +147 -0
- data/lib/active_record/relation/finder_methods.rb +565 -0
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder.rb +152 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +1231 -0
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +77 -0
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/result.rb +149 -0
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +222 -0
- data/lib/active_record/schema.rb +70 -0
- data/lib/active_record/schema_dumper.rb +255 -0
- data/lib/active_record/schema_migration.rb +56 -0
- data/lib/active_record/scoping.rb +106 -0
- data/lib/active_record/scoping/default.rb +152 -0
- data/lib/active_record/scoping/named.rb +213 -0
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/statement_cache.rb +121 -0
- data/lib/active_record/store.rb +211 -0
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +337 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
- data/lib/active_record/timestamp.rb +153 -0
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +502 -0
- data/lib/active_record/translation.rb +24 -0
- data/lib/active_record/type.rb +79 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/validations.rb +93 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +60 -0
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +238 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/rails/generators/active_record.rb +19 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration.rb +35 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +78 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
- metadata +333 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module MySQL
|
6
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
|
7
|
+
undef to_yaml if method_defined?(:to_yaml)
|
8
|
+
|
9
|
+
attr_reader :extra
|
10
|
+
|
11
|
+
def initialize(type_metadata, extra: "")
|
12
|
+
super(type_metadata)
|
13
|
+
@type_metadata = type_metadata
|
14
|
+
@extra = extra
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
other.is_a?(MySQL::TypeMetadata) &&
|
19
|
+
attributes_for_hash == other.attributes_for_hash
|
20
|
+
end
|
21
|
+
alias eql? ==
|
22
|
+
|
23
|
+
def hash
|
24
|
+
attributes_for_hash.hash
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def attributes_for_hash
|
30
|
+
[self.class, @type_metadata, extra]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
4
|
+
require "active_record/connection_adapters/mysql/database_statements"
|
5
|
+
|
6
|
+
gem "mysql2", ">= 0.4.4", "< 0.6.0"
|
7
|
+
require "mysql2"
|
8
|
+
|
9
|
+
module ActiveRecord
|
10
|
+
module ConnectionHandling # :nodoc:
|
11
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
12
|
+
def mysql2_connection(config)
|
13
|
+
config = config.symbolize_keys
|
14
|
+
config[:flags] ||= 0
|
15
|
+
|
16
|
+
if config[:flags].kind_of? Array
|
17
|
+
config[:flags].push "FOUND_ROWS".freeze
|
18
|
+
else
|
19
|
+
config[:flags] |= Mysql2::Client::FOUND_ROWS
|
20
|
+
end
|
21
|
+
|
22
|
+
client = Mysql2::Client.new(config)
|
23
|
+
ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
|
24
|
+
rescue Mysql2::Error => error
|
25
|
+
if error.message.include?("Unknown database")
|
26
|
+
raise ActiveRecord::NoDatabaseError
|
27
|
+
else
|
28
|
+
raise
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ConnectionAdapters
|
34
|
+
class Mysql2Adapter < AbstractMysqlAdapter
|
35
|
+
ADAPTER_NAME = "Mysql2".freeze
|
36
|
+
|
37
|
+
include MySQL::DatabaseStatements
|
38
|
+
|
39
|
+
def initialize(connection, logger, connection_options, config)
|
40
|
+
super
|
41
|
+
@prepared_statements = false unless config.key?(:prepared_statements)
|
42
|
+
configure_connection
|
43
|
+
end
|
44
|
+
|
45
|
+
def supports_json?
|
46
|
+
!mariadb? && version >= "5.7.8"
|
47
|
+
end
|
48
|
+
|
49
|
+
def supports_comments?
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def supports_comments_in_create?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def supports_savepoints?
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
# HELPER METHODS ===========================================
|
62
|
+
|
63
|
+
def each_hash(result) # :nodoc:
|
64
|
+
if block_given?
|
65
|
+
result.each(as: :hash, symbolize_keys: true) do |row|
|
66
|
+
yield row
|
67
|
+
end
|
68
|
+
else
|
69
|
+
to_enum(:each_hash, result)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def error_number(exception)
|
74
|
+
exception.error_number if exception.respond_to?(:error_number)
|
75
|
+
end
|
76
|
+
|
77
|
+
#--
|
78
|
+
# QUOTING ==================================================
|
79
|
+
#++
|
80
|
+
|
81
|
+
def quote_string(string)
|
82
|
+
@connection.escape(string)
|
83
|
+
end
|
84
|
+
|
85
|
+
#--
|
86
|
+
# CONNECTION MANAGEMENT ====================================
|
87
|
+
#++
|
88
|
+
|
89
|
+
def active?
|
90
|
+
@connection.ping
|
91
|
+
end
|
92
|
+
|
93
|
+
def reconnect!
|
94
|
+
super
|
95
|
+
disconnect!
|
96
|
+
connect
|
97
|
+
end
|
98
|
+
alias :reset! :reconnect!
|
99
|
+
|
100
|
+
# Disconnects from the database if already connected.
|
101
|
+
# Otherwise, this method does nothing.
|
102
|
+
def disconnect!
|
103
|
+
super
|
104
|
+
@connection.close
|
105
|
+
end
|
106
|
+
|
107
|
+
def discard! # :nodoc:
|
108
|
+
@connection.automatic_close = false
|
109
|
+
@connection = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def connect
|
115
|
+
@connection = Mysql2::Client.new(@config)
|
116
|
+
configure_connection
|
117
|
+
end
|
118
|
+
|
119
|
+
def configure_connection
|
120
|
+
@connection.query_options.merge!(as: :array)
|
121
|
+
super
|
122
|
+
end
|
123
|
+
|
124
|
+
def full_version
|
125
|
+
@full_version ||= @connection.server_info[:version]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
# PostgreSQL-specific extensions to column definitions in a table.
|
6
|
+
class PostgreSQLColumn < Column #:nodoc:
|
7
|
+
delegate :array, :oid, :fmod, to: :sql_type_metadata
|
8
|
+
alias :array? :array
|
9
|
+
|
10
|
+
def initialize(*, max_identifier_length: 63, **)
|
11
|
+
super
|
12
|
+
@max_identifier_length = max_identifier_length
|
13
|
+
end
|
14
|
+
|
15
|
+
def serial?
|
16
|
+
return unless default_function
|
17
|
+
|
18
|
+
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
19
|
+
sequence_name_from_parts(table_name, name, suffix) == sequence_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
attr_reader :max_identifier_length
|
25
|
+
|
26
|
+
private
|
27
|
+
def sequence_name_from_parts(table_name, column_name, suffix)
|
28
|
+
over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
|
29
|
+
|
30
|
+
if over_length > 0
|
31
|
+
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
32
|
+
over_length -= column_name.length - column_name_length
|
33
|
+
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
34
|
+
end
|
35
|
+
|
36
|
+
if over_length > 0
|
37
|
+
table_name = table_name[0, table_name.length - over_length]
|
38
|
+
end
|
39
|
+
|
40
|
+
"#{table_name}_#{column_name}_#{suffix}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module DatabaseStatements
|
7
|
+
def explain(arel, binds = [])
|
8
|
+
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
9
|
+
PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
|
10
|
+
end
|
11
|
+
|
12
|
+
# The internal PostgreSQL identifier of the money data type.
|
13
|
+
MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
|
14
|
+
# The internal PostgreSQL identifier of the BYTEA data type.
|
15
|
+
BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
|
16
|
+
|
17
|
+
# create a 2D array representing the result set
|
18
|
+
def result_as_array(res) #:nodoc:
|
19
|
+
# check if we have any binary column and if they need escaping
|
20
|
+
ftypes = Array.new(res.nfields) do |i|
|
21
|
+
[i, res.ftype(i)]
|
22
|
+
end
|
23
|
+
|
24
|
+
rows = res.values
|
25
|
+
return rows unless ftypes.any? { |_, x|
|
26
|
+
x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
|
27
|
+
}
|
28
|
+
|
29
|
+
typehash = ftypes.group_by { |_, type| type }
|
30
|
+
binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
|
31
|
+
monies = typehash[MONEY_COLUMN_TYPE_OID] || []
|
32
|
+
|
33
|
+
rows.each do |row|
|
34
|
+
# unescape string passed BYTEA field (OID == 17)
|
35
|
+
binaries.each do |index, _|
|
36
|
+
row[index] = unescape_bytea(row[index])
|
37
|
+
end
|
38
|
+
|
39
|
+
# If this is a money type column and there are any currency symbols,
|
40
|
+
# then strip them off. Indeed it would be prettier to do this in
|
41
|
+
# PostgreSQLColumn.string_to_decimal but would break form input
|
42
|
+
# fields that call value_before_type_cast.
|
43
|
+
monies.each do |index, _|
|
44
|
+
data = row[index]
|
45
|
+
# Because money output is formatted according to the locale, there are two
|
46
|
+
# cases to consider (note the decimal separators):
|
47
|
+
# (1) $12,345,678.12
|
48
|
+
# (2) $12.345.678,12
|
49
|
+
case data
|
50
|
+
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
51
|
+
data.gsub!(/[^-\d.]/, "")
|
52
|
+
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
53
|
+
data.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Queries the database and returns the results in an Array-like object
|
60
|
+
def query(sql, name = nil) #:nodoc:
|
61
|
+
log(sql, name) do
|
62
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
63
|
+
result_as_array @connection.async_exec(sql)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Executes an SQL statement, returning a PG::Result object on success
|
69
|
+
# or raising a PG::Error exception otherwise.
|
70
|
+
# Note: the PG::Result object is manually memory managed; if you don't
|
71
|
+
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
|
72
|
+
def execute(sql, name = nil)
|
73
|
+
log(sql, name) do
|
74
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
75
|
+
@connection.async_exec(sql)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
81
|
+
execute_and_clear(sql, name, binds, prepare: prepare) do |result|
|
82
|
+
types = {}
|
83
|
+
fields = result.fields
|
84
|
+
fields.each_with_index do |fname, i|
|
85
|
+
ftype = result.ftype i
|
86
|
+
fmod = result.fmod i
|
87
|
+
types[fname] = get_oid_type(ftype, fmod, fname)
|
88
|
+
end
|
89
|
+
ActiveRecord::Result.new(fields, result.values, types)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def exec_delete(sql, name = nil, binds = [])
|
94
|
+
execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
|
95
|
+
end
|
96
|
+
alias :exec_update :exec_delete
|
97
|
+
|
98
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc:
|
99
|
+
if pk.nil?
|
100
|
+
# Extract the table from the insert sql. Yuck.
|
101
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
102
|
+
pk = primary_key(table_ref) if table_ref
|
103
|
+
end
|
104
|
+
|
105
|
+
if pk = suppress_composite_primary_key(pk)
|
106
|
+
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
|
107
|
+
end
|
108
|
+
|
109
|
+
super
|
110
|
+
end
|
111
|
+
private :sql_for_insert
|
112
|
+
|
113
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
114
|
+
if use_insert_returning? || pk == false
|
115
|
+
super
|
116
|
+
else
|
117
|
+
result = exec_query(sql, name, binds)
|
118
|
+
unless sequence_name
|
119
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
120
|
+
if table_ref
|
121
|
+
pk = primary_key(table_ref) if pk.nil?
|
122
|
+
pk = suppress_composite_primary_key(pk)
|
123
|
+
sequence_name = default_sequence_name(table_ref, pk)
|
124
|
+
end
|
125
|
+
return result unless sequence_name
|
126
|
+
end
|
127
|
+
last_insert_id_result(sequence_name)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Begins a transaction.
|
132
|
+
def begin_db_transaction
|
133
|
+
execute "BEGIN"
|
134
|
+
end
|
135
|
+
|
136
|
+
def begin_isolated_db_transaction(isolation)
|
137
|
+
begin_db_transaction
|
138
|
+
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
139
|
+
end
|
140
|
+
|
141
|
+
# Commits a transaction.
|
142
|
+
def commit_db_transaction
|
143
|
+
execute "COMMIT"
|
144
|
+
end
|
145
|
+
|
146
|
+
# Aborts a transaction.
|
147
|
+
def exec_rollback_db_transaction
|
148
|
+
execute "ROLLBACK"
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
# Returns the current ID of a table's sequence.
|
153
|
+
def last_insert_id_result(sequence_name)
|
154
|
+
exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
155
|
+
end
|
156
|
+
|
157
|
+
def suppress_composite_primary_key(pk)
|
158
|
+
pk unless pk.is_a?(Array)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
class ExplainPrettyPrinter # :nodoc:
|
7
|
+
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
|
8
|
+
# PostgreSQL shell:
|
9
|
+
#
|
10
|
+
# QUERY PLAN
|
11
|
+
# ------------------------------------------------------------------------------
|
12
|
+
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
|
13
|
+
# Join Filter: (posts.user_id = users.id)
|
14
|
+
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
|
15
|
+
# Index Cond: (id = 1)
|
16
|
+
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
|
17
|
+
# Filter: (posts.user_id = 1)
|
18
|
+
# (6 rows)
|
19
|
+
#
|
20
|
+
def pp(result)
|
21
|
+
header = result.columns.first
|
22
|
+
lines = result.rows.map(&:first)
|
23
|
+
|
24
|
+
# We add 2 because there's one char of padding at both sides, note
|
25
|
+
# the extra hyphens in the example above.
|
26
|
+
width = [header, *lines].map(&:length).max + 2
|
27
|
+
|
28
|
+
pp = []
|
29
|
+
|
30
|
+
pp << header.center(width).rstrip
|
31
|
+
pp << "-" * width
|
32
|
+
|
33
|
+
pp += lines.map { |line| " #{line}" }
|
34
|
+
|
35
|
+
nrows = result.rows.length
|
36
|
+
rows_label = nrows == 1 ? "row" : "rows"
|
37
|
+
pp << "(#{nrows} #{rows_label})"
|
38
|
+
|
39
|
+
pp.join("\n") + "\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/postgresql/oid/array"
|
4
|
+
require "active_record/connection_adapters/postgresql/oid/bit"
|
5
|
+
require "active_record/connection_adapters/postgresql/oid/bit_varying"
|
6
|
+
require "active_record/connection_adapters/postgresql/oid/bytea"
|
7
|
+
require "active_record/connection_adapters/postgresql/oid/cidr"
|
8
|
+
require "active_record/connection_adapters/postgresql/oid/date"
|
9
|
+
require "active_record/connection_adapters/postgresql/oid/date_time"
|
10
|
+
require "active_record/connection_adapters/postgresql/oid/decimal"
|
11
|
+
require "active_record/connection_adapters/postgresql/oid/enum"
|
12
|
+
require "active_record/connection_adapters/postgresql/oid/hstore"
|
13
|
+
require "active_record/connection_adapters/postgresql/oid/inet"
|
14
|
+
require "active_record/connection_adapters/postgresql/oid/jsonb"
|
15
|
+
require "active_record/connection_adapters/postgresql/oid/money"
|
16
|
+
require "active_record/connection_adapters/postgresql/oid/oid"
|
17
|
+
require "active_record/connection_adapters/postgresql/oid/point"
|
18
|
+
require "active_record/connection_adapters/postgresql/oid/legacy_point"
|
19
|
+
require "active_record/connection_adapters/postgresql/oid/range"
|
20
|
+
require "active_record/connection_adapters/postgresql/oid/specialized_string"
|
21
|
+
require "active_record/connection_adapters/postgresql/oid/uuid"
|
22
|
+
require "active_record/connection_adapters/postgresql/oid/vector"
|
23
|
+
require "active_record/connection_adapters/postgresql/oid/xml"
|
24
|
+
|
25
|
+
require "active_record/connection_adapters/postgresql/oid/type_map_initializer"
|
26
|
+
|
27
|
+
module ActiveRecord
|
28
|
+
module ConnectionAdapters
|
29
|
+
module PostgreSQL
|
30
|
+
module OID # :nodoc:
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|