Class: Tina4::Drivers::MysqlDriver
Constant Summary
collapse
- WRITE_VERBS =
First SIX characters of the statements whose row count #affected_rows
reports. "REPLAC" is REPLACE truncated to the same width.
%w[INSERT UPDATE DELETE REPLAC].freeze
Tina4::DatabaseAdapter::CONNECT_TIMEOUT_SLACK_SECONDS, Tina4::DatabaseAdapter::CONNECT_TIMEOUT_VAR, Tina4::DatabaseAdapter::CONTRACT, Tina4::DatabaseAdapter::DEFAULT_CONNECT_TIMEOUT_SECONDS
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#affected_rows ⇒ Object
Rows changed by the most recent INSERT/UPDATE/DELETE on this connection.
-
#apply_limit(sql, limit, offset = 0) ⇒ Object
NEW LINE, not a space — appended inline the clause lands inside a trailing -- comment and the engine ignores it (see the note on Drivers::SqliteDriver#apply_limit).
-
#begin_transaction ⇒ Object
-
#close ⇒ Object
-
#columns(table_name) ⇒ Object
-
#commit ⇒ Object
-
#connect(connection_string, username: nil, password: nil) ⇒ Object
-
#count_subquery_alias ⇒ Object
Postgres, MySQL, MSSQL and ODBC all REQUIRE a name for a derived table, so the COUNT probe in Database#count_probe wraps as FROM (sql) AS _count_query.
-
#execute(sql, params = []) ⇒ Object
-
#execute_query(sql, params = []) ⇒ Object
-
#last_insert_id ⇒ Object
-
#placeholder ⇒ Object
-
#placeholders(count) ⇒ Object
-
#rollback ⇒ Object
-
#table_exists?(name) ⇒ Boolean
v3.13.14 (#48): MySQL's "schema" is the database.
-
#tables ⇒ Object
#split_schema
bounding_connect, connect_timed_out!, connect_timeout_seconds, connect_timeout_whole_seconds, implemented_by?
Instance Attribute Details
#connection ⇒ Object
Returns the value of attribute connection.
22
23
24
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 22
def connection
@connection
end
|
Instance Method Details
#affected_rows ⇒ Object
Rows changed by the most recent INSERT/UPDATE/DELETE on this connection.
Parity with SQLite (connection.changes), PostgreSQL (cmd_tuples), MSSQL
(TinyTds::Result#do) and the Python master (cursor.rowcount).
138
139
140
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 138
def affected_rows
@affected_rows.to_i
end
|
#apply_limit(sql, limit, offset = 0) ⇒ Object
NEW LINE, not a space — appended inline the clause lands inside a
trailing -- comment and the engine ignores it (see the note on
Drivers::SqliteDriver#apply_limit).
153
154
155
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 153
def apply_limit(sql, limit, offset = 0)
"#{sql}\nLIMIT #{limit} OFFSET #{offset}"
end
|
#begin_transaction ⇒ Object
157
158
159
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 157
def begin_transaction
@connection.query("START TRANSACTION")
end
|
#close ⇒ Object
63
64
65
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 63
def close
@connection&.close
end
|
#columns(table_name) ⇒ Object
187
188
189
190
191
192
193
194
195
196
197
198
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 187
def columns(table_name)
rows = execute_query("DESCRIBE #{table_name}")
rows.map do |r|
{
name: r[:Field],
type: r[:Type],
nullable: r[:Null] == "YES",
default: r[:Default],
primary_key: r[:Key] == "PRI"
}
end
end
|
#commit ⇒ Object
161
162
163
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 161
def commit
@connection.query("COMMIT")
end
|
#connect(connection_string, username: nil, password: nil) ⇒ Object
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
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 24
def connect(connection_string, username: nil, password: nil)
begin
require "mysql2"
rescue LoadError
raise LoadError,
"The 'mysql2' gem is required for MySQL connections. Install one of:\n" \
" bundle add mysql2 # if your project uses Bundler\n" \
" gem install mysql2 # bare driver"
end
uri = URI.parse(connection_string)
host = uri.host || "127.0.0.1"
host = "127.0.0.1" if host == "localhost" && uri.port
options = {
host: host,
port: uri.port || 3306,
username: username || uri.user,
password: password || uri.password,
database: uri.path&.sub("/", "")
}
seconds = Tina4::DatabaseAdapter.connect_timeout_whole_seconds
options[:connect_timeout] = seconds if seconds
Tina4::DatabaseAdapter.bounding_connect(options[:host], options[:port]) do
@connection = Mysql2::Client.new(**options)
end
end
|
#count_subquery_alias ⇒ Object
Postgres, MySQL, MSSQL and ODBC all REQUIRE a name for a derived
table, so the COUNT probe in Database#count_probe wraps as
FROM (sql) AS _count_query. SQLite and Firebird do not define
this and get no alias - Firebird rejects AS in that position.
12
13
14
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 12
def count_subquery_alias
"_count_query"
end
|
#execute(sql, params = []) ⇒ Object
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
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 77
def execute(sql, params = [])
stmt = nil
result =
if params.empty?
@connection.query(sql)
else
stmt = @connection.prepare(sql)
stmt.execute(*params)
end
if WRITE_VERBS.include?(sql.to_s.lstrip[0, 6].upcase)
@affected_rows = stmt ? stmt.affected_rows.to_i : @connection.affected_rows.to_i
end
if sql.to_s.lstrip[0, 6].casecmp?("INSERT")
first_id = @connection.last_id
rows = @affected_rows.to_i
@last_insert_id =
if first_id.to_i.positive?
first_id.to_i + [rows, 1].max - 1
else
first_id
end
end
result
end
|
#execute_query(sql, params = []) ⇒ Object
67
68
69
70
71
72
73
74
75
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 67
def execute_query(sql, params = [])
if params.empty?
results = @connection.query(sql, symbolize_keys: true)
else
stmt = @connection.prepare(sql)
results = stmt.execute(*params, symbolize_keys: true)
end
results.to_a
end
|
#last_insert_id ⇒ Object
131
132
133
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 131
def last_insert_id
@last_insert_id
end
|
#placeholder ⇒ Object
142
143
144
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 142
def placeholder
"?"
end
|
#placeholders(count) ⇒ Object
146
147
148
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 146
def placeholders(count)
(["?"] * count).join(", ")
end
|
#rollback ⇒ Object
165
166
167
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 165
def rollback
@connection.query("ROLLBACK")
end
|
#table_exists?(name) ⇒ Boolean
v3.13.14 (#48): MySQL's "schema" is the database. A qualified name
("otherdb.table") checks that catalog; a bare name defaults to the
connection's current database via DATABASE().
172
173
174
175
176
177
178
179
180
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 172
def table_exists?(name)
schema, tbl = split_schema(name)
rows = execute_query(
"SELECT 1 FROM information_schema.tables " \
"WHERE table_schema = COALESCE(?, DATABASE()) AND table_name = ?",
[schema, tbl]
)
!rows.empty?
end
|
#tables ⇒ Object
182
183
184
185
|
# File 'lib/tina4/drivers/mysql_driver.rb', line 182
def tables
rows = execute_query("SHOW TABLES")
rows.map { |r| r.values.first }
end
|