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
data/ext/trilogy-ruby/cext.c
CHANGED
|
@@ -11,10 +11,149 @@
|
|
|
11
11
|
#include <unistd.h>
|
|
12
12
|
#include <fcntl.h>
|
|
13
13
|
|
|
14
|
-
#include <trilogy.h>
|
|
15
|
-
|
|
16
14
|
#include "trilogy-ruby.h"
|
|
17
15
|
|
|
16
|
+
typedef struct _buffer_pool_entry_struct {
|
|
17
|
+
size_t cap;
|
|
18
|
+
uint8_t *buff;
|
|
19
|
+
} buffer_pool_entry;
|
|
20
|
+
|
|
21
|
+
typedef struct _buffer_pool_struct {
|
|
22
|
+
size_t capa;
|
|
23
|
+
size_t len;
|
|
24
|
+
buffer_pool_entry *entries;
|
|
25
|
+
} buffer_pool;
|
|
26
|
+
|
|
27
|
+
#ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
28
|
+
static VALUE _global_buffer_pool = Qnil;
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
#define BUFFER_POOL_MAX_SIZE 8
|
|
32
|
+
|
|
33
|
+
static void buffer_pool_free(void *data)
|
|
34
|
+
{
|
|
35
|
+
#ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
36
|
+
_global_buffer_pool = Qnil;
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
buffer_pool *pool = (buffer_pool *)data;
|
|
40
|
+
if (pool->capa) {
|
|
41
|
+
for (size_t index = 0; index < pool->len; index++) {
|
|
42
|
+
xfree(pool->entries[index].buff);
|
|
43
|
+
}
|
|
44
|
+
xfree(pool->entries);
|
|
45
|
+
}
|
|
46
|
+
xfree(pool);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static size_t buffer_pool_memsize(const void *data)
|
|
50
|
+
{
|
|
51
|
+
const buffer_pool *pool = (const buffer_pool *)data;
|
|
52
|
+
|
|
53
|
+
size_t memsize = sizeof(buffer_pool) + sizeof(buffer_pool_entry) * pool->capa;
|
|
54
|
+
|
|
55
|
+
if (pool->capa) {
|
|
56
|
+
for (size_t index = 0; index < pool->len; index++) {
|
|
57
|
+
memsize += pool->entries[index].cap;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return memsize;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static const rb_data_type_t buffer_pool_type = {
|
|
65
|
+
.wrap_struct_name = "trilogy/buffer_pool",
|
|
66
|
+
.function = {
|
|
67
|
+
.dmark = NULL,
|
|
68
|
+
.dfree = buffer_pool_free,
|
|
69
|
+
.dsize = buffer_pool_memsize,
|
|
70
|
+
},
|
|
71
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
static VALUE create_rb_buffer_pool(void)
|
|
75
|
+
{
|
|
76
|
+
buffer_pool *pool;
|
|
77
|
+
return TypedData_Make_Struct(Qfalse, buffer_pool, &buffer_pool_type, pool);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
81
|
+
#include <ruby/ractor.h>
|
|
82
|
+
static rb_ractor_local_key_t buffer_pool_key;
|
|
83
|
+
|
|
84
|
+
static VALUE get_rb_buffer_pool(void)
|
|
85
|
+
{
|
|
86
|
+
VALUE pool;
|
|
87
|
+
if (!rb_ractor_local_storage_value_lookup(buffer_pool_key, &pool)) {
|
|
88
|
+
pool = create_rb_buffer_pool();
|
|
89
|
+
rb_ractor_local_storage_value_set(buffer_pool_key, pool);
|
|
90
|
+
}
|
|
91
|
+
return pool;
|
|
92
|
+
}
|
|
93
|
+
#else
|
|
94
|
+
static VALUE get_rb_buffer_pool(void)
|
|
95
|
+
{
|
|
96
|
+
if (NIL_P(_global_buffer_pool)) {
|
|
97
|
+
_global_buffer_pool = create_rb_buffer_pool();
|
|
98
|
+
}
|
|
99
|
+
return _global_buffer_pool;
|
|
100
|
+
}
|
|
101
|
+
#endif
|
|
102
|
+
|
|
103
|
+
static inline buffer_pool *get_buffer_pool(void)
|
|
104
|
+
{
|
|
105
|
+
buffer_pool *pool;
|
|
106
|
+
VALUE rb_pool = get_rb_buffer_pool();
|
|
107
|
+
if (NIL_P(rb_pool)) {
|
|
108
|
+
return NULL;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
TypedData_Get_Struct(rb_pool, buffer_pool, &buffer_pool_type, pool);
|
|
112
|
+
return pool;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static void buffer_checkout(trilogy_buffer_t *buffer, size_t initial_capacity)
|
|
116
|
+
{
|
|
117
|
+
buffer_pool * pool = get_buffer_pool();
|
|
118
|
+
if (pool->len) {
|
|
119
|
+
pool->len--;
|
|
120
|
+
buffer->buff = pool->entries[pool->len].buff;
|
|
121
|
+
buffer->cap = pool->entries[pool->len].cap;
|
|
122
|
+
} else {
|
|
123
|
+
buffer->buff = xmalloc(initial_capacity);
|
|
124
|
+
buffer->cap = initial_capacity;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static bool buffer_checkin(trilogy_buffer_t *buffer)
|
|
129
|
+
{
|
|
130
|
+
buffer_pool * pool = get_buffer_pool();
|
|
131
|
+
|
|
132
|
+
if (pool->len >= BUFFER_POOL_MAX_SIZE) {
|
|
133
|
+
xfree(buffer->buff);
|
|
134
|
+
buffer->buff = NULL;
|
|
135
|
+
buffer->cap = 0;
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!pool->capa) {
|
|
140
|
+
pool->entries = RB_ALLOC_N(buffer_pool_entry, 16);
|
|
141
|
+
pool->capa = 16;
|
|
142
|
+
} else if (pool->len >= pool->capa) {
|
|
143
|
+
pool->capa *= 2;
|
|
144
|
+
RB_REALLOC_N(pool->entries, buffer_pool_entry, pool->capa);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
pool->entries[pool->len].buff = buffer->buff;
|
|
148
|
+
pool->entries[pool->len].cap = buffer->cap;
|
|
149
|
+
pool->len++;
|
|
150
|
+
|
|
151
|
+
buffer->buff = NULL;
|
|
152
|
+
buffer->cap = 0;
|
|
153
|
+
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
18
157
|
VALUE Trilogy_CastError;
|
|
19
158
|
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
|
20
159
|
Trilogy_ConnectionClosedError,
|
|
@@ -22,27 +161,36 @@ static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLErro
|
|
|
22
161
|
|
|
23
162
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
|
24
163
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
|
25
|
-
|
|
26
|
-
|
|
164
|
+
id_password, id_database, id_enable_cleartext_plugin,
|
|
165
|
+
id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
|
27
166
|
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
|
|
28
|
-
id_from_code, id_from_errno,
|
|
167
|
+
id_from_code, id_from_errno, id_max_allowed_packet;
|
|
29
168
|
|
|
30
169
|
struct trilogy_ctx {
|
|
31
170
|
trilogy_conn_t conn;
|
|
32
|
-
|
|
171
|
+
rb_encoding *encoding;
|
|
33
172
|
unsigned int query_flags;
|
|
34
|
-
|
|
173
|
+
char server_version[TRILOGY_SERVER_VERSION_SIZE + 1];
|
|
35
174
|
};
|
|
36
175
|
|
|
37
|
-
static void
|
|
176
|
+
static void rb_trilogy_acquire_buffer(struct trilogy_ctx *ctx)
|
|
38
177
|
{
|
|
39
|
-
|
|
40
|
-
|
|
178
|
+
if (!ctx->conn.packet_buffer.buff) {
|
|
179
|
+
buffer_checkout(&ctx->conn.packet_buffer, TRILOGY_DEFAULT_BUF_SIZE);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static void rb_trilogy_release_buffer(struct trilogy_ctx *ctx)
|
|
184
|
+
{
|
|
185
|
+
if (ctx->conn.packet_buffer.buff) {
|
|
186
|
+
buffer_checkin(&ctx->conn.packet_buffer);
|
|
187
|
+
}
|
|
41
188
|
}
|
|
42
189
|
|
|
43
190
|
static void free_trilogy(void *ptr)
|
|
44
191
|
{
|
|
45
192
|
struct trilogy_ctx *ctx = ptr;
|
|
193
|
+
|
|
46
194
|
trilogy_free(&ctx->conn);
|
|
47
195
|
xfree(ptr);
|
|
48
196
|
}
|
|
@@ -60,7 +208,7 @@ static size_t trilogy_memsize(const void *ptr) {
|
|
|
60
208
|
static const rb_data_type_t trilogy_data_type = {
|
|
61
209
|
.wrap_struct_name = "trilogy",
|
|
62
210
|
.function = {
|
|
63
|
-
.dmark =
|
|
211
|
+
.dmark = NULL,
|
|
64
212
|
.dfree = free_trilogy,
|
|
65
213
|
.dsize = trilogy_memsize,
|
|
66
214
|
},
|
|
@@ -116,6 +264,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
|
116
264
|
VALUE rbmsg = rb_vsprintf(msg, args);
|
|
117
265
|
va_end(args);
|
|
118
266
|
|
|
267
|
+
rb_trilogy_release_buffer(ctx);
|
|
268
|
+
|
|
119
269
|
if (!trilogy_error_recoverable_p(rc)) {
|
|
120
270
|
if (ctx->conn.socket != NULL) {
|
|
121
271
|
// trilogy_sock_shutdown may affect errno
|
|
@@ -178,7 +328,7 @@ static VALUE allocate_trilogy(VALUE klass)
|
|
|
178
328
|
|
|
179
329
|
ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
|
|
180
330
|
|
|
181
|
-
if (
|
|
331
|
+
if (trilogy_init_no_buffer(&ctx->conn) < 0) {
|
|
182
332
|
VALUE rbmsg = rb_str_new("trilogy_init", 13);
|
|
183
333
|
trilogy_syserr_fail_str(errno, rbmsg);
|
|
184
334
|
}
|
|
@@ -295,42 +445,29 @@ static int _cb_ruby_wait(trilogy_sock_t *sock, trilogy_wait_t wait)
|
|
|
295
445
|
return TRILOGY_OK;
|
|
296
446
|
}
|
|
297
447
|
|
|
298
|
-
struct
|
|
299
|
-
int rc;
|
|
300
|
-
trilogy_sock_t *sock;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
static void *no_gvl_resolve(void *data)
|
|
448
|
+
static int try_connect(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake, const trilogy_sockopt_t *opts, int fd)
|
|
304
449
|
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
450
|
+
if (fd < 0) {
|
|
451
|
+
return TRILOGY_ERR;
|
|
452
|
+
}
|
|
309
453
|
|
|
310
|
-
static int try_connect(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake, const trilogy_sockopt_t *opts)
|
|
311
|
-
{
|
|
312
454
|
trilogy_sock_t *sock = trilogy_sock_new(opts);
|
|
313
455
|
if (sock == NULL) {
|
|
314
456
|
return TRILOGY_ERR;
|
|
315
457
|
}
|
|
316
458
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// Do the DNS resolving with the GVL unlocked. At this point all
|
|
320
|
-
// configuration data is copied and available to the trilogy socket.
|
|
321
|
-
rb_thread_call_without_gvl(no_gvl_resolve, (void *)&args, RUBY_UBF_IO, NULL);
|
|
322
|
-
|
|
323
|
-
int rc = args.rc;
|
|
324
|
-
|
|
325
|
-
if (rc != TRILOGY_OK) {
|
|
326
|
-
trilogy_sock_close(sock);
|
|
327
|
-
return rc;
|
|
328
|
-
}
|
|
459
|
+
int rc;
|
|
329
460
|
|
|
330
461
|
/* replace the default wait callback with our GVL-aware callback so we can
|
|
331
462
|
escape the GVL on each wait operation without going through call_without_gvl */
|
|
332
463
|
sock->wait_cb = _cb_ruby_wait;
|
|
333
|
-
|
|
464
|
+
|
|
465
|
+
int newfd = dup(fd);
|
|
466
|
+
if (newfd < 0) {
|
|
467
|
+
return TRILOGY_ERR;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
rc = trilogy_connect_set_fd(&ctx->conn, sock, newfd);
|
|
334
471
|
if (rc < 0) {
|
|
335
472
|
trilogy_sock_close(sock);
|
|
336
473
|
return rc;
|
|
@@ -374,7 +511,12 @@ static void auth_switch(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake)
|
|
|
374
511
|
}
|
|
375
512
|
|
|
376
513
|
if (rc != TRILOGY_AGAIN) {
|
|
377
|
-
|
|
514
|
+
if (rc == TRILOGY_UNSUPPORTED) {
|
|
515
|
+
handle_trilogy_error(ctx, rc, "trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket");
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
|
|
519
|
+
}
|
|
378
520
|
}
|
|
379
521
|
|
|
380
522
|
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
@@ -428,12 +570,7 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
|
428
570
|
}
|
|
429
571
|
|
|
430
572
|
if (rc != TRILOGY_AGAIN) {
|
|
431
|
-
|
|
432
|
-
handle_trilogy_error(ctx, rc, "trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket");
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
|
|
436
|
-
}
|
|
573
|
+
handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
|
|
437
574
|
}
|
|
438
575
|
|
|
439
576
|
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
@@ -447,14 +584,24 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
|
447
584
|
}
|
|
448
585
|
}
|
|
449
586
|
|
|
450
|
-
|
|
587
|
+
#ifndef HAVE_RB_IO_DESCRIPTOR /* Ruby < 3.1 */
|
|
588
|
+
static int rb_io_descriptor(VALUE io)
|
|
589
|
+
{
|
|
590
|
+
rb_io_t *fptr;
|
|
591
|
+
GetOpenFile(io, fptr);
|
|
592
|
+
rb_io_check_closed(fptr);
|
|
593
|
+
return fptr->fd;
|
|
594
|
+
}
|
|
595
|
+
#endif
|
|
596
|
+
|
|
597
|
+
static VALUE rb_trilogy_connect(VALUE self, VALUE raw_socket, VALUE encoding, VALUE charset, VALUE opts)
|
|
451
598
|
{
|
|
452
599
|
struct trilogy_ctx *ctx = get_ctx(self);
|
|
453
600
|
trilogy_sockopt_t connopt = {0};
|
|
454
601
|
trilogy_handshake_t handshake;
|
|
455
602
|
VALUE val;
|
|
456
603
|
|
|
457
|
-
|
|
604
|
+
ctx->encoding = rb_to_encoding(encoding);
|
|
458
605
|
connopt.encoding = NUM2INT(charset);
|
|
459
606
|
|
|
460
607
|
Check_Type(opts, T_HASH);
|
|
@@ -602,7 +749,17 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
|
|
|
602
749
|
connopt.tls_max_version = NUM2INT(val);
|
|
603
750
|
}
|
|
604
751
|
|
|
605
|
-
|
|
752
|
+
VALUE io = rb_io_get_io(raw_socket);
|
|
753
|
+
|
|
754
|
+
rb_io_t *fptr;
|
|
755
|
+
GetOpenFile(io, fptr);
|
|
756
|
+
rb_io_check_readable(fptr);
|
|
757
|
+
rb_io_check_writable(fptr);
|
|
758
|
+
|
|
759
|
+
int fd = rb_io_descriptor(io);
|
|
760
|
+
|
|
761
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
762
|
+
int rc = try_connect(ctx, &handshake, &connopt, fd);
|
|
606
763
|
if (rc != TRILOGY_OK) {
|
|
607
764
|
if (connopt.path) {
|
|
608
765
|
handle_trilogy_error(ctx, rc, "trilogy_connect - unable to connect to %s", connopt.path);
|
|
@@ -617,6 +774,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
|
|
|
617
774
|
|
|
618
775
|
authenticate(ctx, &handshake, connopt.ssl_mode);
|
|
619
776
|
|
|
777
|
+
rb_trilogy_release_buffer(ctx);
|
|
778
|
+
|
|
620
779
|
return Qnil;
|
|
621
780
|
}
|
|
622
781
|
|
|
@@ -626,6 +785,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
|
626
785
|
|
|
627
786
|
StringValue(database);
|
|
628
787
|
|
|
788
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
789
|
+
|
|
629
790
|
int rc = trilogy_change_db_send(&ctx->conn, RSTRING_PTR(database), RSTRING_LEN(database));
|
|
630
791
|
|
|
631
792
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -653,6 +814,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
|
653
814
|
}
|
|
654
815
|
}
|
|
655
816
|
|
|
817
|
+
rb_trilogy_release_buffer(ctx);
|
|
818
|
+
|
|
656
819
|
return Qtrue;
|
|
657
820
|
}
|
|
658
821
|
|
|
@@ -660,6 +823,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
|
|
660
823
|
{
|
|
661
824
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
662
825
|
|
|
826
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
827
|
+
|
|
663
828
|
int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
|
|
664
829
|
|
|
665
830
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -687,6 +852,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
|
|
687
852
|
}
|
|
688
853
|
}
|
|
689
854
|
|
|
855
|
+
rb_trilogy_release_buffer(ctx);
|
|
856
|
+
|
|
690
857
|
return Qtrue;
|
|
691
858
|
}
|
|
692
859
|
|
|
@@ -767,102 +934,107 @@ static VALUE read_query_response(VALUE vargs)
|
|
|
767
934
|
double query_time = finish.tv_sec - start.tv_sec;
|
|
768
935
|
query_time += (double)(finish.tv_nsec - start.tv_nsec) / 1000000000.0;
|
|
769
936
|
|
|
770
|
-
VALUE
|
|
771
|
-
|
|
772
|
-
VALUE column_names = rb_ary_new2(column_count);
|
|
773
|
-
rb_ivar_set(result, id_ivar_fields, column_names);
|
|
937
|
+
VALUE column_names = 0;
|
|
774
938
|
|
|
775
939
|
VALUE rows = rb_ary_new();
|
|
776
|
-
rb_ivar_set(result, id_ivar_rows, rows);
|
|
777
|
-
|
|
778
|
-
rb_ivar_set(result, id_ivar_query_time, DBL2NUM(query_time));
|
|
779
940
|
|
|
941
|
+
VALUE last_insert_id = Qnil, affected_rows = Qnil;
|
|
780
942
|
if (rc == TRILOGY_OK) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
rb_ivar_set(result, id_ivar_affected_rows, ULL2NUM(ctx->conn.affected_rows));
|
|
784
|
-
|
|
785
|
-
return result;
|
|
786
|
-
} else {
|
|
787
|
-
rb_ivar_set(result, id_ivar_last_insert_id, Qnil);
|
|
788
|
-
rb_ivar_set(result, id_ivar_affected_rows, Qnil);
|
|
943
|
+
last_insert_id = ULL2NUM(ctx->conn.last_insert_id);
|
|
944
|
+
affected_rows = ULL2NUM(ctx->conn.affected_rows);
|
|
789
945
|
}
|
|
946
|
+
else {
|
|
947
|
+
VALUE rb_column_info;
|
|
948
|
+
struct column_info *column_info = ALLOCV_N(struct column_info, rb_column_info, column_count);
|
|
949
|
+
VALUE rb_ruby_values;
|
|
950
|
+
VALUE *row_ruby_values = ALLOCV_N(VALUE, rb_ruby_values, column_count);
|
|
790
951
|
|
|
791
|
-
|
|
792
|
-
|
|
952
|
+
for (uint64_t i = 0; i < column_count; i++) {
|
|
953
|
+
trilogy_column_t column;
|
|
793
954
|
|
|
794
|
-
|
|
795
|
-
|
|
955
|
+
while (1) {
|
|
956
|
+
rc = trilogy_read_column(&ctx->conn, &column);
|
|
796
957
|
|
|
797
|
-
|
|
798
|
-
|
|
958
|
+
if (rc == TRILOGY_OK) {
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
799
961
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
962
|
+
if (rc != TRILOGY_AGAIN) {
|
|
963
|
+
return read_query_error(args, rc, "trilogy_read_column");
|
|
964
|
+
}
|
|
803
965
|
|
|
804
|
-
|
|
805
|
-
|
|
966
|
+
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
967
|
+
if (rc != TRILOGY_OK) {
|
|
968
|
+
return read_query_error(args, rc, "trilogy_read_column");
|
|
969
|
+
}
|
|
806
970
|
}
|
|
807
971
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
972
|
+
#ifdef HAVE_RB_ENC_INTERNED_STR
|
|
973
|
+
row_ruby_values[i] = rb_enc_interned_str(column.name, column.name_len, ctx->encoding);
|
|
974
|
+
#else
|
|
975
|
+
row_ruby_values[i] = rb_enc_str_new(column.name, column.name_len, ctx->encoding);
|
|
976
|
+
OBJ_FREEZE(row_ruby_values[i]);
|
|
977
|
+
#endif
|
|
978
|
+
|
|
979
|
+
column_info[i].type = column.type;
|
|
980
|
+
column_info[i].flags = column.flags;
|
|
981
|
+
column_info[i].len = column.len;
|
|
982
|
+
column_info[i].charset = column.charset;
|
|
983
|
+
column_info[i].decimals = column.decimals;
|
|
812
984
|
}
|
|
813
985
|
|
|
814
|
-
|
|
815
|
-
VALUE column_name = rb_interned_str(column.name, column.name_len);
|
|
816
|
-
#else
|
|
817
|
-
VALUE column_name = rb_str_new(column.name, column.name_len);
|
|
818
|
-
OBJ_FREEZE(column_name);
|
|
819
|
-
#endif
|
|
986
|
+
column_names = rb_ary_new_from_values(column_count, row_ruby_values);
|
|
820
987
|
|
|
821
|
-
|
|
988
|
+
VALUE rb_trilogy_values;
|
|
989
|
+
trilogy_value_t *row_trilogy_values = ALLOCV_N(trilogy_value_t, rb_trilogy_values, column_count);
|
|
822
990
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
column_info[i].len = column.len;
|
|
826
|
-
column_info[i].charset = column.charset;
|
|
827
|
-
column_info[i].decimals = column.decimals;
|
|
828
|
-
}
|
|
991
|
+
while (1) {
|
|
992
|
+
int rc = trilogy_read_row(&ctx->conn, row_trilogy_values);
|
|
829
993
|
|
|
830
|
-
|
|
831
|
-
|
|
994
|
+
if (rc == TRILOGY_AGAIN) {
|
|
995
|
+
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
996
|
+
if (rc != TRILOGY_OK) {
|
|
997
|
+
return read_query_error(args, rc, "trilogy_read_row");
|
|
998
|
+
}
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
832
1001
|
|
|
833
|
-
|
|
834
|
-
|
|
1002
|
+
if (rc == TRILOGY_EOF) {
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
835
1005
|
|
|
836
|
-
if (rc == TRILOGY_AGAIN) {
|
|
837
|
-
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
838
1006
|
if (rc != TRILOGY_OK) {
|
|
839
1007
|
return read_query_error(args, rc, "trilogy_read_row");
|
|
840
1008
|
}
|
|
841
|
-
continue;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
if (rc == TRILOGY_EOF) {
|
|
845
|
-
break;
|
|
846
|
-
}
|
|
847
1009
|
|
|
848
|
-
if (rc != TRILOGY_OK) {
|
|
849
|
-
return read_query_error(args, rc, "trilogy_read_row");
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
if (args->cast_options->flatten_rows) {
|
|
853
1010
|
for (uint64_t i = 0; i < column_count; i++) {
|
|
854
|
-
|
|
1011
|
+
row_ruby_values[i] = rb_trilogy_cast_value(row_trilogy_values + i, column_info + i, args->cast_options);
|
|
855
1012
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1013
|
+
|
|
1014
|
+
if (args->cast_options->flatten_rows) {
|
|
1015
|
+
rb_ary_cat(rows, row_ruby_values, column_count);
|
|
1016
|
+
} else {
|
|
1017
|
+
rb_ary_push(rows, rb_ary_new_from_values(column_count, row_ruby_values));
|
|
860
1018
|
}
|
|
861
|
-
rb_ary_push(rows, row);
|
|
862
1019
|
}
|
|
863
|
-
}
|
|
864
1020
|
|
|
865
|
-
|
|
1021
|
+
ALLOCV_END(rb_column_info);
|
|
1022
|
+
ALLOCV_END(rb_trilogy_values);
|
|
1023
|
+
ALLOCV_END(rb_ruby_values);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
return rb_class_new_instance(
|
|
1027
|
+
6,
|
|
1028
|
+
(VALUE []){
|
|
1029
|
+
column_names,
|
|
1030
|
+
rows,
|
|
1031
|
+
DBL2NUM(query_time),
|
|
1032
|
+
(ctx->conn.server_status & TRILOGY_SERVER_STATUS_IN_TRANS) ? Qtrue : Qfalse,
|
|
1033
|
+
affected_rows,
|
|
1034
|
+
last_insert_id,
|
|
1035
|
+
},
|
|
1036
|
+
Trilogy_Result
|
|
1037
|
+
);
|
|
866
1038
|
}
|
|
867
1039
|
|
|
868
1040
|
static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
|
@@ -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
|
|
|
@@ -917,12 +1093,39 @@ static VALUE rb_trilogy_more_results_exist(VALUE self)
|
|
|
917
1093
|
}
|
|
918
1094
|
}
|
|
919
1095
|
|
|
1096
|
+
static VALUE rb_trilogy_abandon_results(VALUE self)
|
|
1097
|
+
{
|
|
1098
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
1099
|
+
|
|
1100
|
+
long count = 0;
|
|
1101
|
+
while (ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS) {
|
|
1102
|
+
count++;
|
|
1103
|
+
int rc = trilogy_drain_results(&ctx->conn);
|
|
1104
|
+
while (rc == TRILOGY_AGAIN) {
|
|
1105
|
+
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
1106
|
+
if (rc != TRILOGY_OK) {
|
|
1107
|
+
handle_trilogy_error(ctx, rc, "trilogy_sock_wait_read");
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
rc = trilogy_drain_results(&ctx->conn);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (rc != TRILOGY_OK) {
|
|
1114
|
+
handle_trilogy_error(ctx, rc, "trilogy_drain_results");
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return LONG2NUM(count);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
920
1121
|
static VALUE rb_trilogy_query(VALUE self, VALUE query)
|
|
921
1122
|
{
|
|
922
1123
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
923
1124
|
|
|
924
1125
|
StringValue(query);
|
|
925
|
-
query = rb_str_export_to_enc(query,
|
|
1126
|
+
query = rb_str_export_to_enc(query, ctx->encoding);
|
|
1127
|
+
|
|
1128
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
926
1129
|
|
|
927
1130
|
int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
|
|
928
1131
|
|
|
@@ -941,6 +1144,8 @@ static VALUE rb_trilogy_ping(VALUE self)
|
|
|
941
1144
|
{
|
|
942
1145
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
943
1146
|
|
|
1147
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1148
|
+
|
|
944
1149
|
int rc = trilogy_ping_send(&ctx->conn);
|
|
945
1150
|
|
|
946
1151
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -968,6 +1173,7 @@ static VALUE rb_trilogy_ping(VALUE self)
|
|
|
968
1173
|
}
|
|
969
1174
|
}
|
|
970
1175
|
|
|
1176
|
+
rb_trilogy_release_buffer(ctx);
|
|
971
1177
|
return Qtrue;
|
|
972
1178
|
}
|
|
973
1179
|
|
|
@@ -985,13 +1191,19 @@ static VALUE rb_trilogy_escape(VALUE self, VALUE str)
|
|
|
985
1191
|
const char *escaped_str;
|
|
986
1192
|
size_t escaped_len;
|
|
987
1193
|
|
|
1194
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1195
|
+
|
|
988
1196
|
int rc = trilogy_escape(&ctx->conn, RSTRING_PTR(str), RSTRING_LEN(str), &escaped_str, &escaped_len);
|
|
989
1197
|
|
|
990
1198
|
if (rc < 0) {
|
|
991
1199
|
handle_trilogy_error(ctx, rc, "trilogy_escape");
|
|
992
1200
|
}
|
|
993
1201
|
|
|
994
|
-
|
|
1202
|
+
VALUE escaped_string = rb_enc_str_new(escaped_str, escaped_len, str_enc);
|
|
1203
|
+
|
|
1204
|
+
rb_trilogy_release_buffer(ctx);
|
|
1205
|
+
|
|
1206
|
+
return escaped_string;
|
|
995
1207
|
}
|
|
996
1208
|
|
|
997
1209
|
static VALUE rb_trilogy_close(VALUE self)
|
|
@@ -1002,6 +1214,8 @@ static VALUE rb_trilogy_close(VALUE self)
|
|
|
1002
1214
|
return Qnil;
|
|
1003
1215
|
}
|
|
1004
1216
|
|
|
1217
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1218
|
+
|
|
1005
1219
|
int rc = trilogy_close_send(&ctx->conn);
|
|
1006
1220
|
|
|
1007
1221
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -1027,6 +1241,8 @@ static VALUE rb_trilogy_close(VALUE self)
|
|
|
1027
1241
|
// we must clear any SSL errors left in the queue from a read/write.
|
|
1028
1242
|
ERR_clear_error();
|
|
1029
1243
|
|
|
1244
|
+
rb_trilogy_release_buffer(ctx);
|
|
1245
|
+
|
|
1030
1246
|
trilogy_free(&ctx->conn);
|
|
1031
1247
|
|
|
1032
1248
|
return Qnil;
|
|
@@ -1134,14 +1350,15 @@ static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_
|
|
|
1134
1350
|
|
|
1135
1351
|
RUBY_FUNC_EXPORTED void Init_cext(void)
|
|
1136
1352
|
{
|
|
1137
|
-
#ifdef
|
|
1353
|
+
#ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
1138
1354
|
rb_ext_ractor_safe(true);
|
|
1355
|
+
buffer_pool_key = rb_ractor_local_storage_value_newkey();
|
|
1139
1356
|
#endif
|
|
1140
1357
|
|
|
1141
1358
|
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
|
1142
1359
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
|
1143
1360
|
|
|
1144
|
-
rb_define_private_method(Trilogy, "_connect", rb_trilogy_connect,
|
|
1361
|
+
rb_define_private_method(Trilogy, "_connect", rb_trilogy_connect, 4);
|
|
1145
1362
|
rb_define_method(Trilogy, "change_db", rb_trilogy_change_db, 1);
|
|
1146
1363
|
rb_define_alias(Trilogy, "select_db", "change_db");
|
|
1147
1364
|
rb_define_method(Trilogy, "query", rb_trilogy_query, 1);
|
|
@@ -1165,6 +1382,7 @@ RUBY_FUNC_EXPORTED void Init_cext(void)
|
|
|
1165
1382
|
rb_define_method(Trilogy, "server_version", rb_trilogy_server_version, 0);
|
|
1166
1383
|
rb_define_method(Trilogy, "more_results_exist?", rb_trilogy_more_results_exist, 0);
|
|
1167
1384
|
rb_define_method(Trilogy, "next_result", rb_trilogy_next_result, 0);
|
|
1385
|
+
rb_define_method(Trilogy, "abandon_results!", rb_trilogy_abandon_results, 0);
|
|
1168
1386
|
rb_define_method(Trilogy, "set_server_option", rb_trilogy_set_server_option, 1);
|
|
1169
1387
|
rb_define_const(Trilogy, "TLS_VERSION_10", INT2NUM(TRILOGY_TLS_VERSION_10));
|
|
1170
1388
|
rb_define_const(Trilogy, "TLS_VERSION_11", INT2NUM(TRILOGY_TLS_VERSION_11));
|
|
@@ -1249,12 +1467,6 @@ RUBY_FUNC_EXPORTED void Init_cext(void)
|
|
|
1249
1467
|
id_multi_result = rb_intern("multi_result");
|
|
1250
1468
|
id_from_code = rb_intern("from_code");
|
|
1251
1469
|
id_from_errno = rb_intern("from_errno");
|
|
1252
|
-
id_ivar_affected_rows = rb_intern("@affected_rows");
|
|
1253
|
-
id_ivar_fields = rb_intern("@fields");
|
|
1254
|
-
id_ivar_last_insert_id = rb_intern("@last_insert_id");
|
|
1255
|
-
id_ivar_rows = rb_intern("@rows");
|
|
1256
|
-
id_ivar_query_time = rb_intern("@query_time");
|
|
1257
|
-
id_connection_options = rb_intern("@connection_options");
|
|
1258
1470
|
|
|
1259
1471
|
rb_trilogy_cast_init();
|
|
1260
1472
|
|