trilogy 2.8.1 → 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: 314d8fc7b424ff0f7cb1a7b432fdf64d51d4a1c3bb0eb20dcf8ea67fb2445bd5
4
- data.tar.gz: 66b842ec3cf4017226fcc43e4b0bb931701b1299ea1cb025d8764ad7705dd96e
3
+ metadata.gz: 6e84050730e47a4bd826b9c15b226d0f825a46df8849c3c4a89c01011e27fb6c
4
+ data.tar.gz: eddfedb0481b09220bb95f1de423b473aa78f2ad8058de692b85c52bba1c0480
5
5
  SHA512:
6
- metadata.gz: 5cf6f57d91e14972b5fc61576c1b5be98644c03a4a6185dd6fe80aa2c4c22f629c792abb1572e37dbe6b53aec2208cbb344a5575d8877094d3072a16d011bcbe
7
- data.tar.gz: e967b694945e7c2506240d20e2cb45fa67e0aca7f80ca4961cca7556d7fec8e27f1ab790a8459fc57de425a9144cdc808cc19547a607f35713640e59b752552f
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
@@ -133,7 +293,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
133
293
  rb_raise(Trilogy_TimeoutError, "%" PRIsVALUE, rbmsg);
134
294
 
135
295
  case TRILOGY_ERR: {
136
- VALUE message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
296
+ VALUE conn_message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
297
+ VALUE message = rb_sprintf("%" PRIsVALUE " (%" PRIsVALUE ")", conn_message, rbmsg);
137
298
  VALUE exc = rb_funcall(Trilogy_ProtocolError, id_from_code, 2, message, INT2NUM(ctx->conn.error_code));
138
299
  rb_exc_raise(exc);
139
300
  }
@@ -177,7 +338,7 @@ static VALUE allocate_trilogy(VALUE klass)
177
338
 
178
339
  ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
179
340
 
180
- if (trilogy_init(&ctx->conn) < 0) {
341
+ if (trilogy_init_no_buffer(&ctx->conn) < 0) {
181
342
  VALUE rbmsg = rb_str_new("trilogy_init", 13);
182
343
  trilogy_syserr_fail_str(errno, rbmsg);
183
344
  }
@@ -601,6 +762,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
601
762
  connopt.tls_max_version = NUM2INT(val);
602
763
  }
603
764
 
765
+ rb_trilogy_acquire_buffer(ctx);
766
+
604
767
  int rc = try_connect(ctx, &handshake, &connopt);
605
768
  if (rc != TRILOGY_OK) {
606
769
  if (connopt.path) {
@@ -616,6 +779,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
616
779
 
617
780
  authenticate(ctx, &handshake, connopt.ssl_mode);
618
781
 
782
+ rb_trilogy_release_buffer(ctx);
783
+
619
784
  return Qnil;
620
785
  }
621
786
 
@@ -625,6 +790,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
625
790
 
626
791
  StringValue(database);
627
792
 
793
+ rb_trilogy_acquire_buffer(ctx);
794
+
628
795
  int rc = trilogy_change_db_send(&ctx->conn, RSTRING_PTR(database), RSTRING_LEN(database));
629
796
 
630
797
  if (rc == TRILOGY_AGAIN) {
@@ -652,6 +819,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
652
819
  }
653
820
  }
654
821
 
822
+ rb_trilogy_release_buffer(ctx);
823
+
655
824
  return Qtrue;
656
825
  }
657
826
 
@@ -659,6 +828,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
659
828
  {
660
829
  struct trilogy_ctx *ctx = get_open_ctx(self);
661
830
 
831
+ rb_trilogy_acquire_buffer(ctx);
832
+
662
833
  int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
663
834
 
664
835
  if (rc == TRILOGY_AGAIN) {
@@ -686,6 +857,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
686
857
  }
687
858
  }
688
859
 
860
+ rb_trilogy_release_buffer(ctx);
861
+
689
862
  return Qtrue;
690
863
  }
691
864
 
@@ -891,6 +1064,10 @@ static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
891
1064
  handle_trilogy_error(ctx, args.rc, args.msg);
892
1065
  }
893
1066
 
1067
+ if (!(ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS)) {
1068
+ rb_trilogy_release_buffer(ctx);
1069
+ }
1070
+
894
1071
  return result;
895
1072
  }
896
1073
 
@@ -923,6 +1100,8 @@ static VALUE rb_trilogy_query(VALUE self, VALUE query)
923
1100
  StringValue(query);
924
1101
  query = rb_str_export_to_enc(query, rb_to_encoding(ctx->encoding));
925
1102
 
1103
+ rb_trilogy_acquire_buffer(ctx);
1104
+
926
1105
  int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
927
1106
 
928
1107
  if (rc == TRILOGY_AGAIN) {
@@ -940,6 +1119,8 @@ static VALUE rb_trilogy_ping(VALUE self)
940
1119
  {
941
1120
  struct trilogy_ctx *ctx = get_open_ctx(self);
942
1121
 
1122
+ rb_trilogy_acquire_buffer(ctx);
1123
+
943
1124
  int rc = trilogy_ping_send(&ctx->conn);
944
1125
 
945
1126
  if (rc == TRILOGY_AGAIN) {
@@ -967,6 +1148,7 @@ static VALUE rb_trilogy_ping(VALUE self)
967
1148
  }
968
1149
  }
969
1150
 
1151
+ rb_trilogy_release_buffer(ctx);
970
1152
  return Qtrue;
971
1153
  }
972
1154
 
@@ -984,13 +1166,19 @@ static VALUE rb_trilogy_escape(VALUE self, VALUE str)
984
1166
  const char *escaped_str;
985
1167
  size_t escaped_len;
986
1168
 
1169
+ rb_trilogy_acquire_buffer(ctx);
1170
+
987
1171
  int rc = trilogy_escape(&ctx->conn, RSTRING_PTR(str), RSTRING_LEN(str), &escaped_str, &escaped_len);
988
1172
 
989
1173
  if (rc < 0) {
990
1174
  handle_trilogy_error(ctx, rc, "trilogy_escape");
991
1175
  }
992
1176
 
993
- 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;
994
1182
  }
995
1183
 
996
1184
  static VALUE rb_trilogy_close(VALUE self)
@@ -1001,6 +1189,8 @@ static VALUE rb_trilogy_close(VALUE self)
1001
1189
  return Qnil;
1002
1190
  }
1003
1191
 
1192
+ rb_trilogy_acquire_buffer(ctx);
1193
+
1004
1194
  int rc = trilogy_close_send(&ctx->conn);
1005
1195
 
1006
1196
  if (rc == TRILOGY_AGAIN) {
@@ -1026,6 +1216,8 @@ static VALUE rb_trilogy_close(VALUE self)
1026
1216
  // we must clear any SSL errors left in the queue from a read/write.
1027
1217
  ERR_clear_error();
1028
1218
 
1219
+ rb_trilogy_release_buffer(ctx);
1220
+
1029
1221
  trilogy_free(&ctx->conn);
1030
1222
 
1031
1223
  return Qnil;
@@ -1133,6 +1325,11 @@ static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_
1133
1325
 
1134
1326
  RUBY_FUNC_EXPORTED void Init_cext(void)
1135
1327
  {
1328
+ #ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
1329
+ rb_ext_ractor_safe(true);
1330
+ buffer_pool_key = rb_ractor_local_storage_value_newkey();
1331
+ #endif
1332
+
1136
1333
  VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
1137
1334
  rb_define_alloc_func(Trilogy, allocate_trilogy);
1138
1335
 
@@ -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,
@@ -289,6 +289,7 @@ typedef enum {
289
289
  XX(TRILOGY_TYPE_YEAR, 0x0d) \
290
290
  XX(TRILOGY_TYPE_VARCHAR, 0x0f) \
291
291
  XX(TRILOGY_TYPE_BIT, 0x10) \
292
+ XX(TRILOGY_TYPE_VECTOR, 0xf2) \
292
293
  XX(TRILOGY_TYPE_JSON, 0xf5) \
293
294
  XX(TRILOGY_TYPE_NEWDECIMAL, 0xf6) \
294
295
  XX(TRILOGY_TYPE_ENUM, 0xf7) \
@@ -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
  }
@@ -182,7 +182,7 @@ int trilogy_builder_write_buffer(trilogy_builder_t *builder, const void *data, s
182
182
 
183
183
  size_t fragment_remaining = TRILOGY_MAX_PACKET_LEN - builder->fragment_length;
184
184
 
185
- if (builder->packet_length >= builder->packet_max_length - len) {
185
+ if (builder->packet_length + len >= builder->packet_max_length) {
186
186
  return TRILOGY_MAX_PACKET_EXCEEDED;
187
187
  }
188
188
 
@@ -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 {
@@ -926,6 +926,8 @@ int trilogy_build_stmt_execute_packet(trilogy_builder_t *builder, uint32_t stmt_
926
926
  case TRILOGY_TYPE_VAR_STRING:
927
927
  case TRILOGY_TYPE_STRING:
928
928
  case TRILOGY_TYPE_GEOMETRY:
929
+ case TRILOGY_TYPE_JSON:
930
+ case TRILOGY_TYPE_VECTOR:
929
931
  CHECKED(trilogy_builder_write_lenenc_buffer(builder, val.as.str.data, val.as.str.len));
930
932
 
931
933
  break;
@@ -1059,6 +1061,7 @@ int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_colum
1059
1061
  case TRILOGY_TYPE_DECIMAL:
1060
1062
  case TRILOGY_TYPE_NEWDECIMAL:
1061
1063
  case TRILOGY_TYPE_JSON:
1064
+ case TRILOGY_TYPE_VECTOR:
1062
1065
  CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_values[i].as.str.len,
1063
1066
  (const void **)&out_values[i].as.str.data));
1064
1067
 
@@ -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.8.1"
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.8.1
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-05-13 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.3
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: []