-
Notifications
You must be signed in to change notification settings - Fork 21.6k
/
mysql2_adapter.rb
170 lines (139 loc) · 4.53 KB
/
mysql2_adapter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# frozen_string_literal: true
require "active_record/connection_adapters/abstract_mysql_adapter"
require "active_record/connection_adapters/mysql/database_statements"
gem "mysql2", "~> 0.5"
require "mysql2"
module ActiveRecord
module ConnectionHandling # :nodoc:
# Establishes a connection to the database that's used by all Active Record objects.
def mysql2_connection(config)
config = config.symbolize_keys
config[:flags] ||= 0
if config[:flags].kind_of? Array
config[:flags].push "FOUND_ROWS"
else
config[:flags] |= Mysql2::Client::FOUND_ROWS
end
ConnectionAdapters::Mysql2Adapter.new(
ConnectionAdapters::Mysql2Adapter.new_client(config),
logger,
nil,
config,
)
end
end
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
ER_BAD_DB_ERROR = 1049
ER_ACCESS_DENIED_ERROR = 1045
ER_CONN_HOST_ERROR = 2003
ER_UNKNOWN_HOST_ERROR = 2005
ADAPTER_NAME = "Mysql2"
include MySQL::DatabaseStatements
class << self
def new_client(config)
Mysql2::Client.new(config)
rescue Mysql2::Error => error
if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
raise ActiveRecord::NoDatabaseError.db_error(config[:database])
elsif error.error_number == ConnectionAdapters::Mysql2Adapter::ER_ACCESS_DENIED_ERROR
raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
elsif [ConnectionAdapters::Mysql2Adapter::ER_CONN_HOST_ERROR, ConnectionAdapters::Mysql2Adapter::ER_UNKNOWN_HOST_ERROR].include?(error.error_number)
raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
else
raise ActiveRecord::ConnectionNotEstablished, error.message
end
end
end
def initialize(connection, logger, connection_options, config)
superclass_config = config.reverse_merge(prepared_statements: false)
super(connection, logger, connection_options, superclass_config)
configure_connection
end
def self.database_exists?(config)
!!ActiveRecord::Base.mysql2_connection(config)
rescue ActiveRecord::NoDatabaseError
false
end
def supports_json?
!mariadb? && database_version >= "5.7.8"
end
def supports_comments?
true
end
def supports_comments_in_create?
true
end
def supports_savepoints?
true
end
def supports_lazy_transactions?
true
end
# HELPER METHODS ===========================================
def each_hash(result, &block) # :nodoc:
if block_given?
result.each(as: :hash, symbolize_keys: true, &block)
else
to_enum(:each_hash, result)
end
end
def error_number(exception)
exception.error_number if exception.respond_to?(:error_number)
end
#--
# QUOTING ==================================================
#++
def quote_string(string)
@connection.escape(string)
rescue Mysql2::Error => error
raise translate_exception(error, message: error.message, sql: "<escape>", binds: [])
end
#--
# CONNECTION MANAGEMENT ====================================
#++
def active?
@connection.ping
end
def reconnect!
super
disconnect!
connect
end
alias :reset! :reconnect!
# Disconnects from the database if already connected.
# Otherwise, this method does nothing.
def disconnect!
super
@connection.close
end
def discard! # :nodoc:
super
@connection.automatic_close = false
@connection = nil
end
private
def connect
@connection = self.class.new_client(@config)
configure_connection
end
def configure_connection
@connection.query_options[:as] = :array
super
end
def full_version
schema_cache.database_version.full_version_string
end
def get_full_version
@connection.server_info[:version]
end
def translate_exception(exception, message:, sql:, binds:)
if exception.is_a?(Mysql2::Error::TimeoutError) && !exception.error_number
ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds)
else
super
end
end
end
end
end