trilogy 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -5
- data/Rakefile +6 -0
- data/ext/trilogy-ruby/cast.c +0 -4
- data/ext/trilogy-ruby/cext.c +106 -34
- data/ext/trilogy-ruby/inc/trilogy/blocking.h +118 -0
- data/ext/trilogy-ruby/inc/trilogy/builder.h +60 -0
- data/ext/trilogy-ruby/inc/trilogy/client.h +214 -0
- data/ext/trilogy-ruby/inc/trilogy/error.h +4 -1
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +269 -3
- data/ext/trilogy-ruby/inc/trilogy/reader.h +4 -0
- data/ext/trilogy-ruby/inc/trilogy/socket.h +2 -1
- data/ext/trilogy-ruby/src/blocking.c +117 -0
- data/ext/trilogy-ruby/src/builder.c +63 -0
- data/ext/trilogy-ruby/src/client.c +180 -17
- data/ext/trilogy-ruby/src/protocol.c +503 -0
- data/ext/trilogy-ruby/src/reader.c +38 -0
- data/ext/trilogy-ruby/src/socket.c +96 -39
- data/lib/trilogy/encoding.rb +97 -0
- data/lib/trilogy/error.rb +118 -0
- data/lib/trilogy/result.rb +33 -0
- data/lib/trilogy/version.rb +1 -1
- data/lib/trilogy.rb +9 -239
- data/trilogy.gemspec +1 -1
- metadata +6 -3
@@ -1,5 +1,6 @@
|
|
1
1
|
#include <netdb.h>
|
2
2
|
#include <netinet/tcp.h>
|
3
|
+
#include <netinet/in.h>
|
3
4
|
#include <poll.h>
|
4
5
|
#include <sys/socket.h>
|
5
6
|
#include <sys/types.h>
|
@@ -65,7 +66,11 @@ static ssize_t _cb_raw_read(trilogy_sock_t *_sock, void *buf, size_t nread)
|
|
65
66
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
66
67
|
ssize_t data_read = read(sock->fd, buf, nread);
|
67
68
|
if (data_read < 0) {
|
68
|
-
|
69
|
+
if (errno == EINTR || errno == EAGAIN) {
|
70
|
+
return (ssize_t)TRILOGY_AGAIN;
|
71
|
+
} else {
|
72
|
+
return (ssize_t)TRILOGY_SYSERR;
|
73
|
+
}
|
69
74
|
}
|
70
75
|
return data_read;
|
71
76
|
}
|
@@ -75,6 +80,14 @@ static ssize_t _cb_raw_write(trilogy_sock_t *_sock, const void *buf, size_t nwri
|
|
75
80
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
76
81
|
ssize_t data_written = write(sock->fd, buf, nwrite);
|
77
82
|
if (data_written < 0) {
|
83
|
+
if (errno == EINTR || errno == EAGAIN) {
|
84
|
+
return (ssize_t)TRILOGY_AGAIN;
|
85
|
+
}
|
86
|
+
|
87
|
+
if (errno == EPIPE) {
|
88
|
+
return (ssize_t)TRILOGY_CLOSED_CONNECTION;
|
89
|
+
}
|
90
|
+
|
78
91
|
return (ssize_t)TRILOGY_SYSERR;
|
79
92
|
}
|
80
93
|
return data_written;
|
@@ -109,7 +122,53 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
|
|
109
122
|
return rc;
|
110
123
|
}
|
111
124
|
|
112
|
-
static int
|
125
|
+
static int _cb_shutdown_connect(trilogy_sock_t *_sock) {
|
126
|
+
(void)_sock;
|
127
|
+
return TRILOGY_CLOSED_CONNECTION;
|
128
|
+
}
|
129
|
+
static ssize_t _cb_shutdown_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite) {
|
130
|
+
(void)_sock;
|
131
|
+
(void)buf;
|
132
|
+
(void)nwrite;
|
133
|
+
return TRILOGY_CLOSED_CONNECTION;
|
134
|
+
}
|
135
|
+
static ssize_t _cb_shutdown_read(trilogy_sock_t *_sock, void *buf, size_t nread) {
|
136
|
+
(void)_sock;
|
137
|
+
(void)buf;
|
138
|
+
(void)nread;
|
139
|
+
return TRILOGY_CLOSED_CONNECTION;
|
140
|
+
}
|
141
|
+
static int _cb_shutdown_wait(trilogy_sock_t *_sock, trilogy_wait_t wait) {
|
142
|
+
(void)_sock;
|
143
|
+
(void)wait;
|
144
|
+
return TRILOGY_OK;
|
145
|
+
}
|
146
|
+
static int _cb_shutdown_shutdown(trilogy_sock_t *_sock) {
|
147
|
+
(void)_sock;
|
148
|
+
return TRILOGY_OK;
|
149
|
+
}
|
150
|
+
|
151
|
+
// Shutdown will close the underlying socket fd and replace all I/O operations with stubs which perform no action.
|
152
|
+
static int _cb_raw_shutdown(trilogy_sock_t *_sock) {
|
153
|
+
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
154
|
+
|
155
|
+
// Replace all operations with stubs which return immediately
|
156
|
+
sock->base.connect_cb = _cb_shutdown_connect;
|
157
|
+
sock->base.read_cb = _cb_shutdown_read;
|
158
|
+
sock->base.write_cb = _cb_shutdown_write;
|
159
|
+
sock->base.wait_cb = _cb_shutdown_wait;
|
160
|
+
sock->base.shutdown_cb = _cb_shutdown_shutdown;
|
161
|
+
|
162
|
+
// These "raw" callbacks won't attempt further operations on the socket and work correctly with fd set to -1
|
163
|
+
sock->base.close_cb = _cb_raw_close;
|
164
|
+
sock->base.fd_cb = _cb_raw_fd;
|
165
|
+
|
166
|
+
if (sock->fd != -1)
|
167
|
+
close(sock->fd);
|
168
|
+
sock->fd = -1;
|
169
|
+
|
170
|
+
return TRILOGY_OK;
|
171
|
+
}
|
113
172
|
|
114
173
|
static int set_nonblocking_fd(int sock)
|
115
174
|
{
|
@@ -306,12 +365,18 @@ fail:
|
|
306
365
|
|
307
366
|
static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
|
308
367
|
{
|
309
|
-
if (ret
|
368
|
+
if (ret <= 0) {
|
310
369
|
int rc = SSL_get_error(sock->ssl, (int)ret);
|
311
370
|
if (rc == SSL_ERROR_WANT_WRITE || rc == SSL_ERROR_WANT_READ) {
|
312
371
|
return (ssize_t)TRILOGY_AGAIN;
|
313
|
-
} else if (rc == SSL_ERROR_SYSCALL &&
|
314
|
-
|
372
|
+
} else if (rc == SSL_ERROR_SYSCALL && !ERR_peek_error()) {
|
373
|
+
if (errno == 0) {
|
374
|
+
// On OpenSSL <= 1.1.1, SSL_ERROR_SYSCALL with an errno value
|
375
|
+
// of 0 indicates unexpected EOF from the peer.
|
376
|
+
return (ssize_t)TRILOGY_CLOSED_CONNECTION;
|
377
|
+
} else {
|
378
|
+
return (ssize_t)TRILOGY_SYSERR;
|
379
|
+
}
|
315
380
|
}
|
316
381
|
return (ssize_t)TRILOGY_OPENSSL_ERR;
|
317
382
|
}
|
@@ -321,6 +386,11 @@ static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
|
|
321
386
|
static ssize_t _cb_ssl_read(trilogy_sock_t *_sock, void *buf, size_t nread)
|
322
387
|
{
|
323
388
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
389
|
+
|
390
|
+
// This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
|
391
|
+
// in the queue.
|
392
|
+
ERR_clear_error();
|
393
|
+
|
324
394
|
ssize_t data_read = (ssize_t)SSL_read(sock->ssl, buf, (int)nread);
|
325
395
|
return ssl_io_return(sock, data_read);
|
326
396
|
}
|
@@ -328,6 +398,11 @@ static ssize_t _cb_ssl_read(trilogy_sock_t *_sock, void *buf, size_t nread)
|
|
328
398
|
static ssize_t _cb_ssl_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite)
|
329
399
|
{
|
330
400
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
401
|
+
|
402
|
+
// This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
|
403
|
+
// in the queue.
|
404
|
+
ERR_clear_error();
|
405
|
+
|
331
406
|
ssize_t data_written = (ssize_t)SSL_write(sock->ssl, buf, (int)nwrite);
|
332
407
|
return ssl_io_return(sock, data_written);
|
333
408
|
}
|
@@ -340,15 +415,9 @@ static int _cb_ssl_shutdown(trilogy_sock_t *_sock)
|
|
340
415
|
// we need to close it. The OpenSSL explicitly states
|
341
416
|
// not to call SSL_shutdown on a broken SSL socket.
|
342
417
|
SSL_free(sock->ssl);
|
343
|
-
// Reset the handlers since we tore down SSL, so we
|
344
|
-
// fall back to the regular methods for detecting
|
345
|
-
// we have a closed connection and for the cleanup.
|
346
|
-
sock->base.read_cb = _cb_raw_read;
|
347
|
-
sock->base.write_cb = _cb_raw_write;
|
348
|
-
sock->base.shutdown_cb = _cb_raw_shutdown;
|
349
|
-
sock->base.close_cb = _cb_raw_close;
|
350
418
|
sock->ssl = NULL;
|
351
419
|
|
420
|
+
// This will rewrite the handlers
|
352
421
|
return _cb_raw_shutdown(_sock);
|
353
422
|
}
|
354
423
|
|
@@ -356,7 +425,12 @@ static int _cb_ssl_close(trilogy_sock_t *_sock)
|
|
356
425
|
{
|
357
426
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
358
427
|
if (sock->ssl != NULL) {
|
359
|
-
|
428
|
+
if (SSL_in_init(sock->ssl) == 0) {
|
429
|
+
(void)SSL_shutdown(sock->ssl);
|
430
|
+
// SSL_shutdown might return WANT_WRITE or WANT_READ. Ideally we would retry but we don't want to block.
|
431
|
+
// It may also push an error onto the OpenSSL error queue, so clear that.
|
432
|
+
ERR_clear_error();
|
433
|
+
}
|
360
434
|
SSL_free(sock->ssl);
|
361
435
|
sock->ssl = NULL;
|
362
436
|
}
|
@@ -537,6 +611,10 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
|
|
537
611
|
{
|
538
612
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
539
613
|
|
614
|
+
// This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
|
615
|
+
// in the queue.
|
616
|
+
ERR_clear_error();
|
617
|
+
|
540
618
|
SSL_CTX *ctx = trilogy_ssl_ctx(&sock->base.opts);
|
541
619
|
|
542
620
|
if (!ctx) {
|
@@ -548,7 +626,7 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
|
|
548
626
|
|
549
627
|
if (sock->base.opts.ssl_mode == TRILOGY_SSL_VERIFY_IDENTITY && sock->base.opts.hostname == NULL) {
|
550
628
|
// If hostname validation is requested and no hostname provided, treat it as an error.
|
551
|
-
#
|
629
|
+
#ifdef SSL_F_TLS_PROCESS_SERVER_CERTIFICATE
|
552
630
|
ERR_put_error(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
|
553
631
|
#else
|
554
632
|
ERR_put_error(ERR_LIB_SSL, SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
|
@@ -579,6 +657,10 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
|
|
579
657
|
goto fail;
|
580
658
|
|
581
659
|
for (;;) {
|
660
|
+
// This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
|
661
|
+
// in the queue.
|
662
|
+
ERR_clear_error();
|
663
|
+
|
582
664
|
int ret = SSL_connect(sock->ssl);
|
583
665
|
if (ret == 1) {
|
584
666
|
#if OPENSSL_VERSION_NUMBER < 0x1000200fL
|
@@ -621,28 +703,3 @@ fail:
|
|
621
703
|
sock->ssl = NULL;
|
622
704
|
return TRILOGY_OPENSSL_ERR;
|
623
705
|
}
|
624
|
-
|
625
|
-
int trilogy_sock_discard(trilogy_sock_t *_sock)
|
626
|
-
{
|
627
|
-
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
628
|
-
|
629
|
-
if (sock->fd < 0) {
|
630
|
-
return TRILOGY_OK;
|
631
|
-
}
|
632
|
-
|
633
|
-
int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
|
634
|
-
if (null_fd < 0) {
|
635
|
-
return TRILOGY_SYSERR;
|
636
|
-
}
|
637
|
-
|
638
|
-
if (dup2(null_fd, sock->fd) < 0) {
|
639
|
-
close(null_fd);
|
640
|
-
return TRILOGY_SYSERR;
|
641
|
-
}
|
642
|
-
|
643
|
-
if (close(null_fd) < 0) {
|
644
|
-
return TRILOGY_SYSERR;
|
645
|
-
}
|
646
|
-
|
647
|
-
return TRILOGY_OK;
|
648
|
-
}
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class Trilogy
|
2
|
+
module Encoding
|
3
|
+
RUBY_ENCODINGS = {
|
4
|
+
"big5" => "Big5",
|
5
|
+
"dec8" => nil,
|
6
|
+
"cp850" => "CP850",
|
7
|
+
"hp8" => nil,
|
8
|
+
"koi8r" => "KOI8-R",
|
9
|
+
"latin1" => "ISO-8859-1",
|
10
|
+
"latin2" => "ISO-8859-2",
|
11
|
+
"swe7" => nil,
|
12
|
+
"ascii" => "US-ASCII",
|
13
|
+
"ujis" => "eucJP-ms",
|
14
|
+
"sjis" => "Shift_JIS",
|
15
|
+
"hebrew" => "ISO-8859-8",
|
16
|
+
"tis620" => "TIS-620",
|
17
|
+
"euckr" => "EUC-KR",
|
18
|
+
"koi8u" => "KOI8-R",
|
19
|
+
"gb2312" => "GB2312",
|
20
|
+
"greek" => "ISO-8859-7",
|
21
|
+
"cp1250" => "Windows-1250",
|
22
|
+
"gbk" => "GBK",
|
23
|
+
"latin5" => "ISO-8859-9",
|
24
|
+
"armscii8" => nil,
|
25
|
+
"utf8" => "UTF-8",
|
26
|
+
"ucs2" => "UTF-16BE",
|
27
|
+
"cp866" => "IBM866",
|
28
|
+
"keybcs2" => nil,
|
29
|
+
"macce" => "macCentEuro",
|
30
|
+
"macroman" => "macRoman",
|
31
|
+
"cp852" => "CP852",
|
32
|
+
"latin7" => "ISO-8859-13",
|
33
|
+
"utf8mb4" => "UTF-8",
|
34
|
+
"cp1251" => "Windows-1251",
|
35
|
+
"utf16" => "UTF-16",
|
36
|
+
"cp1256" => "Windows-1256",
|
37
|
+
"cp1257" => "Windows-1257",
|
38
|
+
"utf32" => "UTF-32",
|
39
|
+
"binary" => "ASCII-8BIT",
|
40
|
+
"geostd8" => nil,
|
41
|
+
"cp932" => "Windows-31J",
|
42
|
+
"eucjpms" => "eucJP-ms",
|
43
|
+
"utf16le" => "UTF-16LE",
|
44
|
+
"gb18030" => "GB18030",
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
CHARSETS = {
|
48
|
+
"big5" => CHARSET_BIG5_CHINESE_CI,
|
49
|
+
"cp850" => CHARSET_CP850_GENERAL_CI,
|
50
|
+
"koi8r" => CHARSET_KOI8R_GENERAL_CI,
|
51
|
+
"latin1" => CHARSET_LATIN1_GENERAL_CI,
|
52
|
+
"latin2" => CHARSET_LATIN2_GENERAL_CI,
|
53
|
+
"ascii" => CHARSET_ASCII_GENERAL_CI,
|
54
|
+
"ujis" => CHARSET_UJIS_JAPANESE_CI,
|
55
|
+
"sjis" => CHARSET_SJIS_JAPANESE_CI,
|
56
|
+
"hebrew" => CHARSET_HEBREW_GENERAL_CI,
|
57
|
+
"tis620" => CHARSET_TIS620_THAI_CI,
|
58
|
+
"euckr" => CHARSET_EUCKR_KOREAN_CI,
|
59
|
+
"koi8u" => CHARSET_KOI8U_GENERAL_CI,
|
60
|
+
"gb2312" => CHARSET_GB2312_CHINESE_CI,
|
61
|
+
"greek" => CHARSET_GREEK_GENERAL_CI,
|
62
|
+
"cp1250" => CHARSET_CP1250_GENERAL_CI,
|
63
|
+
"gbk" => CHARSET_GBK_CHINESE_CI,
|
64
|
+
"latin5" => CHARSET_LATIN5_TURKISH_CI,
|
65
|
+
"utf8" => CHARSET_UTF8_GENERAL_CI,
|
66
|
+
"ucs2" => CHARSET_UCS2_GENERAL_CI,
|
67
|
+
"cp866" => CHARSET_CP866_GENERAL_CI,
|
68
|
+
"cp932" => CHARSET_CP932_JAPANESE_CI,
|
69
|
+
"eucjpms" => CHARSET_EUCJPMS_JAPANESE_CI,
|
70
|
+
"utf16le" => CHARSET_UTF16_GENERAL_CI,
|
71
|
+
"gb18030" => CHARSET_GB18030_CHINESE_CI,
|
72
|
+
"macce" => CHARSET_MACCE_GENERAL_CI,
|
73
|
+
"macroman" => CHARSET_MACROMAN_GENERAL_CI,
|
74
|
+
"cp852" => CHARSET_CP852_GENERAL_CI,
|
75
|
+
"latin7" => CHARSET_LATIN7_GENERAL_CI,
|
76
|
+
"utf8mb4" => CHARSET_UTF8MB4_GENERAL_CI,
|
77
|
+
"cp1251" => CHARSET_CP1251_GENERAL_CI,
|
78
|
+
"utf16" => CHARSET_UTF16_GENERAL_CI,
|
79
|
+
"cp1256" => CHARSET_CP1256_GENERAL_CI,
|
80
|
+
"cp1257" => CHARSET_CP1257_GENERAL_CI,
|
81
|
+
"utf32" => CHARSET_UTF32_GENERAL_CI,
|
82
|
+
"binary" => CHARSET_BINARY,
|
83
|
+
}.freeze
|
84
|
+
|
85
|
+
def self.find(mysql_encoding)
|
86
|
+
unless rb_encoding = RUBY_ENCODINGS[mysql_encoding]
|
87
|
+
raise ArgumentError, "Unknown or unsupported encoding: #{mysql_encoding}"
|
88
|
+
end
|
89
|
+
|
90
|
+
::Encoding.find(rb_encoding)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.charset(mysql_encoding)
|
94
|
+
CHARSETS[mysql_encoding]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class Trilogy
|
2
|
+
# Trilogy::Error is the base error type. All errors raised by Trilogy
|
3
|
+
# should be descendants of Trilogy::Error
|
4
|
+
module Error
|
5
|
+
attr_reader :error_code
|
6
|
+
end
|
7
|
+
|
8
|
+
# Trilogy::ConnectionError is the base error type for all potentially transient
|
9
|
+
# network errors.
|
10
|
+
module ConnectionError
|
11
|
+
include Error
|
12
|
+
end
|
13
|
+
|
14
|
+
# Trilogy may raise various syscall errors, which we treat as Trilogy::Errors.
|
15
|
+
class SyscallError
|
16
|
+
ERRORS = {}
|
17
|
+
|
18
|
+
Errno.constants
|
19
|
+
.map { |c| Errno.const_get(c) }.uniq
|
20
|
+
.select { |c| c.is_a?(Class) && c < SystemCallError }
|
21
|
+
.each do |c|
|
22
|
+
errno_name = c.to_s.split('::').last
|
23
|
+
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::Error })
|
24
|
+
end
|
25
|
+
|
26
|
+
ERRORS.freeze
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def from_errno(errno, message)
|
30
|
+
ERRORS[errno].new(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class BaseError < StandardError
|
36
|
+
include Error
|
37
|
+
|
38
|
+
def initialize(error_message = nil, error_code = nil)
|
39
|
+
message = error_code ? "#{error_code}: #{error_message}" : error_message
|
40
|
+
super(message)
|
41
|
+
@error_code = error_code
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class BaseConnectionError < BaseError
|
46
|
+
include ConnectionError
|
47
|
+
end
|
48
|
+
|
49
|
+
# Trilogy::ClientError is the base error type for invalid queries or parameters
|
50
|
+
# that shouldn't be retried.
|
51
|
+
class ClientError < BaseError
|
52
|
+
include Error
|
53
|
+
end
|
54
|
+
|
55
|
+
class QueryError < ClientError
|
56
|
+
end
|
57
|
+
|
58
|
+
class CastError < ClientError
|
59
|
+
end
|
60
|
+
|
61
|
+
class TimeoutError < Errno::ETIMEDOUT
|
62
|
+
include ConnectionError
|
63
|
+
|
64
|
+
def initialize(error_message = nil, error_code = nil)
|
65
|
+
super
|
66
|
+
@error_code = error_code
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class ConnectionRefusedError < Errno::ECONNREFUSED
|
71
|
+
include ConnectionError
|
72
|
+
end
|
73
|
+
|
74
|
+
class ConnectionResetError < Errno::ECONNRESET
|
75
|
+
include ConnectionError
|
76
|
+
end
|
77
|
+
|
78
|
+
# DatabaseError was replaced by ProtocolError, but we'll keep it around as an
|
79
|
+
# ancestor of ProtocolError for compatibility reasons (e.g. so `rescue DatabaseError`
|
80
|
+
# still works. We can remove this class in the next major release.
|
81
|
+
module DatabaseError
|
82
|
+
end
|
83
|
+
|
84
|
+
class ProtocolError < BaseError
|
85
|
+
include DatabaseError
|
86
|
+
|
87
|
+
ERROR_CODES = {
|
88
|
+
1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
|
89
|
+
1044 => BaseConnectionError, # ER_DBACCESS_DENIED_ERROR
|
90
|
+
1045 => BaseConnectionError, # ER_ACCESS_DENIED_ERROR
|
91
|
+
1064 => QueryError, # ER_PARSE_ERROR
|
92
|
+
1152 => BaseConnectionError, # ER_ABORTING_CONNECTION
|
93
|
+
1153 => BaseConnectionError, # ER_NET_PACKET_TOO_LARGE
|
94
|
+
1154 => BaseConnectionError, # ER_NET_READ_ERROR_FROM_PIPE
|
95
|
+
1155 => BaseConnectionError, # ER_NET_FCNTL_ERROR
|
96
|
+
1156 => BaseConnectionError, # ER_NET_PACKETS_OUT_OF_ORDER
|
97
|
+
1157 => BaseConnectionError, # ER_NET_UNCOMPRESS_ERROR
|
98
|
+
1158 => BaseConnectionError, # ER_NET_READ_ERROR
|
99
|
+
1159 => BaseConnectionError, # ER_NET_READ_INTERRUPTED
|
100
|
+
1160 => BaseConnectionError, # ER_NET_ERROR_ON_WRITE
|
101
|
+
1161 => BaseConnectionError, # ER_NET_WRITE_INTERRUPTED
|
102
|
+
1927 => BaseConnectionError, # ER_CONNECTION_KILLED
|
103
|
+
}
|
104
|
+
class << self
|
105
|
+
def from_code(message, code)
|
106
|
+
ERROR_CODES.fetch(code, self).new(message, code)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class SSLError < BaseError
|
112
|
+
include ConnectionError
|
113
|
+
end
|
114
|
+
|
115
|
+
class ConnectionClosed < IOError
|
116
|
+
include ConnectionError
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Trilogy
|
2
|
+
class Result
|
3
|
+
attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
|
4
|
+
|
5
|
+
def count
|
6
|
+
rows.count
|
7
|
+
end
|
8
|
+
|
9
|
+
def each_hash
|
10
|
+
return enum_for(:each_hash) unless block_given?
|
11
|
+
|
12
|
+
rows.each do |row|
|
13
|
+
this_row = {}
|
14
|
+
|
15
|
+
idx = 0
|
16
|
+
row.each do |col|
|
17
|
+
this_row[fields[idx]] = col
|
18
|
+
idx += 1
|
19
|
+
end
|
20
|
+
|
21
|
+
yield this_row
|
22
|
+
end
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def each(&bk)
|
28
|
+
rows.each(&bk)
|
29
|
+
end
|
30
|
+
|
31
|
+
include Enumerable
|
32
|
+
end
|
33
|
+
end
|
data/lib/trilogy/version.rb
CHANGED