trilogy 2.5.0 → 2.6.1
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 +1 -2
- data/ext/trilogy-ruby/cext.c +16 -12
- data/ext/trilogy-ruby/extconf.rb +5 -1
- data/ext/trilogy-ruby/src/buffer.c +6 -1
- data/ext/trilogy-ruby/src/socket.c +25 -4
- data/lib/trilogy/error.rb +7 -1
- data/lib/trilogy/version.rb +1 -1
- data/lib/trilogy.rb +4 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d015527cefe1e66b73b4db1d31b98e3db6ab616edb1fb2da947054a55818f338
|
4
|
+
data.tar.gz: 315bdd0e7dabf0f37ed69f5cd0884a702a7502443b1e26e5b01bec90b122e11d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6e50321b8493b6ea8137d534e0fa8eedc5b7388093fee5e910dbe8c6bd81c0e0dc9c8d9c448895096fb8bd0244a0ee65b19b5f580c3b9137c76c9af221f0ab2
|
7
|
+
data.tar.gz: 7d8b81caf8faaadc4ef548ffddab7a73f9b8d4d6ede5a0f9078c6ea65cd195f83bdcacdf5a3d7b71d76503161a689d8ac66b058a4c605a915f9a9dcf4aa56cdd
|
data/README.md
CHANGED
@@ -27,7 +27,6 @@ $ gem install trilogy
|
|
27
27
|
``` ruby
|
28
28
|
client = Trilogy.new(host: "127.0.0.1", port: 3306, username: "root", read_timeout: 2)
|
29
29
|
if client.ping
|
30
|
-
client.query_options[:database_timezone] = :utc
|
31
30
|
client.change_db "mydb"
|
32
31
|
|
33
32
|
result = client.query("SELECT id, created_at FROM users LIMIT 10")
|
@@ -63,7 +62,7 @@ bundle exec rake build
|
|
63
62
|
|
64
63
|
The official Ruby bindings are inside of the canonical trilogy repository itself.
|
65
64
|
|
66
|
-
1. Fork it ( https://github.com/
|
65
|
+
1. Fork it ( https://github.com/trilogy-libraries/trilogy/fork )
|
67
66
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
67
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
69
68
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/ext/trilogy-ruby/cext.c
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
VALUE Trilogy_CastError;
|
19
19
|
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
20
20
|
Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError,
|
21
|
-
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result;
|
21
|
+
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_EOFError;
|
22
22
|
|
23
23
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
24
24
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
@@ -43,9 +43,7 @@ static void mark_trilogy(void *ptr)
|
|
43
43
|
static void free_trilogy(void *ptr)
|
44
44
|
{
|
45
45
|
struct trilogy_ctx *ctx = ptr;
|
46
|
-
|
47
|
-
trilogy_free(&ctx->conn);
|
48
|
-
}
|
46
|
+
trilogy_free(&ctx->conn);
|
49
47
|
xfree(ptr);
|
50
48
|
}
|
51
49
|
|
@@ -96,7 +94,7 @@ static void trilogy_syserr_fail_str(int e, VALUE msg)
|
|
96
94
|
rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg);
|
97
95
|
} else if (e == EPIPE) {
|
98
96
|
// Backwards compatibility: This error class makes no sense, but matches legacy behavior
|
99
|
-
rb_raise(
|
97
|
+
rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION: EPIPE", msg);
|
100
98
|
} else {
|
101
99
|
VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg);
|
102
100
|
rb_exc_raise(exc);
|
@@ -158,6 +156,10 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
158
156
|
rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE ": TRILOGY_DNS_ERROR", rbmsg);
|
159
157
|
}
|
160
158
|
|
159
|
+
case TRILOGY_CLOSED_CONNECTION: {
|
160
|
+
rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", rbmsg);
|
161
|
+
}
|
162
|
+
|
161
163
|
default:
|
162
164
|
rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": %s", rbmsg, trilogy_error(rc));
|
163
165
|
}
|
@@ -305,6 +307,7 @@ static int try_connect(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake,
|
|
305
307
|
int rc = args.rc;
|
306
308
|
|
307
309
|
if (rc != TRILOGY_OK) {
|
310
|
+
trilogy_sock_close(sock);
|
308
311
|
return rc;
|
309
312
|
}
|
310
313
|
|
@@ -312,8 +315,10 @@ static int try_connect(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake,
|
|
312
315
|
escape the GVL on each wait operation without going through call_without_gvl */
|
313
316
|
sock->wait_cb = _cb_ruby_wait;
|
314
317
|
rc = trilogy_connect_send_socket(&ctx->conn, sock);
|
315
|
-
if (rc < 0)
|
318
|
+
if (rc < 0) {
|
319
|
+
trilogy_sock_close(sock);
|
316
320
|
return rc;
|
321
|
+
}
|
317
322
|
|
318
323
|
while (1) {
|
319
324
|
rc = trilogy_connect_recv(&ctx->conn, handshake);
|
@@ -421,7 +426,7 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
421
426
|
}
|
422
427
|
}
|
423
428
|
|
424
|
-
static VALUE
|
429
|
+
static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE opts)
|
425
430
|
{
|
426
431
|
struct trilogy_ctx *ctx = get_ctx(self);
|
427
432
|
trilogy_sockopt_t connopt = {0};
|
@@ -432,7 +437,6 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VA
|
|
432
437
|
connopt.encoding = NUM2INT(charset);
|
433
438
|
|
434
439
|
Check_Type(opts, T_HASH);
|
435
|
-
rb_ivar_set(self, id_connection_options, opts);
|
436
440
|
|
437
441
|
if ((val = rb_hash_lookup(opts, ID2SYM(id_ssl_mode))) != Qnil) {
|
438
442
|
Check_Type(val, T_FIXNUM);
|
@@ -574,9 +578,6 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VA
|
|
574
578
|
}
|
575
579
|
|
576
580
|
int rc = try_connect(ctx, &handshake, &connopt);
|
577
|
-
if (rc == TRILOGY_TIMEOUT) {
|
578
|
-
rb_raise(Trilogy_TimeoutError, "trilogy_connect_recv");
|
579
|
-
}
|
580
581
|
if (rc != TRILOGY_OK) {
|
581
582
|
if (connopt.path) {
|
582
583
|
handle_trilogy_error(ctx, rc, "trilogy_connect - unable to connect to %s", connopt.path);
|
@@ -1100,7 +1101,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1100
1101
|
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
1101
1102
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
1102
1103
|
|
1103
|
-
rb_define_private_method(Trilogy, "
|
1104
|
+
rb_define_private_method(Trilogy, "_connect", rb_trilogy_connect, 3);
|
1104
1105
|
rb_define_method(Trilogy, "change_db", rb_trilogy_change_db, 1);
|
1105
1106
|
rb_define_alias(Trilogy, "select_db", "change_db");
|
1106
1107
|
rb_define_method(Trilogy, "query", rb_trilogy_query, 1);
|
@@ -1176,6 +1177,9 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1176
1177
|
Trilogy_CastError = rb_const_get(Trilogy, rb_intern("CastError"));
|
1177
1178
|
rb_global_variable(&Trilogy_CastError);
|
1178
1179
|
|
1180
|
+
Trilogy_EOFError = rb_const_get(Trilogy, rb_intern("EOFError"));
|
1181
|
+
rb_global_variable(&Trilogy_EOFError);
|
1182
|
+
|
1179
1183
|
id_socket = rb_intern("socket");
|
1180
1184
|
id_host = rb_intern("host");
|
1181
1185
|
id_port = rb_intern("port");
|
data/ext/trilogy-ruby/extconf.rb
CHANGED
@@ -2,8 +2,12 @@ require "mkmf"
|
|
2
2
|
|
3
3
|
# concatenate trilogy library sources to allow the compiler to optimise across
|
4
4
|
# source files
|
5
|
+
|
6
|
+
trilogy_src_dir = File.realpath("src", __dir__)
|
5
7
|
File.binwrite("trilogy.c",
|
6
|
-
Dir["#{
|
8
|
+
Dir["#{trilogy_src_dir}/**/*.c"].map { |src|
|
9
|
+
%{#line 1 "#{src}"\n} + File.binread(src)
|
10
|
+
}.join)
|
7
11
|
|
8
12
|
$objs = %w[trilogy.o cast.o cext.o]
|
9
13
|
$CFLAGS << " -I #{__dir__}/inc -std=gnu99 -fvisibility=hidden"
|
@@ -57,4 +57,9 @@ int trilogy_buffer_putc(trilogy_buffer_t *buffer, uint8_t c)
|
|
57
57
|
return TRILOGY_OK;
|
58
58
|
}
|
59
59
|
|
60
|
-
void trilogy_buffer_free(trilogy_buffer_t *buffer)
|
60
|
+
void trilogy_buffer_free(trilogy_buffer_t *buffer)
|
61
|
+
{
|
62
|
+
free(buffer->buff);
|
63
|
+
buffer->buff = NULL;
|
64
|
+
buffer->len = buffer->cap = 0;
|
65
|
+
}
|
@@ -100,8 +100,15 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
|
|
100
100
|
if (sock->fd != -1) {
|
101
101
|
rc = close(sock->fd);
|
102
102
|
}
|
103
|
+
|
103
104
|
if (sock->addr) {
|
104
|
-
|
105
|
+
if (sock->base.opts.hostname == NULL && sock->base.opts.path != NULL) {
|
106
|
+
/* We created these with calloc so must free them instead of calling freeaddrinfo */
|
107
|
+
free(sock->addr->ai_addr);
|
108
|
+
free(sock->addr);
|
109
|
+
} else {
|
110
|
+
freeaddrinfo(sock->addr);
|
111
|
+
}
|
105
112
|
}
|
106
113
|
|
107
114
|
free(sock->base.opts.hostname);
|
@@ -189,12 +196,21 @@ static int raw_connect_internal(struct trilogy_sock *sock, const struct addrinfo
|
|
189
196
|
{
|
190
197
|
int sockerr;
|
191
198
|
socklen_t sockerr_len = sizeof(sockerr);
|
199
|
+
int rc = TRILOGY_SYSERR;
|
192
200
|
|
193
201
|
sock->fd = socket(ai->ai_family, SOCK_STREAM, ai->ai_protocol);
|
194
202
|
if (sock->fd < 0) {
|
195
203
|
return TRILOGY_SYSERR;
|
196
204
|
}
|
197
205
|
|
206
|
+
#ifdef TCP_NODELAY
|
207
|
+
if (sock->addr->ai_family != PF_UNIX) {
|
208
|
+
int flags = 1;
|
209
|
+
if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) < 0) {
|
210
|
+
goto fail;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
#endif
|
198
214
|
if (sock->base.opts.keepalive_enabled) {
|
199
215
|
int flags = 1;
|
200
216
|
if (setsockopt(sock->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) < 0) {
|
@@ -236,8 +252,8 @@ static int raw_connect_internal(struct trilogy_sock *sock, const struct addrinfo
|
|
236
252
|
}
|
237
253
|
}
|
238
254
|
|
239
|
-
if (trilogy_sock_wait_write((trilogy_sock_t *)sock) < 0) {
|
240
|
-
goto
|
255
|
+
if ((rc = trilogy_sock_wait_write((trilogy_sock_t *)sock)) < 0) {
|
256
|
+
goto failrc;
|
241
257
|
}
|
242
258
|
|
243
259
|
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) < 0) {
|
@@ -255,9 +271,11 @@ static int raw_connect_internal(struct trilogy_sock *sock, const struct addrinfo
|
|
255
271
|
return TRILOGY_OK;
|
256
272
|
|
257
273
|
fail:
|
274
|
+
rc = TRILOGY_SYSERR;
|
275
|
+
failrc:
|
258
276
|
close(sock->fd);
|
259
277
|
sock->fd = -1;
|
260
|
-
return
|
278
|
+
return rc;
|
261
279
|
}
|
262
280
|
|
263
281
|
static int _cb_raw_connect(trilogy_sock_t *_sock)
|
@@ -369,6 +387,9 @@ static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
|
|
369
387
|
int rc = SSL_get_error(sock->ssl, (int)ret);
|
370
388
|
if (rc == SSL_ERROR_WANT_WRITE || rc == SSL_ERROR_WANT_READ) {
|
371
389
|
return (ssize_t)TRILOGY_AGAIN;
|
390
|
+
} else if (rc == SSL_ERROR_ZERO_RETURN) {
|
391
|
+
// Server has closed the connection for writing by sending the close_notify alert
|
392
|
+
return (ssize_t)TRILOGY_CLOSED_CONNECTION;
|
372
393
|
} else if (rc == SSL_ERROR_SYSCALL && !ERR_peek_error()) {
|
373
394
|
if (errno == 0) {
|
374
395
|
// On OpenSSL <= 1.1.1, SSL_ERROR_SYSCALL with an errno value
|
data/lib/trilogy/error.rb
CHANGED
@@ -20,7 +20,7 @@ class Trilogy
|
|
20
20
|
.select { |c| c.is_a?(Class) && c < SystemCallError }
|
21
21
|
.each do |c|
|
22
22
|
errno_name = c.to_s.split('::').last
|
23
|
-
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::
|
23
|
+
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::ConnectionError })
|
24
24
|
end
|
25
25
|
|
26
26
|
ERRORS.freeze
|
@@ -112,7 +112,13 @@ class Trilogy
|
|
112
112
|
include ConnectionError
|
113
113
|
end
|
114
114
|
|
115
|
+
# Raised on attempt to use connection which was explicitly closed by the user
|
115
116
|
class ConnectionClosed < IOError
|
116
117
|
include ConnectionError
|
117
118
|
end
|
119
|
+
|
120
|
+
# Occurs when a socket read or write returns EOF or when an operation is
|
121
|
+
# attempted on a socket which previously encountered an error.
|
122
|
+
class EOFError < BaseConnectionError
|
123
|
+
end
|
118
124
|
end
|
data/lib/trilogy/version.rb
CHANGED
data/lib/trilogy.rb
CHANGED
@@ -8,12 +8,14 @@ require "trilogy/encoding"
|
|
8
8
|
|
9
9
|
class Trilogy
|
10
10
|
def initialize(options = {})
|
11
|
-
options[:port] = options[:port].to_i if options
|
11
|
+
options[:port] = options[:port].to_i if options[:port]
|
12
12
|
mysql_encoding = options[:encoding] || "utf8mb4"
|
13
13
|
encoding = Trilogy::Encoding.find(mysql_encoding)
|
14
14
|
charset = Trilogy::Encoding.charset(mysql_encoding)
|
15
|
+
@connection_options = options
|
16
|
+
@connected_host = nil
|
15
17
|
|
16
|
-
|
18
|
+
_connect(encoding, charset, options)
|
17
19
|
end
|
18
20
|
|
19
21
|
def connection_options
|
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.
|
4
|
+
version: 2.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
requirements: []
|
105
|
-
rubygems_version: 3.4.
|
105
|
+
rubygems_version: 3.4.10
|
106
106
|
signing_key:
|
107
107
|
specification_version: 4
|
108
108
|
summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
|