trilogy 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/trilogy.rb CHANGED
@@ -1,7 +1,178 @@
1
- require "trilogy/cext"
1
+ # frozen_string_literal: true
2
+
2
3
  require "trilogy/version"
3
4
 
4
5
  class Trilogy
6
+ # Trilogy::Error is the base error type. All errors raised by Trilogy
7
+ # should be descendants of Trilogy::Error
8
+ module Error
9
+ attr_reader :error_code
10
+ end
11
+
12
+ # Trilogy::ConnectionError is the base error type for all potentially transient
13
+ # network errors.
14
+ module ConnectionError
15
+ include Error
16
+ end
17
+
18
+ # Trilogy may raise various syscall errors, which we treat as Trilogy::Errors.
19
+ class SyscallError
20
+ ERRORS = {}
21
+
22
+ Errno.constants
23
+ .map { |c| Errno.const_get(c) }.uniq
24
+ .select { |c| c.is_a?(Class) && c < SystemCallError }
25
+ .each do |c|
26
+ errno_name = c.to_s.split('::').last
27
+ ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::Error })
28
+ end
29
+
30
+ ERRORS.freeze
31
+
32
+ class << self
33
+ def from_errno(errno, message)
34
+ ERRORS[errno].new(message)
35
+ end
36
+ end
37
+ end
38
+
39
+ class BaseError < StandardError
40
+ include Error
41
+
42
+ def initialize(error_message = nil, error_code = nil)
43
+ message = error_code ? "#{error_code}: #{error_message}" : error_message
44
+ super(message)
45
+ @error_code = error_code
46
+ end
47
+ end
48
+
49
+ class BaseConnectionError < BaseError
50
+ include ConnectionError
51
+ end
52
+
53
+ # Trilogy::ClientError is the base error type for invalid queries or parameters
54
+ # that shouldn't be retried.
55
+ class ClientError < BaseError
56
+ include Error
57
+ end
58
+
59
+ class QueryError < ClientError
60
+ end
61
+
62
+ class CastError < ClientError
63
+ end
64
+
65
+ class TimeoutError < Errno::ETIMEDOUT
66
+ include ConnectionError
67
+ end
68
+
69
+ class ConnectionRefusedError < Errno::ECONNREFUSED
70
+ include ConnectionError
71
+ end
72
+
73
+ class ConnectionResetError < Errno::ECONNRESET
74
+ include ConnectionError
75
+ end
76
+
77
+ # DatabaseError was replaced by ProtocolError, but we'll keep it around as an
78
+ # ancestor of ProtocolError for compatibility reasons (e.g. so `rescue DatabaseError`
79
+ # still works. We can remove this class in the next major release.
80
+ module DatabaseError
81
+ end
82
+
83
+ class ProtocolError < BaseError
84
+ include DatabaseError
85
+
86
+ ERROR_CODES = {
87
+ 1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
88
+ 1044 => BaseConnectionError, # ER_DBACCESS_DENIED_ERROR
89
+ 1045 => BaseConnectionError, # ER_ACCESS_DENIED_ERROR
90
+ 1064 => QueryError, # ER_PARSE_ERROR
91
+ 1152 => BaseConnectionError, # ER_ABORTING_CONNECTION
92
+ 1153 => BaseConnectionError, # ER_NET_PACKET_TOO_LARGE
93
+ 1154 => BaseConnectionError, # ER_NET_READ_ERROR_FROM_PIPE
94
+ 1155 => BaseConnectionError, # ER_NET_FCNTL_ERROR
95
+ 1156 => BaseConnectionError, # ER_NET_PACKETS_OUT_OF_ORDER
96
+ 1157 => BaseConnectionError, # ER_NET_UNCOMPRESS_ERROR
97
+ 1158 => BaseConnectionError, # ER_NET_READ_ERROR
98
+ 1159 => BaseConnectionError, # ER_NET_READ_INTERRUPTED
99
+ 1160 => BaseConnectionError, # ER_NET_ERROR_ON_WRITE
100
+ 1161 => BaseConnectionError, # ER_NET_WRITE_INTERRUPTED
101
+ 1927 => BaseConnectionError, # ER_CONNECTION_KILLED
102
+ }
103
+ class << self
104
+ def from_code(message, code)
105
+ ERROR_CODES.fetch(code, self).new(message, code)
106
+ end
107
+ end
108
+ end
109
+
110
+ class SSLError < BaseError
111
+ include ConnectionError
112
+ end
113
+
114
+ class ConnectionClosed < IOError
115
+ include ConnectionError
116
+ end
117
+
118
+ MYSQL_TO_RUBY_ENCODINGS_MAP = {
119
+ "big5" => "Big5",
120
+ "dec8" => nil,
121
+ "cp850" => "CP850",
122
+ "hp8" => nil,
123
+ "koi8r" => "KOI8-R",
124
+ "latin1" => "ISO-8859-1",
125
+ "latin2" => "ISO-8859-2",
126
+ "swe7" => nil,
127
+ "ascii" => "US-ASCII",
128
+ "ujis" => "eucJP-ms",
129
+ "sjis" => "Shift_JIS",
130
+ "hebrew" => "ISO-8859-8",
131
+ "tis620" => "TIS-620",
132
+ "euckr" => "EUC-KR",
133
+ "koi8u" => "KOI8-R",
134
+ "gb2312" => "GB2312",
135
+ "greek" => "ISO-8859-7",
136
+ "cp1250" => "Windows-1250",
137
+ "gbk" => "GBK",
138
+ "latin5" => "ISO-8859-9",
139
+ "armscii8" => nil,
140
+ "utf8" => "UTF-8",
141
+ "ucs2" => "UTF-16BE",
142
+ "cp866" => "IBM866",
143
+ "keybcs2" => nil,
144
+ "macce" => "macCentEuro",
145
+ "macroman" => "macRoman",
146
+ "cp852" => "CP852",
147
+ "latin7" => "ISO-8859-13",
148
+ "utf8mb4" => "UTF-8",
149
+ "cp1251" => "Windows-1251",
150
+ "utf16" => "UTF-16",
151
+ "cp1256" => "Windows-1256",
152
+ "cp1257" => "Windows-1257",
153
+ "utf32" => "UTF-32",
154
+ "binary" => "ASCII-8BIT",
155
+ "geostd8" => nil,
156
+ "cp932" => "Windows-31J",
157
+ "eucjpms" => "eucJP-ms",
158
+ "utf16le" => "UTF-16LE",
159
+ "gb18030" => "GB18030",
160
+ }.freeze
161
+
162
+ def initialize(options = {})
163
+ mysql_encoding = options[:encoding] || "utf8mb4"
164
+ unless rb_encoding = MYSQL_TO_RUBY_ENCODINGS_MAP[mysql_encoding]
165
+ raise ArgumentError, "Unknown or unsupported encoding: #{mysql_encoding}"
166
+ end
167
+ encoding = Encoding.find(rb_encoding)
168
+ charset = charset_for_mysql_encoding(mysql_encoding)
169
+ _initialize(encoding, charset, **options)
170
+ end
171
+
172
+ def connection_options
173
+ @connection_options.dup.freeze
174
+ end
175
+
5
176
  def in_transaction?
6
177
  (server_status & SERVER_STATUS_IN_TRANS) != 0
7
178
  end
@@ -28,34 +199,81 @@ class Trilogy
28
199
  ensure
29
200
  self.query_flags = old_flags
30
201
  end
31
- end
32
202
 
33
- Trilogy::Result.class_eval do
34
- def count
35
- rows.count
36
- end
203
+ class Result
204
+ attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
205
+
206
+ def count
207
+ rows.count
208
+ end
37
209
 
38
- def each_hash
39
- return enum_for(:each_hash) unless block_given?
210
+ def each_hash
211
+ return enum_for(:each_hash) unless block_given?
40
212
 
41
- rows.each do |row|
42
- this_row = {}
213
+ rows.each do |row|
214
+ this_row = {}
43
215
 
44
- idx = 0
45
- row.each do |col|
46
- this_row[fields[idx]] = col
47
- idx += 1
216
+ idx = 0
217
+ row.each do |col|
218
+ this_row[fields[idx]] = col
219
+ idx += 1
220
+ end
221
+
222
+ yield this_row
48
223
  end
49
224
 
50
- yield this_row
225
+ self
51
226
  end
52
227
 
53
- self
54
- end
228
+ def each(&bk)
229
+ rows.each(&bk)
230
+ end
55
231
 
56
- def each(&bk)
57
- rows.each(&bk)
232
+ include Enumerable
58
233
  end
59
234
 
60
- include Enumerable
235
+ private
236
+
237
+ def charset_for_mysql_encoding(mysql_encoding)
238
+ @mysql_encodings_map ||= {
239
+ "big5" => CHARSET_BIG5_CHINESE_CI,
240
+ "cp850" => CHARSET_CP850_GENERAL_CI,
241
+ "koi8r" => CHARSET_KOI8R_GENERAL_CI,
242
+ "latin1" => CHARSET_LATIN1_GENERAL_CI,
243
+ "latin2" => CHARSET_LATIN2_GENERAL_CI,
244
+ "ascii" => CHARSET_ASCII_GENERAL_CI,
245
+ "ujis" => CHARSET_UJIS_JAPANESE_CI,
246
+ "sjis" => CHARSET_SJIS_JAPANESE_CI,
247
+ "hebrew" => CHARSET_HEBREW_GENERAL_CI,
248
+ "tis620" => CHARSET_TIS620_THAI_CI,
249
+ "euckr" => CHARSET_EUCKR_KOREAN_CI,
250
+ "koi8u" => CHARSET_KOI8U_GENERAL_CI,
251
+ "gb2312" => CHARSET_GB2312_CHINESE_CI,
252
+ "greek" => CHARSET_GREEK_GENERAL_CI,
253
+ "cp1250" => CHARSET_CP1250_GENERAL_CI,
254
+ "gbk" => CHARSET_GBK_CHINESE_CI,
255
+ "latin5" => CHARSET_LATIN5_TURKISH_CI,
256
+ "utf8" => CHARSET_UTF8_GENERAL_CI,
257
+ "ucs2" => CHARSET_UCS2_GENERAL_CI,
258
+ "cp866" => CHARSET_CP866_GENERAL_CI,
259
+ "cp932" => CHARSET_CP932_JAPANESE_CI,
260
+ "eucjpms" => CHARSET_EUCJPMS_JAPANESE_CI,
261
+ "utf16le" => CHARSET_UTF16_GENERAL_CI,
262
+ "gb18030" => CHARSET_GB18030_CHINESE_CI,
263
+ "macce" => CHARSET_MACCE_GENERAL_CI,
264
+ "macroman" => CHARSET_MACROMAN_GENERAL_CI,
265
+ "cp852" => CHARSET_CP852_GENERAL_CI,
266
+ "latin7" => CHARSET_LATIN7_GENERAL_CI,
267
+ "utf8mb4" => CHARSET_UTF8MB4_GENERAL_CI,
268
+ "cp1251" => CHARSET_CP1251_GENERAL_CI,
269
+ "utf16" => CHARSET_UTF16_GENERAL_CI,
270
+ "cp1256" => CHARSET_CP1256_GENERAL_CI,
271
+ "cp1257" => CHARSET_CP1257_GENERAL_CI,
272
+ "utf32" => CHARSET_UTF32_GENERAL_CI,
273
+ "binary" => CHARSET_BINARY,
274
+ }.freeze
275
+ @mysql_encodings_map[mysql_encoding]
276
+ end
61
277
  end
278
+
279
+ require "trilogy/cext"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trilogy
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-17 00:00:00.000000000 Z
11
+ date: 2023-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -99,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
- rubygems_version: 3.3.3
102
+ rubygems_version: 3.4.7
103
103
  signing_key:
104
104
  specification_version: 4
105
105
  summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy