trilogy 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +110 -33
- 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 +266 -2
- 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 -244
- 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