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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0730bbbdae7e8eab195c4ad745e223bcd55fe6299f98cb324c88beea15ebdc5e
4
- data.tar.gz: 7779f268cbfae85bf5575f680ebff9fee6d22b78bb5d3d315ba664969ab9618a
3
+ metadata.gz: d015527cefe1e66b73b4db1d31b98e3db6ab616edb1fb2da947054a55818f338
4
+ data.tar.gz: 315bdd0e7dabf0f37ed69f5cd0884a702a7502443b1e26e5b01bec90b122e11d
5
5
  SHA512:
6
- metadata.gz: 42c81e496210cfc0538ef1dd9f4f7c34e2ce94de45e5bcfe4c5815839c463a6b3ae78af529b88c63a670b3cd2035a6b931ef76fdfe1ec508f6b7851858b664d2
7
- data.tar.gz: ad05962a8a47cea68ab66188badf405fe96342587bd86d91faf43dd028dc641949ea58d9a6d25547e820c4700c6cd9548d70a2494f0a215b08bb8a61c9c920c8
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/github/trilogy/fork )
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`)
@@ -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
- if (ctx->conn.socket != NULL) {
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(Trilogy_QueryError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", msg);
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 rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VALUE opts)
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, "_initialize", rb_trilogy_initialize, 3);
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");
@@ -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["#{__dir__}/src/**/*.c"].map { |src| File.binread(src) }.join)
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) { free(buffer->buff); }
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
- freeaddrinfo(sock->addr);
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 fail;
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 TRILOGY_SYSERR;
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::Error })
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
@@ -1,3 +1,3 @@
1
1
  class Trilogy
2
- VERSION = "2.5.0"
2
+ VERSION = "2.6.1"
3
3
  end
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.key?(:port)
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
- _initialize(encoding, charset, options)
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.5.0
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: 2023-08-16 00:00:00.000000000 Z
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.7
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