trilogy 2.2.0 → 2.4.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 +4 -4
- data/README.md +7 -1
- data/ext/trilogy-ruby/cast.c +12 -7
- data/ext/trilogy-ruby/cext.c +230 -88
- data/ext/trilogy-ruby/extconf.rb +1 -1
- data/ext/trilogy-ruby/inc/trilogy/blocking.h +18 -1
- data/ext/trilogy-ruby/inc/trilogy/client.h +58 -0
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +56 -35
- data/ext/trilogy-ruby/inc/trilogy/socket.h +2 -0
- data/ext/trilogy-ruby/src/blocking.c +23 -0
- data/ext/trilogy-ruby/src/client.c +51 -3
- data/ext/trilogy-ruby/src/protocol.c +21 -6
- data/ext/trilogy-ruby/src/socket.c +25 -0
- data/ext/trilogy-ruby/trilogy-ruby.h +4 -1
- data/lib/trilogy/version.rb +1 -1
- data/lib/trilogy.rb +238 -20
- metadata +3 -3
data/ext/trilogy-ruby/cext.c
CHANGED
@@ -8,29 +8,40 @@
|
|
8
8
|
#include <sys/time.h>
|
9
9
|
#include <sys/un.h>
|
10
10
|
|
11
|
+
#include <unistd.h>
|
12
|
+
#include <fcntl.h>
|
13
|
+
|
11
14
|
#include <trilogy.h>
|
12
15
|
|
13
16
|
#include "trilogy-ruby.h"
|
14
17
|
|
15
18
|
#define TRILOGY_RB_TIMEOUT 1
|
16
19
|
|
17
|
-
VALUE
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
VALUE Trilogy_CastError;
|
21
|
+
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
22
|
+
Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError,
|
23
|
+
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result;
|
21
24
|
|
22
25
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
23
26
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
24
27
|
id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
|
25
28
|
id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
26
|
-
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version
|
29
|
+
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
|
30
|
+
id_from_code, id_from_errno, id_connection_options;
|
27
31
|
|
28
32
|
struct trilogy_ctx {
|
29
33
|
trilogy_conn_t conn;
|
30
34
|
char server_version[TRILOGY_SERVER_VERSION_SIZE + 1];
|
31
35
|
unsigned int query_flags;
|
36
|
+
VALUE encoding;
|
32
37
|
};
|
33
38
|
|
39
|
+
static void mark_trilogy(void *ptr)
|
40
|
+
{
|
41
|
+
struct trilogy_ctx *ctx = ptr;
|
42
|
+
rb_gc_mark(ctx->encoding);
|
43
|
+
}
|
44
|
+
|
34
45
|
static void free_trilogy(void *ptr)
|
35
46
|
{
|
36
47
|
struct trilogy_ctx *ctx = ptr;
|
@@ -50,10 +61,10 @@ static size_t trilogy_memsize(const void *ptr) {
|
|
50
61
|
return memsize;
|
51
62
|
}
|
52
63
|
|
53
|
-
const rb_data_type_t trilogy_data_type = {
|
64
|
+
static const rb_data_type_t trilogy_data_type = {
|
54
65
|
.wrap_struct_name = "trilogy",
|
55
66
|
.function = {
|
56
|
-
.dmark =
|
67
|
+
.dmark = mark_trilogy,
|
57
68
|
.dfree = free_trilogy,
|
58
69
|
.dsize = trilogy_memsize,
|
59
70
|
},
|
@@ -72,12 +83,25 @@ static struct trilogy_ctx *get_open_ctx(VALUE obj)
|
|
72
83
|
struct trilogy_ctx *ctx = get_ctx(obj);
|
73
84
|
|
74
85
|
if (ctx->conn.socket == NULL) {
|
75
|
-
rb_raise(
|
86
|
+
rb_raise(Trilogy_ConnectionClosedError, "Attempted to use closed connection");
|
76
87
|
}
|
77
88
|
|
78
89
|
return ctx;
|
79
90
|
}
|
80
91
|
|
92
|
+
NORETURN(static void trilogy_syserr_fail_str(int, VALUE));
|
93
|
+
static void trilogy_syserr_fail_str(int e, VALUE msg)
|
94
|
+
{
|
95
|
+
if (e == ECONNREFUSED) {
|
96
|
+
rb_raise(Trilogy_ConnectionRefusedError, "%" PRIsVALUE, msg);
|
97
|
+
} else if (e == ECONNRESET) {
|
98
|
+
rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg);
|
99
|
+
} else {
|
100
|
+
VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg);
|
101
|
+
rb_exc_raise(exc);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
81
105
|
NORETURN(static void handle_trilogy_error(struct trilogy_ctx *, int, const char *, ...));
|
82
106
|
static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *msg, ...)
|
83
107
|
{
|
@@ -88,16 +112,11 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
88
112
|
|
89
113
|
switch (rc) {
|
90
114
|
case TRILOGY_SYSERR:
|
91
|
-
|
115
|
+
trilogy_syserr_fail_str(errno, rbmsg);
|
92
116
|
|
93
117
|
case TRILOGY_ERR: {
|
94
118
|
VALUE message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
|
95
|
-
VALUE exc =
|
96
|
-
rb_sprintf("%" PRIsVALUE ": %d %" PRIsVALUE, rbmsg, ctx->conn.error_code, message));
|
97
|
-
|
98
|
-
rb_ivar_set(exc, rb_intern("@error_code"), INT2FIX(ctx->conn.error_code));
|
99
|
-
rb_ivar_set(exc, rb_intern("@error_message"), message);
|
100
|
-
|
119
|
+
VALUE exc = rb_funcall(Trilogy_ProtocolError, id_from_code, 2, message, INT2NUM(ctx->conn.error_code));
|
101
120
|
rb_exc_raise(exc);
|
102
121
|
}
|
103
122
|
|
@@ -105,18 +124,23 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
105
124
|
unsigned long ossl_error = ERR_get_error();
|
106
125
|
ERR_clear_error();
|
107
126
|
if (ERR_GET_LIB(ossl_error) == ERR_LIB_SYS) {
|
108
|
-
|
127
|
+
int err_reason = ERR_GET_REASON(ossl_error);
|
128
|
+
trilogy_syserr_fail_str(err_reason, rbmsg);
|
109
129
|
}
|
110
130
|
// We can't recover from OpenSSL level errors if there's
|
111
131
|
// an active connection.
|
112
132
|
if (ctx->conn.socket != NULL) {
|
113
133
|
trilogy_sock_shutdown(ctx->conn.socket);
|
114
134
|
}
|
115
|
-
rb_raise(
|
135
|
+
rb_raise(Trilogy_SSLError, "%" PRIsVALUE ": SSL Error: %s", rbmsg, ERR_reason_error_string(ossl_error));
|
136
|
+
}
|
137
|
+
|
138
|
+
case TRILOGY_DNS_ERR: {
|
139
|
+
rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE ": TRILOGY_DNS_ERROR", rbmsg);
|
116
140
|
}
|
117
141
|
|
118
142
|
default:
|
119
|
-
rb_raise(
|
143
|
+
rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": %s", rbmsg, trilogy_error(rc));
|
120
144
|
}
|
121
145
|
}
|
122
146
|
|
@@ -129,7 +153,8 @@ static VALUE allocate_trilogy(VALUE klass)
|
|
129
153
|
ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
|
130
154
|
|
131
155
|
if (trilogy_init(&ctx->conn) < 0) {
|
132
|
-
|
156
|
+
VALUE rbmsg = rb_str_new("trilogy_init", 13);
|
157
|
+
trilogy_syserr_fail_str(errno, rbmsg);
|
133
158
|
}
|
134
159
|
|
135
160
|
return obj;
|
@@ -145,7 +170,7 @@ static int flush_writes(struct trilogy_ctx *ctx)
|
|
145
170
|
}
|
146
171
|
|
147
172
|
if (trilogy_sock_wait_write(ctx->conn.socket) < 0) {
|
148
|
-
|
173
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_flush_writes");
|
149
174
|
}
|
150
175
|
}
|
151
176
|
}
|
@@ -279,7 +304,7 @@ static void auth_switch(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake)
|
|
279
304
|
}
|
280
305
|
|
281
306
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
282
|
-
|
307
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_auth_recv");
|
283
308
|
}
|
284
309
|
}
|
285
310
|
}
|
@@ -305,7 +330,7 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
305
330
|
}
|
306
331
|
} else {
|
307
332
|
if (ssl_mode != TRILOGY_SSL_PREFERRED_NOVERIFY) {
|
308
|
-
rb_raise(
|
333
|
+
rb_raise(Trilogy_SSLError, "SSL required, not supported by server");
|
309
334
|
}
|
310
335
|
}
|
311
336
|
}
|
@@ -332,7 +357,7 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
332
357
|
}
|
333
358
|
|
334
359
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
335
|
-
|
360
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_auth_recv");
|
336
361
|
}
|
337
362
|
}
|
338
363
|
|
@@ -341,14 +366,18 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
341
366
|
}
|
342
367
|
}
|
343
368
|
|
344
|
-
static VALUE rb_trilogy_initialize(VALUE self, VALUE opts)
|
369
|
+
static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VALUE opts)
|
345
370
|
{
|
346
371
|
struct trilogy_ctx *ctx = get_ctx(self);
|
347
372
|
trilogy_sockopt_t connopt = {0};
|
348
373
|
trilogy_handshake_t handshake;
|
349
374
|
VALUE val;
|
350
375
|
|
376
|
+
RB_OBJ_WRITE(self, &ctx->encoding, encoding);
|
377
|
+
connopt.encoding = NUM2INT(charset);
|
378
|
+
|
351
379
|
Check_Type(opts, T_HASH);
|
380
|
+
rb_ivar_set(self, id_connection_options, opts);
|
352
381
|
|
353
382
|
if ((val = rb_hash_lookup(opts, ID2SYM(id_ssl_mode))) != Qnil) {
|
354
383
|
Check_Type(val, T_FIXNUM);
|
@@ -426,6 +455,14 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE opts)
|
|
426
455
|
connopt.flags |= TRILOGY_CAPABILITIES_FOUND_ROWS;
|
427
456
|
}
|
428
457
|
|
458
|
+
if (RTEST(rb_hash_aref(opts, ID2SYM(id_multi_result)))) {
|
459
|
+
connopt.flags |= TRILOGY_CAPABILITIES_MULTI_RESULTS;
|
460
|
+
}
|
461
|
+
|
462
|
+
if (RTEST(rb_hash_aref(opts, ID2SYM(id_multi_statement)))) {
|
463
|
+
connopt.flags |= TRILOGY_CAPABILITIES_MULTI_STATEMENTS | TRILOGY_CAPABILITIES_MULTI_RESULTS;
|
464
|
+
}
|
465
|
+
|
429
466
|
if ((val = rb_hash_aref(opts, ID2SYM(id_ssl_ca))) != Qnil) {
|
430
467
|
Check_Type(val, T_STRING);
|
431
468
|
connopt.ssl_ca = StringValueCStr(val);
|
@@ -478,7 +515,7 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE opts)
|
|
478
515
|
|
479
516
|
int rc = try_connect(ctx, &handshake, &connopt);
|
480
517
|
if (rc == TRILOGY_RB_TIMEOUT) {
|
481
|
-
|
518
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_connect_recv");
|
482
519
|
}
|
483
520
|
if (rc != TRILOGY_OK) {
|
484
521
|
if (connopt.path) {
|
@@ -525,29 +562,59 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
525
562
|
}
|
526
563
|
|
527
564
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
528
|
-
|
565
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_change_db_recv");
|
566
|
+
}
|
567
|
+
}
|
568
|
+
|
569
|
+
return Qtrue;
|
570
|
+
}
|
571
|
+
|
572
|
+
static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
573
|
+
{
|
574
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
575
|
+
|
576
|
+
int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
|
577
|
+
|
578
|
+
if (rc == TRILOGY_AGAIN) {
|
579
|
+
rc = flush_writes(ctx);
|
580
|
+
}
|
581
|
+
|
582
|
+
if (rc != TRILOGY_OK) {
|
583
|
+
handle_trilogy_error(ctx, rc, "trilogy_set_option_send");
|
584
|
+
}
|
585
|
+
|
586
|
+
while (1) {
|
587
|
+
rc = trilogy_set_option_recv(&ctx->conn);
|
588
|
+
|
589
|
+
if (rc == TRILOGY_OK) {
|
590
|
+
break;
|
591
|
+
}
|
592
|
+
|
593
|
+
if (rc != TRILOGY_AGAIN) {
|
594
|
+
handle_trilogy_error(ctx, rc, "trilogy_set_option_recv");
|
595
|
+
}
|
596
|
+
|
597
|
+
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
598
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_set_option_recv");
|
529
599
|
}
|
530
600
|
}
|
531
601
|
|
532
602
|
return Qtrue;
|
533
603
|
}
|
534
604
|
|
605
|
+
|
535
606
|
static void load_query_options(unsigned int query_flags, struct rb_trilogy_cast_options *cast_options)
|
536
607
|
{
|
537
608
|
cast_options->cast = (query_flags & TRILOGY_FLAGS_CAST) != 0;
|
538
609
|
cast_options->cast_booleans = (query_flags & TRILOGY_FLAGS_CAST_BOOLEANS) != 0;
|
610
|
+
cast_options->cast_decimals_to_bigdecimals = (query_flags & TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS) != 0;
|
539
611
|
cast_options->database_local_time = (query_flags & TRILOGY_FLAGS_LOCAL_TIMEZONE) != 0;
|
540
612
|
cast_options->flatten_rows = (query_flags & TRILOGY_FLAGS_FLATTEN_ROWS) != 0;
|
541
613
|
}
|
542
614
|
|
543
|
-
struct
|
615
|
+
struct read_query_response_state {
|
544
616
|
struct rb_trilogy_cast_options *cast_options;
|
545
617
|
struct trilogy_ctx *ctx;
|
546
|
-
VALUE query;
|
547
|
-
|
548
|
-
// to free by caller:
|
549
|
-
struct column_info *column_info;
|
550
|
-
trilogy_value_t *row_values;
|
551
618
|
|
552
619
|
// Error state for tracking
|
553
620
|
const char *msg;
|
@@ -570,34 +637,25 @@ static void get_timespec_monotonic(struct timespec *ts)
|
|
570
637
|
#endif
|
571
638
|
}
|
572
639
|
|
573
|
-
static VALUE read_query_error(struct
|
640
|
+
static VALUE read_query_error(struct read_query_response_state *args, int rc, const char *msg)
|
574
641
|
{
|
575
642
|
args->rc = rc;
|
576
643
|
args->msg = msg;
|
577
644
|
return Qundef;
|
578
645
|
}
|
579
646
|
|
580
|
-
static VALUE
|
647
|
+
static VALUE read_query_response(VALUE vargs)
|
581
648
|
{
|
582
|
-
struct
|
649
|
+
struct read_query_response_state *args = (void *)vargs;
|
583
650
|
struct trilogy_ctx *ctx = args->ctx;
|
584
|
-
VALUE query = args->query;
|
585
651
|
|
586
652
|
struct timespec start;
|
587
653
|
get_timespec_monotonic(&start);
|
588
654
|
|
589
|
-
int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
|
590
|
-
|
591
|
-
if (rc == TRILOGY_AGAIN) {
|
592
|
-
rc = flush_writes(ctx);
|
593
|
-
}
|
594
|
-
|
595
|
-
if (rc < 0) {
|
596
|
-
return read_query_error(args, rc, "trilogy_query_send");
|
597
|
-
}
|
598
|
-
|
599
655
|
uint64_t column_count = 0;
|
600
656
|
|
657
|
+
int rc;
|
658
|
+
|
601
659
|
while (1) {
|
602
660
|
rc = trilogy_query_recv(&ctx->conn, &column_count);
|
603
661
|
|
@@ -610,7 +668,7 @@ static VALUE execute_read_query(VALUE vargs)
|
|
610
668
|
}
|
611
669
|
|
612
670
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
613
|
-
|
671
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_query_recv");
|
614
672
|
}
|
615
673
|
}
|
616
674
|
|
@@ -636,10 +694,13 @@ static VALUE execute_read_query(VALUE vargs)
|
|
636
694
|
rb_ivar_set(result, id_ivar_affected_rows, ULL2NUM(ctx->conn.affected_rows));
|
637
695
|
|
638
696
|
return result;
|
697
|
+
} else {
|
698
|
+
rb_ivar_set(result, id_ivar_last_insert_id, Qnil);
|
699
|
+
rb_ivar_set(result, id_ivar_affected_rows, Qnil);
|
639
700
|
}
|
640
701
|
|
641
|
-
|
642
|
-
|
702
|
+
VALUE rb_column_info;
|
703
|
+
struct column_info *column_info = ALLOCV_N(struct column_info, rb_column_info, column_count);
|
643
704
|
|
644
705
|
for (uint64_t i = 0; i < column_count; i++) {
|
645
706
|
trilogy_column_t column;
|
@@ -656,7 +717,7 @@ static VALUE execute_read_query(VALUE vargs)
|
|
656
717
|
}
|
657
718
|
|
658
719
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
659
|
-
|
720
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_read_column");
|
660
721
|
}
|
661
722
|
}
|
662
723
|
|
@@ -673,17 +734,18 @@ static VALUE execute_read_query(VALUE vargs)
|
|
673
734
|
column_info[i].flags = column.flags;
|
674
735
|
column_info[i].len = column.len;
|
675
736
|
column_info[i].charset = column.charset;
|
737
|
+
column_info[i].decimals = column.decimals;
|
676
738
|
}
|
677
739
|
|
678
|
-
|
679
|
-
|
740
|
+
VALUE rb_row_values;
|
741
|
+
trilogy_value_t *row_values = ALLOCV_N(trilogy_value_t, rb_row_values, column_count);
|
680
742
|
|
681
743
|
while (1) {
|
682
744
|
int rc = trilogy_read_row(&ctx->conn, row_values);
|
683
745
|
|
684
746
|
if (rc == TRILOGY_AGAIN) {
|
685
747
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
686
|
-
|
748
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_read_row");
|
687
749
|
}
|
688
750
|
continue;
|
689
751
|
}
|
@@ -709,37 +771,23 @@ static VALUE execute_read_query(VALUE vargs)
|
|
709
771
|
}
|
710
772
|
}
|
711
773
|
|
712
|
-
if (ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS) {
|
713
|
-
rb_raise(rb_cTrilogyError, "MORE_RESULTS_EXIST");
|
714
|
-
}
|
715
|
-
|
716
774
|
return result;
|
717
775
|
}
|
718
776
|
|
719
|
-
static VALUE
|
777
|
+
static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
720
778
|
{
|
721
|
-
struct trilogy_ctx *ctx = get_open_ctx(self);
|
722
|
-
|
723
|
-
StringValue(query);
|
724
|
-
|
725
779
|
struct rb_trilogy_cast_options cast_options;
|
726
780
|
load_query_options(ctx->query_flags, &cast_options);
|
727
781
|
|
728
|
-
struct
|
782
|
+
struct read_query_response_state args = {
|
729
783
|
.cast_options = &cast_options,
|
730
|
-
.column_info = NULL,
|
731
784
|
.ctx = ctx,
|
732
|
-
.query = query,
|
733
|
-
.row_values = NULL,
|
734
785
|
.rc = TRILOGY_OK,
|
735
786
|
.msg = NULL,
|
736
787
|
};
|
737
788
|
|
738
789
|
int state = 0;
|
739
|
-
VALUE result = rb_protect(
|
740
|
-
|
741
|
-
xfree(args.column_info);
|
742
|
-
xfree(args.row_values);
|
790
|
+
VALUE result = rb_protect(read_query_response, (VALUE)&args, &state);
|
743
791
|
|
744
792
|
// If we have seen an unexpected exception, jump to it so it gets raised.
|
745
793
|
if (state) {
|
@@ -756,6 +804,48 @@ static VALUE rb_trilogy_query(VALUE self, VALUE query)
|
|
756
804
|
return result;
|
757
805
|
}
|
758
806
|
|
807
|
+
static VALUE rb_trilogy_next_result(VALUE self)
|
808
|
+
{
|
809
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
810
|
+
|
811
|
+
if (!(ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS)) {
|
812
|
+
return Qnil;
|
813
|
+
}
|
814
|
+
|
815
|
+
return execute_read_query_response(ctx);
|
816
|
+
}
|
817
|
+
|
818
|
+
static VALUE rb_trilogy_more_results_exist(VALUE self)
|
819
|
+
{
|
820
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
821
|
+
|
822
|
+
if (ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS) {
|
823
|
+
return Qtrue;
|
824
|
+
} else {
|
825
|
+
return Qfalse;
|
826
|
+
}
|
827
|
+
}
|
828
|
+
|
829
|
+
static VALUE rb_trilogy_query(VALUE self, VALUE query)
|
830
|
+
{
|
831
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
832
|
+
|
833
|
+
StringValue(query);
|
834
|
+
query = rb_str_export_to_enc(query, rb_to_encoding(ctx->encoding));
|
835
|
+
|
836
|
+
int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
|
837
|
+
|
838
|
+
if (rc == TRILOGY_AGAIN) {
|
839
|
+
rc = flush_writes(ctx);
|
840
|
+
}
|
841
|
+
|
842
|
+
if (rc < 0) {
|
843
|
+
handle_trilogy_error(ctx, rc, "trilogy_query_send");
|
844
|
+
}
|
845
|
+
|
846
|
+
return execute_read_query_response(ctx);
|
847
|
+
}
|
848
|
+
|
759
849
|
static VALUE rb_trilogy_ping(VALUE self)
|
760
850
|
{
|
761
851
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
@@ -782,7 +872,7 @@ static VALUE rb_trilogy_ping(VALUE self)
|
|
782
872
|
}
|
783
873
|
|
784
874
|
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
785
|
-
|
875
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_ping_recv");
|
786
876
|
}
|
787
877
|
}
|
788
878
|
|
@@ -857,6 +947,25 @@ static VALUE rb_trilogy_closed(VALUE self)
|
|
857
947
|
}
|
858
948
|
}
|
859
949
|
|
950
|
+
static VALUE rb_trilogy_discard(VALUE self)
|
951
|
+
{
|
952
|
+
struct trilogy_ctx *ctx = get_ctx(self);
|
953
|
+
|
954
|
+
if (ctx->conn.socket == NULL) {
|
955
|
+
return Qtrue;
|
956
|
+
}
|
957
|
+
|
958
|
+
int rc = trilogy_discard(&ctx->conn);
|
959
|
+
switch (rc) {
|
960
|
+
case TRILOGY_OK:
|
961
|
+
return Qtrue;
|
962
|
+
case TRILOGY_SYSERR:
|
963
|
+
trilogy_syserr_fail_str(errno, rb_str_new_cstr("Failed to discard connection"));
|
964
|
+
UNREACHABLE_RETURN(Qfalse);
|
965
|
+
}
|
966
|
+
return Qfalse;
|
967
|
+
}
|
968
|
+
|
860
969
|
static VALUE rb_trilogy_last_insert_id(VALUE self) { return ULL2NUM(get_open_ctx(self)->conn.last_insert_id); }
|
861
970
|
|
862
971
|
static VALUE rb_trilogy_affected_rows(VALUE self) { return ULL2NUM(get_open_ctx(self)->conn.affected_rows); }
|
@@ -916,19 +1025,19 @@ static VALUE rb_trilogy_server_status(VALUE self) { return LONG2FIX(get_open_ctx
|
|
916
1025
|
|
917
1026
|
static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_open_ctx(self)->server_version); }
|
918
1027
|
|
919
|
-
void Init_cext()
|
1028
|
+
RUBY_FUNC_EXPORTED void Init_cext()
|
920
1029
|
{
|
921
|
-
VALUE Trilogy =
|
922
|
-
|
1030
|
+
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
923
1031
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
924
1032
|
|
925
|
-
|
1033
|
+
rb_define_private_method(Trilogy, "_initialize", rb_trilogy_initialize, 3);
|
926
1034
|
rb_define_method(Trilogy, "change_db", rb_trilogy_change_db, 1);
|
927
1035
|
rb_define_method(Trilogy, "query", rb_trilogy_query, 1);
|
928
1036
|
rb_define_method(Trilogy, "ping", rb_trilogy_ping, 0);
|
929
1037
|
rb_define_method(Trilogy, "escape", rb_trilogy_escape, 1);
|
930
1038
|
rb_define_method(Trilogy, "close", rb_trilogy_close, 0);
|
931
1039
|
rb_define_method(Trilogy, "closed?", rb_trilogy_closed, 0);
|
1040
|
+
rb_define_method(Trilogy, "discard!", rb_trilogy_discard, 0);
|
932
1041
|
rb_define_method(Trilogy, "last_insert_id", rb_trilogy_last_insert_id, 0);
|
933
1042
|
rb_define_method(Trilogy, "affected_rows", rb_trilogy_affected_rows, 0);
|
934
1043
|
rb_define_method(Trilogy, "warning_count", rb_trilogy_warning_count, 0);
|
@@ -941,6 +1050,9 @@ void Init_cext()
|
|
941
1050
|
rb_define_method(Trilogy, "write_timeout=", rb_trilogy_write_timeout_set, 1);
|
942
1051
|
rb_define_method(Trilogy, "server_status", rb_trilogy_server_status, 0);
|
943
1052
|
rb_define_method(Trilogy, "server_version", rb_trilogy_server_version, 0);
|
1053
|
+
rb_define_method(Trilogy, "more_results_exist?", rb_trilogy_more_results_exist, 0);
|
1054
|
+
rb_define_method(Trilogy, "next_result", rb_trilogy_next_result, 0);
|
1055
|
+
rb_define_method(Trilogy, "set_server_option", rb_trilogy_set_server_option, 1);
|
944
1056
|
rb_define_const(Trilogy, "TLS_VERSION_10", INT2NUM(TRILOGY_TLS_VERSION_10));
|
945
1057
|
rb_define_const(Trilogy, "TLS_VERSION_11", INT2NUM(TRILOGY_TLS_VERSION_11));
|
946
1058
|
rb_define_const(Trilogy, "TLS_VERSION_12", INT2NUM(TRILOGY_TLS_VERSION_12));
|
@@ -955,27 +1067,43 @@ void Init_cext()
|
|
955
1067
|
rb_define_const(Trilogy, "QUERY_FLAGS_NONE", INT2NUM(0));
|
956
1068
|
rb_define_const(Trilogy, "QUERY_FLAGS_CAST", INT2NUM(TRILOGY_FLAGS_CAST));
|
957
1069
|
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_BOOLEANS", INT2NUM(TRILOGY_FLAGS_CAST_BOOLEANS));
|
1070
|
+
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS", INT2NUM(TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS));
|
958
1071
|
rb_define_const(Trilogy, "QUERY_FLAGS_LOCAL_TIMEZONE", INT2NUM(TRILOGY_FLAGS_LOCAL_TIMEZONE));
|
959
1072
|
rb_define_const(Trilogy, "QUERY_FLAGS_FLATTEN_ROWS", INT2NUM(TRILOGY_FLAGS_FLATTEN_ROWS));
|
960
1073
|
rb_define_const(Trilogy, "QUERY_FLAGS_DEFAULT", INT2NUM(TRILOGY_FLAGS_DEFAULT));
|
961
1074
|
|
962
|
-
|
963
|
-
rb_global_variable(&
|
1075
|
+
Trilogy_ProtocolError = rb_const_get(Trilogy, rb_intern("ProtocolError"));
|
1076
|
+
rb_global_variable(&Trilogy_ProtocolError);
|
1077
|
+
|
1078
|
+
Trilogy_SSLError = rb_const_get(Trilogy, rb_intern("SSLError"));
|
1079
|
+
rb_global_variable(&Trilogy_SSLError);
|
1080
|
+
|
1081
|
+
Trilogy_QueryError = rb_const_get(Trilogy, rb_intern("QueryError"));
|
1082
|
+
rb_global_variable(&Trilogy_QueryError);
|
1083
|
+
|
1084
|
+
Trilogy_TimeoutError = rb_const_get(Trilogy, rb_intern("TimeoutError"));
|
1085
|
+
rb_global_variable(&Trilogy_TimeoutError);
|
1086
|
+
|
1087
|
+
Trilogy_ConnectionRefusedError = rb_const_get(Trilogy, rb_intern("ConnectionRefusedError"));
|
1088
|
+
rb_global_variable(&Trilogy_ConnectionRefusedError);
|
1089
|
+
|
1090
|
+
Trilogy_ConnectionResetError = rb_const_get(Trilogy, rb_intern("ConnectionResetError"));
|
1091
|
+
rb_global_variable(&Trilogy_ConnectionResetError);
|
964
1092
|
|
965
|
-
|
966
|
-
rb_global_variable(&
|
1093
|
+
Trilogy_BaseConnectionError = rb_const_get(Trilogy, rb_intern("BaseConnectionError"));
|
1094
|
+
rb_global_variable(&Trilogy_BaseConnectionError);
|
967
1095
|
|
968
|
-
|
969
|
-
|
1096
|
+
Trilogy_ConnectionClosedError = rb_const_get(Trilogy, rb_intern("ConnectionClosed"));
|
1097
|
+
rb_global_variable(&Trilogy_ConnectionClosedError);
|
970
1098
|
|
971
|
-
Trilogy_Result =
|
1099
|
+
Trilogy_Result = rb_const_get(Trilogy, rb_intern("Result"));
|
972
1100
|
rb_global_variable(&Trilogy_Result);
|
973
1101
|
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
1102
|
+
Trilogy_SyscallError = rb_const_get(Trilogy, rb_intern("SyscallError"));
|
1103
|
+
rb_global_variable(&Trilogy_SyscallError);
|
1104
|
+
|
1105
|
+
Trilogy_CastError = rb_const_get(Trilogy, rb_intern("CastError"));
|
1106
|
+
rb_global_variable(&Trilogy_CastError);
|
979
1107
|
|
980
1108
|
id_socket = rb_intern("socket");
|
981
1109
|
id_host = rb_intern("host");
|
@@ -1002,12 +1130,16 @@ void Init_cext()
|
|
1002
1130
|
id_tls_ciphersuites = rb_intern("tls_ciphersuites");
|
1003
1131
|
id_tls_min_version = rb_intern("tls_min_version");
|
1004
1132
|
id_tls_max_version = rb_intern("tls_max_version");
|
1005
|
-
|
1133
|
+
id_multi_statement = rb_intern("multi_statement");
|
1134
|
+
id_multi_result = rb_intern("multi_result");
|
1135
|
+
id_from_code = rb_intern("from_code");
|
1136
|
+
id_from_errno = rb_intern("from_errno");
|
1006
1137
|
id_ivar_affected_rows = rb_intern("@affected_rows");
|
1007
1138
|
id_ivar_fields = rb_intern("@fields");
|
1008
1139
|
id_ivar_last_insert_id = rb_intern("@last_insert_id");
|
1009
1140
|
id_ivar_rows = rb_intern("@rows");
|
1010
1141
|
id_ivar_query_time = rb_intern("@query_time");
|
1142
|
+
id_connection_options = rb_intern("@connection_options");
|
1011
1143
|
|
1012
1144
|
rb_trilogy_cast_init();
|
1013
1145
|
|
@@ -1015,4 +1147,14 @@ void Init_cext()
|
|
1015
1147
|
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1016
1148
|
TRILOGY_SERVER_STATUS(XX)
|
1017
1149
|
#undef XX
|
1150
|
+
|
1151
|
+
// set_server_option options
|
1152
|
+
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1153
|
+
TRILOGY_SET_SERVER_OPTION(XX)
|
1154
|
+
#undef XX
|
1155
|
+
|
1156
|
+
// charsets
|
1157
|
+
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1158
|
+
TRILOGY_CHARSETS(XX)
|
1159
|
+
#undef XX
|
1018
1160
|
}
|
data/ext/trilogy-ruby/extconf.rb
CHANGED
@@ -6,7 +6,7 @@ File.binwrite("trilogy.c",
|
|
6
6
|
Dir["#{__dir__}/src/**/*.c"].map { |src| File.binread(src) }.join)
|
7
7
|
|
8
8
|
$objs = %w[trilogy.o cast.o cext.o]
|
9
|
-
$CFLAGS << " -I #{__dir__}/inc -std=gnu99"
|
9
|
+
$CFLAGS << " -I #{__dir__}/inc -std=gnu99 -fvisibility=hidden"
|
10
10
|
|
11
11
|
dir_config("openssl")
|
12
12
|
|
@@ -50,7 +50,8 @@ int trilogy_connect_sock(trilogy_conn_t *conn, trilogy_sock_t *sock);
|
|
50
50
|
/* trilogy_change_db - Change the default database for a connection.
|
51
51
|
*
|
52
52
|
* conn - A connected trilogy_conn_t pointer. Using a disconnected
|
53
|
-
*
|
53
|
+
* trilogy_conn_t is undefined.
|
54
|
+
* name - Name of the database to set as default.
|
54
55
|
* name_len - Length of the database name string in bytes.
|
55
56
|
*
|
56
57
|
* Return values
|
@@ -63,6 +64,22 @@ int trilogy_connect_sock(trilogy_conn_t *conn, trilogy_sock_t *sock);
|
|
63
64
|
*/
|
64
65
|
int trilogy_change_db(trilogy_conn_t *conn, const char *name, size_t name_len);
|
65
66
|
|
67
|
+
/* trilogy_set_option - Set server options for the connection.
|
68
|
+
*
|
69
|
+
* conn - A connected trilogy_conn_t pointer. Using a disconnected
|
70
|
+
* trilogy_conn_t is undefined.
|
71
|
+
* option - The server option to set. See: TRILOGY_SET_SERVER_OPTION_TYPE_t;
|
72
|
+
*
|
73
|
+
* Return values
|
74
|
+
* TRILOGY_OK - The change db command completed successfully.
|
75
|
+
* TRILOGY_ERR - The server returned an error.
|
76
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
77
|
+
* TRILOGY_CLOSED_CONNECTION - The connection is closed.
|
78
|
+
* TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
|
79
|
+
* packet.
|
80
|
+
*/
|
81
|
+
int trilogy_set_option(trilogy_conn_t *conn, const uint16_t option);
|
82
|
+
|
66
83
|
/* trilogy_query - Send and execute a query.
|
67
84
|
*
|
68
85
|
* conn - A connected trilogy_conn_t pointer. Using a disconnected
|