trilogy 2.5.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
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