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