trilogy 2.9.0 → 2.10.0

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: 998b06e77dcb78b2f30307834490a7c9c7d61422dea586f646cead7b74467058
4
- data.tar.gz: e5bf1ecf9e8b2b675db0d3c3ee7531db4ab022aa725c4ed0c16db088884c6075
3
+ metadata.gz: 6e84050730e47a4bd826b9c15b226d0f825a46df8849c3c4a89c01011e27fb6c
4
+ data.tar.gz: eddfedb0481b09220bb95f1de423b473aa78f2ad8058de692b85c52bba1c0480
5
5
  SHA512:
6
- metadata.gz: bd2acff1c38bbed9bea64f3fbb9ad474e4d42198dccbcdca0aa1b8ba3b52e35711f1c9e2e1a6859c15a71c38ed08ba06b5adcb5fbb5054b1b4264fd51ae0933f
7
- data.tar.gz: e032a04cfb901d48a4e1e711cd576c380562f2b7f871724d06568dff8bd3b599fd3ea86360b3bcbe2f8f9471f986d6b1cc8f8d8e69309877778d1ce442dd65f3
6
+ metadata.gz: a1fa8ecb46aa1b1595c6d6f1a20b5dd4267452d5c59b0571fe31c4cc854907aeb8f8ad1496099e53ba83b29c0594f88dc6f4f45586ede8b1ad53d70b0ff2a774
7
+ data.tar.gz: a18b393f8b035c8ee3315d42b23d8a46e1597f4ccbac0347acab0161a8c041572eeb8a13d4d323c97a63040f9f18baa04e0742c73e65df33d5763fdd27b6c581
data/README.md CHANGED
@@ -13,7 +13,7 @@ gem 'trilogy'
13
13
  And then execute:
14
14
 
15
15
  ```
16
- $ bundle
16
+ $ bundle install
17
17
  ```
18
18
 
19
19
  Or install it yourself as:
@@ -15,6 +15,149 @@
15
15
 
16
16
  #include "trilogy-ruby.h"
17
17
 
18
+ typedef struct _buffer_pool_entry_struct {
19
+ size_t cap;
20
+ uint8_t *buff;
21
+ } buffer_pool_entry;
22
+
23
+ typedef struct _buffer_pool_struct {
24
+ size_t capa;
25
+ size_t len;
26
+ buffer_pool_entry *entries;
27
+ } buffer_pool;
28
+
29
+ #ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
30
+ static VALUE _global_buffer_pool = Qnil;
31
+ #endif
32
+
33
+ #define BUFFER_POOL_MAX_SIZE 8
34
+
35
+ static void buffer_pool_free(void *data)
36
+ {
37
+ #ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
38
+ _global_buffer_pool = Qnil;
39
+ #endif
40
+
41
+ buffer_pool *pool = (buffer_pool *)data;
42
+ if (pool->capa) {
43
+ for (size_t index = 0; index < pool->len; index++) {
44
+ // NB: buff was allocated by trilogy/buffer.h using raw `malloc`
45
+ // hence we must use raw `free`.
46
+ free(pool->entries[index].buff);
47
+ }
48
+ xfree(pool->entries);
49
+ }
50
+ xfree(pool);
51
+ }
52
+
53
+ static size_t buffer_pool_memsize(const void *data)
54
+ {
55
+ const buffer_pool *pool = (const buffer_pool *)data;
56
+
57
+ size_t memsize = sizeof(buffer_pool) + sizeof(buffer_pool_entry) * pool->capa;
58
+
59
+ if (pool->capa) {
60
+ for (size_t index = 0; index < pool->len; index++) {
61
+ memsize += pool->entries[index].cap;
62
+ }
63
+ }
64
+
65
+ return memsize;
66
+ }
67
+
68
+ static const rb_data_type_t buffer_pool_type = {
69
+ .wrap_struct_name = "trilogy/buffer_pool",
70
+ .function = {
71
+ .dmark = NULL,
72
+ .dfree = buffer_pool_free,
73
+ .dsize = buffer_pool_memsize,
74
+ },
75
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
76
+ };
77
+
78
+ static VALUE create_rb_buffer_pool(void)
79
+ {
80
+ buffer_pool *pool;
81
+ return TypedData_Make_Struct(Qfalse, buffer_pool, &buffer_pool_type, pool);
82
+ }
83
+
84
+ #ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
85
+ #include <ruby/ractor.h>
86
+ static rb_ractor_local_key_t buffer_pool_key;
87
+
88
+ static VALUE get_rb_buffer_pool(void)
89
+ {
90
+ VALUE pool;
91
+ if (!rb_ractor_local_storage_value_lookup(buffer_pool_key, &pool)) {
92
+ pool = create_rb_buffer_pool();
93
+ rb_ractor_local_storage_value_set(buffer_pool_key, pool);
94
+ }
95
+ return pool;
96
+ }
97
+ #else
98
+ static VALUE get_rb_buffer_pool(void)
99
+ {
100
+ if (NIL_P(_global_buffer_pool)) {
101
+ _global_buffer_pool = create_rb_buffer_pool();
102
+ }
103
+ return _global_buffer_pool;
104
+ }
105
+ #endif
106
+
107
+ static inline buffer_pool *get_buffer_pool(void)
108
+ {
109
+ buffer_pool *pool;
110
+ VALUE rb_pool = get_rb_buffer_pool();
111
+ if (NIL_P(rb_pool)) {
112
+ return NULL;
113
+ }
114
+
115
+ TypedData_Get_Struct(rb_pool, buffer_pool, &buffer_pool_type, pool);
116
+ return pool;
117
+ }
118
+
119
+ static void buffer_checkout(trilogy_buffer_t *buffer, size_t initial_capacity)
120
+ {
121
+ buffer_pool * pool = get_buffer_pool();
122
+ if (pool->len) {
123
+ pool->len--;
124
+ buffer->buff = pool->entries[pool->len].buff;
125
+ buffer->cap = pool->entries[pool->len].cap;
126
+ } else {
127
+ buffer->buff = RB_ALLOC_N(uint8_t, initial_capacity);
128
+ buffer->cap = initial_capacity;
129
+ }
130
+ }
131
+
132
+ static bool buffer_checkin(trilogy_buffer_t *buffer)
133
+ {
134
+ buffer_pool * pool = get_buffer_pool();
135
+
136
+ if (pool->len >= BUFFER_POOL_MAX_SIZE) {
137
+ xfree(buffer->buff);
138
+ buffer->buff = NULL;
139
+ buffer->cap = 0;
140
+ return false;
141
+ }
142
+
143
+ if (!pool->capa) {
144
+ pool->entries = RB_ALLOC_N(buffer_pool_entry, 16);
145
+ pool->capa = 16;
146
+ } else if (pool->len >= pool->capa) {
147
+ pool->capa *= 2;
148
+ RB_REALLOC_N(pool->entries, buffer_pool_entry, pool->capa);
149
+ }
150
+
151
+ pool->entries[pool->len].buff = buffer->buff;
152
+ pool->entries[pool->len].cap = buffer->cap;
153
+ pool->len++;
154
+
155
+ buffer->buff = NULL;
156
+ buffer->cap = 0;
157
+
158
+ return true;
159
+ }
160
+
18
161
  VALUE Trilogy_CastError;
19
162
  static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
20
163
  Trilogy_ConnectionClosedError,
@@ -34,6 +177,20 @@ struct trilogy_ctx {
34
177
  VALUE encoding;
35
178
  };
36
179
 
180
+ static void rb_trilogy_acquire_buffer(struct trilogy_ctx *ctx)
181
+ {
182
+ if (!ctx->conn.packet_buffer.buff) {
183
+ buffer_checkout(&ctx->conn.packet_buffer, TRILOGY_DEFAULT_BUF_SIZE);
184
+ }
185
+ }
186
+
187
+ static void rb_trilogy_release_buffer(struct trilogy_ctx *ctx)
188
+ {
189
+ if (ctx->conn.packet_buffer.buff) {
190
+ buffer_checkin(&ctx->conn.packet_buffer);
191
+ }
192
+ }
193
+
37
194
  static void mark_trilogy(void *ptr)
38
195
  {
39
196
  struct trilogy_ctx *ctx = ptr;
@@ -43,6 +200,7 @@ static void mark_trilogy(void *ptr)
43
200
  static void free_trilogy(void *ptr)
44
201
  {
45
202
  struct trilogy_ctx *ctx = ptr;
203
+
46
204
  trilogy_free(&ctx->conn);
47
205
  xfree(ptr);
48
206
  }
@@ -116,6 +274,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
116
274
  VALUE rbmsg = rb_vsprintf(msg, args);
117
275
  va_end(args);
118
276
 
277
+ rb_trilogy_release_buffer(ctx);
278
+
119
279
  if (!trilogy_error_recoverable_p(rc)) {
120
280
  if (ctx->conn.socket != NULL) {
121
281
  // trilogy_sock_shutdown may affect errno
@@ -178,7 +338,7 @@ static VALUE allocate_trilogy(VALUE klass)
178
338
 
179
339
  ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
180
340
 
181
- if (trilogy_init(&ctx->conn) < 0) {
341
+ if (trilogy_init_no_buffer(&ctx->conn) < 0) {
182
342
  VALUE rbmsg = rb_str_new("trilogy_init", 13);
183
343
  trilogy_syserr_fail_str(errno, rbmsg);
184
344
  }
@@ -602,6 +762,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
602
762
  connopt.tls_max_version = NUM2INT(val);
603
763
  }
604
764
 
765
+ rb_trilogy_acquire_buffer(ctx);
766
+
605
767
  int rc = try_connect(ctx, &handshake, &connopt);
606
768
  if (rc != TRILOGY_OK) {
607
769
  if (connopt.path) {
@@ -617,6 +779,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
617
779
 
618
780
  authenticate(ctx, &handshake, connopt.ssl_mode);
619
781
 
782
+ rb_trilogy_release_buffer(ctx);
783
+
620
784
  return Qnil;
621
785
  }
622
786
 
@@ -626,6 +790,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
626
790
 
627
791
  StringValue(database);
628
792
 
793
+ rb_trilogy_acquire_buffer(ctx);
794
+
629
795
  int rc = trilogy_change_db_send(&ctx->conn, RSTRING_PTR(database), RSTRING_LEN(database));
630
796
 
631
797
  if (rc == TRILOGY_AGAIN) {
@@ -653,6 +819,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
653
819
  }
654
820
  }
655
821
 
822
+ rb_trilogy_release_buffer(ctx);
823
+
656
824
  return Qtrue;
657
825
  }
658
826
 
@@ -660,6 +828,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
660
828
  {
661
829
  struct trilogy_ctx *ctx = get_open_ctx(self);
662
830
 
831
+ rb_trilogy_acquire_buffer(ctx);
832
+
663
833
  int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
664
834
 
665
835
  if (rc == TRILOGY_AGAIN) {
@@ -687,6 +857,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
687
857
  }
688
858
  }
689
859
 
860
+ rb_trilogy_release_buffer(ctx);
861
+
690
862
  return Qtrue;
691
863
  }
692
864
 
@@ -892,6 +1064,10 @@ static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
892
1064
  handle_trilogy_error(ctx, args.rc, args.msg);
893
1065
  }
894
1066
 
1067
+ if (!(ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS)) {
1068
+ rb_trilogy_release_buffer(ctx);
1069
+ }
1070
+
895
1071
  return result;
896
1072
  }
897
1073
 
@@ -924,6 +1100,8 @@ static VALUE rb_trilogy_query(VALUE self, VALUE query)
924
1100
  StringValue(query);
925
1101
  query = rb_str_export_to_enc(query, rb_to_encoding(ctx->encoding));
926
1102
 
1103
+ rb_trilogy_acquire_buffer(ctx);
1104
+
927
1105
  int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
928
1106
 
929
1107
  if (rc == TRILOGY_AGAIN) {
@@ -941,6 +1119,8 @@ static VALUE rb_trilogy_ping(VALUE self)
941
1119
  {
942
1120
  struct trilogy_ctx *ctx = get_open_ctx(self);
943
1121
 
1122
+ rb_trilogy_acquire_buffer(ctx);
1123
+
944
1124
  int rc = trilogy_ping_send(&ctx->conn);
945
1125
 
946
1126
  if (rc == TRILOGY_AGAIN) {
@@ -968,6 +1148,7 @@ static VALUE rb_trilogy_ping(VALUE self)
968
1148
  }
969
1149
  }
970
1150
 
1151
+ rb_trilogy_release_buffer(ctx);
971
1152
  return Qtrue;
972
1153
  }
973
1154
 
@@ -985,13 +1166,19 @@ static VALUE rb_trilogy_escape(VALUE self, VALUE str)
985
1166
  const char *escaped_str;
986
1167
  size_t escaped_len;
987
1168
 
1169
+ rb_trilogy_acquire_buffer(ctx);
1170
+
988
1171
  int rc = trilogy_escape(&ctx->conn, RSTRING_PTR(str), RSTRING_LEN(str), &escaped_str, &escaped_len);
989
1172
 
990
1173
  if (rc < 0) {
991
1174
  handle_trilogy_error(ctx, rc, "trilogy_escape");
992
1175
  }
993
1176
 
994
- return rb_enc_str_new(escaped_str, escaped_len, str_enc);
1177
+ VALUE escaped_string = rb_enc_str_new(escaped_str, escaped_len, str_enc);
1178
+
1179
+ rb_trilogy_release_buffer(ctx);
1180
+
1181
+ return escaped_string;
995
1182
  }
996
1183
 
997
1184
  static VALUE rb_trilogy_close(VALUE self)
@@ -1002,6 +1189,8 @@ static VALUE rb_trilogy_close(VALUE self)
1002
1189
  return Qnil;
1003
1190
  }
1004
1191
 
1192
+ rb_trilogy_acquire_buffer(ctx);
1193
+
1005
1194
  int rc = trilogy_close_send(&ctx->conn);
1006
1195
 
1007
1196
  if (rc == TRILOGY_AGAIN) {
@@ -1027,6 +1216,8 @@ static VALUE rb_trilogy_close(VALUE self)
1027
1216
  // we must clear any SSL errors left in the queue from a read/write.
1028
1217
  ERR_clear_error();
1029
1218
 
1219
+ rb_trilogy_release_buffer(ctx);
1220
+
1030
1221
  trilogy_free(&ctx->conn);
1031
1222
 
1032
1223
  return Qnil;
@@ -1134,8 +1325,9 @@ static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_
1134
1325
 
1135
1326
  RUBY_FUNC_EXPORTED void Init_cext(void)
1136
1327
  {
1137
- #ifdef HAVE_RB_EXT_RACTOR_SAFE
1328
+ #ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
1138
1329
  rb_ext_ractor_safe(true);
1330
+ buffer_pool_key = rb_ractor_local_storage_value_newkey();
1139
1331
  #endif
1140
1332
 
1141
1333
  VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
@@ -10,12 +10,12 @@ File.binwrite("trilogy.c",
10
10
  }.join)
11
11
 
12
12
  $objs = %w[trilogy.o cast.o cext.o]
13
- $CFLAGS << " -I #{__dir__}/inc -std=gnu99 -fvisibility=hidden"
13
+ append_cflags(["-I #{__dir__}/inc", "-std=gnu99", "-fvisibility=hidden"])
14
14
 
15
15
  dir_config("openssl")
16
16
 
17
17
  have_library("crypto", "CRYPTO_malloc")
18
18
  have_library("ssl", "SSL_new")
19
19
  have_func("rb_interned_str", "ruby.h")
20
-
20
+ have_func("rb_ractor_local_storage_value_newkey", "ruby.h")
21
21
  create_makefile "trilogy/cext"
@@ -53,6 +53,19 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed);
53
53
  */
54
54
  int trilogy_buffer_putc(trilogy_buffer_t *buffer, uint8_t c);
55
55
 
56
+ /* trilogy_buffer_write - Appends multiple bytes to the buffer, resizing the underlying
57
+ * allocation if necessary.
58
+ *
59
+ * buffer - A pointer to a pre-initialized trilogy_buffer_t.
60
+ * ptr - The pointer to the byte array.
61
+ * len - How many bytes to append.
62
+ *
63
+ * Return values:
64
+ * TRILOGY_OK - The character was appended to the buffer
65
+ * TRILOGY_SYSERR - A system error occurred, check errno.
66
+ */
67
+ int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t len);
68
+
56
69
  /* trilogy_buffer_free - Free an trilogy_buffer_t's underlying storage. The buffer
57
70
  * must be re-initialized with trilogy_buffer_init if it is to be reused. Any
58
71
  * operations performed on an unintialized or freed buffer are undefined.
@@ -106,6 +106,15 @@ typedef struct {
106
106
  */
107
107
  int trilogy_init(trilogy_conn_t *conn);
108
108
 
109
+ /* trilogy_init_no_buffer - Same as trilogy_init but doesn't allocate the packet buffer
110
+ *
111
+ * conn - A pre-allocated trilogy_conn_t pointer.
112
+ *
113
+ * Return values:
114
+ * TRILOGY_OK - The trilogy_conn_t pointer was properly initialized
115
+ */
116
+ int trilogy_init_no_buffer(trilogy_conn_t *conn);
117
+
109
118
  /* trilogy_flush_writes - Attempt to flush the internal packet buffer to the
110
119
  * network. This must be used if a `_send` function returns TRILOGY_AGAIN, and
111
120
  * should continue to be called until it returns a value other than
@@ -25,7 +25,8 @@
25
25
  XX(TRILOGY_MAX_PACKET_EXCEEDED, -20) \
26
26
  XX(TRILOGY_UNKNOWN_TYPE, -21) \
27
27
  XX(TRILOGY_TIMEOUT, -22) \
28
- XX(TRILOGY_AUTH_PLUGIN_ERROR, -23)
28
+ XX(TRILOGY_AUTH_PLUGIN_ERROR, -23) \
29
+ XX(TRILOGY_MEM_ERROR, -24)
29
30
 
30
31
  enum {
31
32
  #define XX(name, code) name = code,
@@ -1,5 +1,6 @@
1
1
  #include <stdint.h>
2
2
  #include <stdlib.h>
3
+ #include <string.h>
3
4
 
4
5
  #include "trilogy/buffer.h"
5
6
  #include "trilogy/error.h"
@@ -23,6 +24,9 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed)
23
24
  {
24
25
  // expand buffer if necessary
25
26
  if (buffer->len + needed > buffer->cap) {
27
+ if (buffer->buff == NULL)
28
+ return TRILOGY_MEM_ERROR;
29
+
26
30
  size_t new_cap = buffer->cap;
27
31
 
28
32
  while (buffer->len + needed > new_cap) {
@@ -57,9 +61,24 @@ int trilogy_buffer_putc(trilogy_buffer_t *buffer, uint8_t c)
57
61
  return TRILOGY_OK;
58
62
  }
59
63
 
64
+ int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t len)
65
+ {
66
+ int rc = trilogy_buffer_expand(buffer, len);
67
+ if (rc) {
68
+ return rc;
69
+ }
70
+
71
+ memcpy(buffer->buff + buffer->len, ptr, len);
72
+ buffer->len += len;
73
+
74
+ return TRILOGY_OK;
75
+ }
76
+
60
77
  void trilogy_buffer_free(trilogy_buffer_t *buffer)
61
78
  {
62
- free(buffer->buff);
63
- buffer->buff = NULL;
64
- buffer->len = buffer->cap = 0;
79
+ if (buffer->buff) {
80
+ free(buffer->buff);
81
+ buffer->buff = NULL;
82
+ buffer->len = buffer->cap = 0;
83
+ }
65
84
  }
@@ -1,4 +1,5 @@
1
1
  #include <fcntl.h>
2
+ #include <string.h>
2
3
 
3
4
  #include "trilogy/client.h"
4
5
  #include "trilogy/error.h"
@@ -117,10 +118,8 @@ static int begin_write(trilogy_conn_t *conn)
117
118
  return trilogy_flush_writes(conn);
118
119
  }
119
120
 
120
- int trilogy_init(trilogy_conn_t *conn)
121
+ int trilogy_init_no_buffer(trilogy_conn_t *conn)
121
122
  {
122
- int rc;
123
-
124
123
  conn->affected_rows = 0;
125
124
  conn->last_insert_id = 0;
126
125
  conn->warning_count = 0;
@@ -142,8 +141,14 @@ int trilogy_init(trilogy_conn_t *conn)
142
141
  trilogy_packet_parser_init(&conn->packet_parser, &packet_parser_callbacks);
143
142
  conn->packet_parser.user_data = &conn->packet_buffer;
144
143
 
145
- CHECKED(trilogy_buffer_init(&conn->packet_buffer, TRILOGY_DEFAULT_BUF_SIZE));
144
+ return TRILOGY_OK;
145
+ }
146
146
 
147
+ int trilogy_init(trilogy_conn_t *conn)
148
+ {
149
+ int rc;
150
+ trilogy_init_no_buffer(conn);
151
+ CHECKED(trilogy_buffer_init(&conn->packet_buffer, TRILOGY_DEFAULT_BUF_SIZE));
147
152
  return TRILOGY_OK;
148
153
  }
149
154
 
@@ -217,7 +222,7 @@ static int read_err_packet(trilogy_conn_t *conn)
217
222
  return TRILOGY_ERR;
218
223
  }
219
224
 
220
- static int read_eof_packet(trilogy_conn_t *conn)
225
+ static int read_deprecated_eof_packet(trilogy_conn_t *conn)
221
226
  {
222
227
  trilogy_eof_packet_t eof_packet;
223
228
 
@@ -236,6 +241,21 @@ static int read_eof_packet(trilogy_conn_t *conn)
236
241
  return TRILOGY_EOF;
237
242
  }
238
243
 
244
+ static int read_eof_packet(trilogy_conn_t *conn)
245
+ {
246
+ int rc;
247
+
248
+ if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) {
249
+ return read_ok_packet(conn);
250
+ } else {
251
+ if ((rc = read_deprecated_eof_packet(conn)) != TRILOGY_EOF) {
252
+ return rc;
253
+ }
254
+
255
+ return TRILOGY_OK;
256
+ }
257
+ }
258
+
239
259
  static int read_auth_switch_packet(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
240
260
  {
241
261
  trilogy_auth_switch_request_packet_t auth_switch_packet;
@@ -646,15 +666,7 @@ static int read_eof(trilogy_conn_t *conn)
646
666
  return rc;
647
667
  }
648
668
 
649
- if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) {
650
- return read_ok_packet(conn);
651
- } else {
652
- if ((rc = read_eof_packet(conn)) != TRILOGY_EOF) {
653
- return rc;
654
- }
655
-
656
- return TRILOGY_OK;
657
- }
669
+ return read_eof_packet(conn);
658
670
  }
659
671
 
660
672
  int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
@@ -679,14 +691,12 @@ int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
679
691
  return rc;
680
692
  }
681
693
 
682
- if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF && current_packet_type(conn) == TRILOGY_PACKET_EOF) {
683
- if ((rc = read_ok_packet(conn)) != TRILOGY_OK) {
694
+ if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
695
+ if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
684
696
  return rc;
685
697
  }
686
698
 
687
699
  return TRILOGY_EOF;
688
- } else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
689
- return read_eof_packet(conn);
690
700
  } else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
691
701
  return read_err_packet(conn);
692
702
  } else {
@@ -722,7 +732,7 @@ int trilogy_drain_results(trilogy_conn_t *conn)
722
732
  }
723
733
  }
724
734
 
725
- static uint8_t escape_lookup_table[256] = {
735
+ static const uint8_t escape_lookup_table[256] = {
726
736
  ['"'] = '"', ['\0'] = '0', ['\''] = '\'', ['\\'] = '\\', ['\n'] = 'n', ['\r'] = 'r', [26] = 'Z',
727
737
  };
728
738
 
@@ -735,28 +745,40 @@ int trilogy_escape(trilogy_conn_t *conn, const char *str, size_t len, const char
735
745
 
736
746
  b->len = 0;
737
747
 
738
- if (conn->server_status & TRILOGY_SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
739
- for (size_t i = 0; i < len; i++) {
740
- const uint8_t c = (uint8_t)str[i];
748
+ // Escaped string will be at least as large as the source string,
749
+ // so might as well pre-expand the buffer.
750
+ CHECKED(trilogy_buffer_expand(b, len));
751
+
752
+ const uint8_t *cursor = (const uint8_t *)str;
753
+ const uint8_t *end = cursor + len;
741
754
 
742
- if (c == '\'') {
743
- CHECKED(trilogy_buffer_putc(b, '\''));
744
- CHECKED(trilogy_buffer_putc(b, '\''));
755
+ if (conn->server_status & TRILOGY_SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
756
+ while (cursor < end) {
757
+ uint8_t *next_escape = memchr(cursor, '\'', (size_t)(end - cursor));
758
+ if (next_escape) {
759
+ CHECKED(trilogy_buffer_write(b, cursor, (size_t)(next_escape - cursor)));
760
+ CHECKED(trilogy_buffer_write(b, (uint8_t *)"\'\'", 2));
761
+ cursor = next_escape + 1;
745
762
  } else {
746
- CHECKED(trilogy_buffer_putc(b, c));
763
+ CHECKED(trilogy_buffer_write(b, cursor, (size_t)(end - cursor)));
764
+ break;
747
765
  }
748
766
  }
749
767
  } else {
750
- for (size_t i = 0; i < len; i++) {
751
- const uint8_t c = (uint8_t)str[i];
752
-
753
- uint8_t escaped = escape_lookup_table[(uint8_t)c];
768
+ while (cursor < end) {
769
+ uint8_t escaped = 0;
770
+ const uint8_t *start = cursor;
771
+ while (cursor < end && !(escaped = escape_lookup_table[*cursor])) {
772
+ cursor++;
773
+ }
754
774
 
775
+ CHECKED(trilogy_buffer_write(b, start, (size_t)(cursor - start)));
755
776
  if (escaped) {
756
777
  CHECKED(trilogy_buffer_putc(b, '\\'));
757
778
  CHECKED(trilogy_buffer_putc(b, escaped));
779
+ cursor++;
758
780
  } else {
759
- CHECKED(trilogy_buffer_putc(b, c));
781
+ break;
760
782
  }
761
783
  }
762
784
  }
@@ -940,20 +962,18 @@ int trilogy_stmt_bind_data_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint
940
962
  int trilogy_stmt_read_row(trilogy_conn_t *conn, trilogy_stmt_t *stmt, trilogy_column_packet_t *columns,
941
963
  trilogy_binary_value_t *values_out)
942
964
  {
943
- int err = read_packet(conn);
965
+ int rc = read_packet(conn);
944
966
 
945
- if (err < 0) {
946
- return err;
967
+ if (rc < 0) {
968
+ return rc;
947
969
  }
948
970
 
949
- if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF && current_packet_type(conn) == TRILOGY_PACKET_EOF) {
950
- if ((err = read_ok_packet(conn)) != TRILOGY_OK) {
951
- return err;
971
+ if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
972
+ if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
973
+ return rc;
952
974
  }
953
975
 
954
976
  return TRILOGY_EOF;
955
- } else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
956
- return read_eof_packet(conn);
957
977
  } else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
958
978
  return read_err_packet(conn);
959
979
  } else {
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Trilogy
2
4
  module Encoding
3
5
  RUBY_ENCODINGS = {
@@ -6,6 +6,8 @@ class Trilogy
6
6
  rows.count
7
7
  end
8
8
 
9
+ alias_method :size, :count
10
+
9
11
  def each_hash
10
12
  return enum_for(:each_hash) unless block_given?
11
13
 
@@ -1,3 +1,3 @@
1
1
  class Trilogy
2
- VERSION = "2.9.0"
2
+ VERSION = "2.10.0"
3
3
  end
data/trilogy.gemspec CHANGED
@@ -22,6 +22,10 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.require_paths = ["lib"]
24
24
 
25
+ s.required_ruby_version = ">= 3.0"
26
+
27
+ s.add_dependency "bigdecimal"
28
+
25
29
  s.add_development_dependency "rake-compiler", "~> 1.0"
26
30
  s.add_development_dependency "minitest", "~> 5.5"
27
31
  end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trilogy
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Engineering
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-11 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bigdecimal
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: rake-compiler
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +51,6 @@ dependencies:
38
51
  - - "~>"
39
52
  - !ruby/object:Gem::Version
40
53
  version: '5.5'
41
- description:
42
54
  email: opensource+trilogy@github.com
43
55
  executables: []
44
56
  extensions:
@@ -87,7 +99,6 @@ homepage: https://github.com/trilogy-libraries/trilogy
87
99
  licenses:
88
100
  - MIT
89
101
  metadata: {}
90
- post_install_message:
91
102
  rdoc_options: []
92
103
  require_paths:
93
104
  - lib
@@ -95,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
106
  requirements:
96
107
  - - ">="
97
108
  - !ruby/object:Gem::Version
98
- version: '0'
109
+ version: '3.0'
99
110
  required_rubygems_version: !ruby/object:Gem::Requirement
100
111
  requirements:
101
112
  - - ">="
102
113
  - !ruby/object:Gem::Version
103
114
  version: '0'
104
115
  requirements: []
105
- rubygems_version: 3.5.11
106
- signing_key:
116
+ rubygems_version: 3.6.9
107
117
  specification_version: 4
108
118
  summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
109
119
  test_files: []