trilogy 2.9.0 → 2.12.4
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 -1
- data/Rakefile +16 -1
- data/ext/trilogy-ruby/cast.c +181 -55
- data/ext/trilogy-ruby/cext.c +337 -125
- data/ext/trilogy-ruby/extconf.rb +15 -3
- data/ext/trilogy-ruby/inc/trilogy/allocator.h +61 -0
- data/ext/trilogy-ruby/inc/trilogy/buffer.h +13 -0
- data/ext/trilogy-ruby/inc/trilogy/client.h +11 -0
- data/ext/trilogy-ruby/inc/trilogy/error.h +2 -1
- data/ext/trilogy-ruby/inc/trilogy/socket.h +2 -0
- data/ext/trilogy-ruby/inc/trilogy.h +1 -0
- data/ext/trilogy-ruby/src/buffer.c +25 -5
- data/ext/trilogy-ruby/src/client.c +425 -99
- data/ext/trilogy-ruby/src/packet_parser.c +1 -1
- data/ext/trilogy-ruby/src/socket.c +39 -29
- data/ext/trilogy-ruby/trilogy-ruby.h +4 -2
- data/ext/trilogy-ruby/trilogy_xallocator.h +1 -0
- data/lib/trilogy/encoding.rb +2 -0
- data/lib/trilogy/error.rb +7 -0
- data/lib/trilogy/result.rb +18 -0
- data/lib/trilogy/version.rb +1 -1
- data/lib/trilogy.rb +81 -1
- data/trilogy.gemspec +3 -2
- metadata +12 -24
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <stdlib.h>
|
|
12
12
|
#include <unistd.h>
|
|
13
13
|
|
|
14
|
+
#include "trilogy/allocator.h"
|
|
14
15
|
#include "trilogy/error.h"
|
|
15
16
|
#include "trilogy/socket.h"
|
|
16
17
|
|
|
@@ -21,10 +22,17 @@
|
|
|
21
22
|
struct trilogy_sock {
|
|
22
23
|
trilogy_sock_t base;
|
|
23
24
|
struct addrinfo *addr;
|
|
24
|
-
int fd;
|
|
25
25
|
SSL *ssl;
|
|
26
|
+
int fd;
|
|
27
|
+
bool freeaddrinfo;
|
|
26
28
|
};
|
|
27
29
|
|
|
30
|
+
void trilogy_sock_set_fd(trilogy_sock_t *_sock, int fd)
|
|
31
|
+
{
|
|
32
|
+
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
|
33
|
+
sock->fd = fd;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
static int _cb_raw_fd(trilogy_sock_t *_sock)
|
|
29
37
|
{
|
|
30
38
|
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
|
@@ -103,30 +111,30 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
|
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
if (sock->addr) {
|
|
106
|
-
if (sock->
|
|
107
|
-
/* We created these with calloc so must free them instead of calling freeaddrinfo */
|
|
108
|
-
free(sock->addr->ai_addr);
|
|
109
|
-
free(sock->addr);
|
|
110
|
-
} else {
|
|
114
|
+
if (sock->freeaddrinfo) {
|
|
111
115
|
freeaddrinfo(sock->addr);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
116
|
+
} else {
|
|
117
|
+
/* We created these with xcalloc so must free them instead of calling freeaddrinfo */
|
|
118
|
+
xfree(sock->addr->ai_addr);
|
|
119
|
+
xfree(sock->addr);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
xfree(sock->base.opts.hostname);
|
|
124
|
+
xfree(sock->base.opts.path);
|
|
125
|
+
xfree(sock->base.opts.database);
|
|
126
|
+
xfree(sock->base.opts.username);
|
|
127
|
+
xfree(sock->base.opts.password);
|
|
128
|
+
xfree(sock->base.opts.ssl_ca);
|
|
129
|
+
xfree(sock->base.opts.ssl_capath);
|
|
130
|
+
xfree(sock->base.opts.ssl_cert);
|
|
131
|
+
xfree(sock->base.opts.ssl_cipher);
|
|
132
|
+
xfree(sock->base.opts.ssl_crl);
|
|
133
|
+
xfree(sock->base.opts.ssl_crlpath);
|
|
134
|
+
xfree(sock->base.opts.ssl_key);
|
|
135
|
+
xfree(sock->base.opts.tls_ciphersuites);
|
|
136
|
+
|
|
137
|
+
xfree(sock);
|
|
130
138
|
return rc;
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -300,12 +308,12 @@ static char *strdupnullok(const char *str)
|
|
|
300
308
|
if (str == NULL) {
|
|
301
309
|
return NULL;
|
|
302
310
|
}
|
|
303
|
-
return
|
|
311
|
+
return xstrdup(str);
|
|
304
312
|
}
|
|
305
313
|
|
|
306
314
|
trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
|
|
307
315
|
{
|
|
308
|
-
struct trilogy_sock *sock =
|
|
316
|
+
struct trilogy_sock *sock = xmalloc(sizeof(struct trilogy_sock));
|
|
309
317
|
|
|
310
318
|
sock->base.connect_cb = _cb_raw_connect;
|
|
311
319
|
sock->base.read_cb = _cb_raw_read;
|
|
@@ -322,7 +330,7 @@ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
|
|
|
322
330
|
sock->base.opts.username = strdupnullok(opts->username);
|
|
323
331
|
|
|
324
332
|
if (sock->base.opts.password) {
|
|
325
|
-
sock->base.opts.password =
|
|
333
|
+
sock->base.opts.password = xmalloc(opts->password_len);
|
|
326
334
|
memcpy(sock->base.opts.password, opts->password, opts->password_len);
|
|
327
335
|
}
|
|
328
336
|
|
|
@@ -352,6 +360,7 @@ int trilogy_sock_resolve(trilogy_sock_t *_sock)
|
|
|
352
360
|
char port[6];
|
|
353
361
|
snprintf(port, sizeof(port), "%hu", sock->base.opts.port);
|
|
354
362
|
|
|
363
|
+
sock->freeaddrinfo = true;
|
|
355
364
|
if (getaddrinfo(sock->base.opts.hostname, port, &hint, &sock->addr) != 0) {
|
|
356
365
|
return TRILOGY_DNS_ERR;
|
|
357
366
|
}
|
|
@@ -362,15 +371,16 @@ int trilogy_sock_resolve(trilogy_sock_t *_sock)
|
|
|
362
371
|
goto fail;
|
|
363
372
|
}
|
|
364
373
|
|
|
365
|
-
sa =
|
|
374
|
+
sa = xcalloc(1, sizeof(struct sockaddr_un));
|
|
366
375
|
sa->sun_family = AF_UNIX;
|
|
367
376
|
strcpy(sa->sun_path, sock->base.opts.path);
|
|
368
377
|
|
|
369
|
-
sock->addr =
|
|
378
|
+
sock->addr = xcalloc(1, sizeof(struct addrinfo));
|
|
370
379
|
sock->addr->ai_family = PF_UNIX;
|
|
371
380
|
sock->addr->ai_socktype = SOCK_STREAM;
|
|
372
381
|
sock->addr->ai_addr = (struct sockaddr *)sa;
|
|
373
382
|
sock->addr->ai_addrlen = sizeof(struct sockaddr_un);
|
|
383
|
+
sock->freeaddrinfo = false;
|
|
374
384
|
} else {
|
|
375
385
|
goto fail;
|
|
376
386
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#ifndef TRILOGY_RUBY_H
|
|
2
2
|
#define TRILOGY_RUBY_H
|
|
3
3
|
|
|
4
|
-
#include <
|
|
5
|
-
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
#include <trilogy_xallocator.h>
|
|
6
6
|
#include <trilogy.h>
|
|
7
7
|
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
|
|
8
10
|
#define TRILOGY_FLAGS_CAST 1
|
|
9
11
|
#define TRILOGY_FLAGS_CAST_BOOLEANS 2
|
|
10
12
|
#define TRILOGY_FLAGS_LOCAL_TIMEZONE 4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#include <ruby.h>
|
data/lib/trilogy/encoding.rb
CHANGED
data/lib/trilogy/error.rb
CHANGED
|
@@ -54,6 +54,12 @@ class Trilogy
|
|
|
54
54
|
include ConnectionError
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
class SynchronizationError < BaseError
|
|
58
|
+
def initialize(message = "This connection is already in use by another thread or fiber")
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
57
63
|
# Trilogy::ClientError is the base error type for invalid queries or parameters
|
|
58
64
|
# that shouldn't be retried.
|
|
59
65
|
class ClientError < BaseError
|
|
@@ -94,6 +100,7 @@ class Trilogy
|
|
|
94
100
|
1160 => BaseConnectionError, # ER_NET_ERROR_ON_WRITE
|
|
95
101
|
1161 => BaseConnectionError, # ER_NET_WRITE_INTERRUPTED
|
|
96
102
|
1927 => BaseConnectionError, # ER_CONNECTION_KILLED
|
|
103
|
+
4031 => BaseConnectionError, # Disconnected by server
|
|
97
104
|
}
|
|
98
105
|
class << self
|
|
99
106
|
def from_code(message, code)
|
data/lib/trilogy/result.rb
CHANGED
|
@@ -2,10 +2,28 @@ class Trilogy
|
|
|
2
2
|
class Result
|
|
3
3
|
attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
|
|
4
4
|
|
|
5
|
+
EMPTY_ARRAY = [].freeze
|
|
6
|
+
private_constant :EMPTY_ARRAY
|
|
7
|
+
|
|
8
|
+
def initialize(fields, rows, query_time, in_transaction, affected_rows, last_insert_id)
|
|
9
|
+
@fields = fields || EMPTY_ARRAY
|
|
10
|
+
@rows = rows || EMPTY_ARRAY
|
|
11
|
+
@query_time = query_time
|
|
12
|
+
@in_transaction = in_transaction
|
|
13
|
+
@affected_rows = affected_rows
|
|
14
|
+
@last_insert_id = last_insert_id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def in_transaction?
|
|
18
|
+
@in_transaction
|
|
19
|
+
end
|
|
20
|
+
|
|
5
21
|
def count
|
|
6
22
|
rows.count
|
|
7
23
|
end
|
|
8
24
|
|
|
25
|
+
alias_method :size, :count
|
|
26
|
+
|
|
9
27
|
def each_hash
|
|
10
28
|
return enum_for(:each_hash) unless block_given?
|
|
11
29
|
|
data/lib/trilogy/version.rb
CHANGED
data/lib/trilogy.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "socket"
|
|
3
4
|
require "trilogy/version"
|
|
4
5
|
require "trilogy/error"
|
|
5
6
|
require "trilogy/result"
|
|
@@ -7,6 +8,38 @@ require "trilogy/cext"
|
|
|
7
8
|
require "trilogy/encoding"
|
|
8
9
|
|
|
9
10
|
class Trilogy
|
|
11
|
+
IO_TIMEOUT_ERROR =
|
|
12
|
+
if defined?(IO::TimeoutError)
|
|
13
|
+
IO::TimeoutError
|
|
14
|
+
else
|
|
15
|
+
Class.new(StandardError)
|
|
16
|
+
end
|
|
17
|
+
private_constant :IO_TIMEOUT_ERROR
|
|
18
|
+
|
|
19
|
+
module Synchronization
|
|
20
|
+
def initialize(...)
|
|
21
|
+
@mutex = Mutex.new
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
synchronized_methods = Trilogy.public_instance_methods(false) - %i(closed? server_version)
|
|
26
|
+
source = synchronized_methods.flat_map do |method|
|
|
27
|
+
[
|
|
28
|
+
"def #{method}(...)",
|
|
29
|
+
"raise SynchronizationError unless @mutex.try_lock",
|
|
30
|
+
"begin",
|
|
31
|
+
"super",
|
|
32
|
+
"ensure",
|
|
33
|
+
"@mutex.unlock",
|
|
34
|
+
"end",
|
|
35
|
+
"end",
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
class_eval(source.join(";"), __FILE__, __LINE__)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
prepend(Synchronization)
|
|
42
|
+
|
|
10
43
|
def initialize(options = {})
|
|
11
44
|
options[:port] = options[:port].to_i if options[:port]
|
|
12
45
|
mysql_encoding = options[:encoding] || "utf8mb4"
|
|
@@ -15,7 +48,54 @@ class Trilogy
|
|
|
15
48
|
@connection_options = options
|
|
16
49
|
@connected_host = nil
|
|
17
50
|
|
|
18
|
-
|
|
51
|
+
socket = nil
|
|
52
|
+
begin
|
|
53
|
+
if host = options[:host]
|
|
54
|
+
port = options[:port] || 3306
|
|
55
|
+
connect_timeout = options[:connect_timeout] || options[:write_timeout]
|
|
56
|
+
|
|
57
|
+
socket = TCPSocket.new(host, port, connect_timeout: connect_timeout)
|
|
58
|
+
|
|
59
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
60
|
+
|
|
61
|
+
if keepalive_enabled = options[:keepalive_enabled]
|
|
62
|
+
keepalive_idle = options[:keepalive_idle]
|
|
63
|
+
keepalive_interval = options[:keepalive_interval]
|
|
64
|
+
keepalive_count = options[:keepalive_count]
|
|
65
|
+
|
|
66
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
|
67
|
+
|
|
68
|
+
if keepalive_idle > 0 && defined?(Socket::TCP_KEEPIDLE)
|
|
69
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, keepalive_idle)
|
|
70
|
+
end
|
|
71
|
+
if keepalive_interval > 0 && defined?(Socket::TCP_KEEPINTVL)
|
|
72
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, keepalive_interval)
|
|
73
|
+
end
|
|
74
|
+
if keepalive_count > 0 && defined?(Socket::TCP_KEEPCNT)
|
|
75
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, keepalive_count)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
path = options[:socket] ||= "/tmp/mysql.sock"
|
|
80
|
+
socket = UNIXSocket.new(path)
|
|
81
|
+
end
|
|
82
|
+
rescue Errno::ETIMEDOUT, IO_TIMEOUT_ERROR => e
|
|
83
|
+
raise Trilogy::TimeoutError, e.message
|
|
84
|
+
rescue SocketError => e
|
|
85
|
+
connection_str = host ? "#{host}:#{port}" : path
|
|
86
|
+
raise Trilogy::BaseConnectionError, "unable to connect to \"#{connection_str}\": #{e.message}"
|
|
87
|
+
rescue => e
|
|
88
|
+
if e.respond_to?(:errno)
|
|
89
|
+
raise Trilogy::SyscallError.from_errno(e.errno, e.message)
|
|
90
|
+
else
|
|
91
|
+
raise
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
_connect(socket, encoding, charset, options)
|
|
96
|
+
ensure
|
|
97
|
+
# Socket's fd will be dup'd in C
|
|
98
|
+
socket&.close
|
|
19
99
|
end
|
|
20
100
|
|
|
21
101
|
def connection_options
|
data/trilogy.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,43 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trilogy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.12.4
|
|
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: 2026-04-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: bigdecimal
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
20
|
-
type: :
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: minitest
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - "~>"
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '5.5'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - "~>"
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '5.5'
|
|
26
|
+
version: '0'
|
|
41
27
|
description:
|
|
42
28
|
email: opensource+trilogy@github.com
|
|
43
29
|
executables: []
|
|
@@ -52,6 +38,7 @@ files:
|
|
|
52
38
|
- ext/trilogy-ruby/cext.c
|
|
53
39
|
- ext/trilogy-ruby/extconf.rb
|
|
54
40
|
- ext/trilogy-ruby/inc/trilogy.h
|
|
41
|
+
- ext/trilogy-ruby/inc/trilogy/allocator.h
|
|
55
42
|
- ext/trilogy-ruby/inc/trilogy/blocking.h
|
|
56
43
|
- ext/trilogy-ruby/inc/trilogy/buffer.h
|
|
57
44
|
- ext/trilogy-ruby/inc/trilogy/builder.h
|
|
@@ -77,6 +64,7 @@ files:
|
|
|
77
64
|
- ext/trilogy-ruby/src/vendor/curl_hostcheck.c
|
|
78
65
|
- ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c
|
|
79
66
|
- ext/trilogy-ruby/trilogy-ruby.h
|
|
67
|
+
- ext/trilogy-ruby/trilogy_xallocator.h
|
|
80
68
|
- lib/trilogy.rb
|
|
81
69
|
- lib/trilogy/encoding.rb
|
|
82
70
|
- lib/trilogy/error.rb
|
|
@@ -95,14 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
95
83
|
requirements:
|
|
96
84
|
- - ">="
|
|
97
85
|
- !ruby/object:Gem::Version
|
|
98
|
-
version: '0'
|
|
86
|
+
version: '3.0'
|
|
99
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
88
|
requirements:
|
|
101
89
|
- - ">="
|
|
102
90
|
- !ruby/object:Gem::Version
|
|
103
91
|
version: '0'
|
|
104
92
|
requirements: []
|
|
105
|
-
rubygems_version: 3.5.
|
|
93
|
+
rubygems_version: 3.5.22
|
|
106
94
|
signing_key:
|
|
107
95
|
specification_version: 4
|
|
108
96
|
summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
|