trilogy 2.3.0 → 2.4.1
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/ext/trilogy-ruby/cast.c +2 -2
- data/ext/trilogy-ruby/cext.c +124 -44
- 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 +54 -29
- 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 +2 -0
- data/lib/trilogy/version.rb +1 -1
- data/lib/trilogy.rb +130 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f62d4a5617aaf6b532cfa2888b297eba7bfb18def74e98b6a12847d2845b81f
|
4
|
+
data.tar.gz: 7c74e6d32f1ec845bccbace0b989a269d833d1582ba38ffd78e8e5f35305883d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ba24a84f4e946c1c7f797c10738fda98bcc9e1fbb0bd19f289fe9cc6cbb9bae252f9cf307c873c8a958c2d2519075d4a677cb681648e6429b18bf9c9a897bb7
|
7
|
+
data.tar.gz: 4ce6afb50256faf2ec873a71194295c9538a4d2188ecae65018b51f8869a97e4cb68eecef6829f9053ef31a5dca1defd107b46281478e02eb5b10606dae3da99
|
data/ext/trilogy-ruby/cast.c
CHANGED
@@ -145,7 +145,7 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
145
145
|
// TODO - optimize so we don't have to allocate a ruby string for
|
146
146
|
// decimal columns
|
147
147
|
VALUE str = rb_str_new(value->data, value->data_len);
|
148
|
-
if (column->decimals == 0) {
|
148
|
+
if (column->decimals == 0 && !options->cast_decimals_to_bigdecimals) {
|
149
149
|
return rb_funcall(rb_mKernel, id_Integer, 1, str);
|
150
150
|
} else {
|
151
151
|
return rb_funcall(rb_mKernel, id_BigDecimal, 1, str);
|
@@ -240,7 +240,7 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
240
240
|
// pad out msec_char with zeroes at the end as it could be at any
|
241
241
|
// level of precision
|
242
242
|
for (size_t i = strlen(msec_char); i < sizeof(msec_char) - 1; i++) {
|
243
|
-
msec_char[i] = 0;
|
243
|
+
msec_char[i] = '0';
|
244
244
|
}
|
245
245
|
|
246
246
|
return rb_funcall(rb_cTime, options->database_local_time ? id_local : id_utc, 7, INT2NUM(2000), INT2NUM(1),
|
data/ext/trilogy-ruby/cext.c
CHANGED
@@ -8,6 +8,9 @@
|
|
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"
|
@@ -16,21 +19,29 @@
|
|
16
19
|
|
17
20
|
VALUE Trilogy_CastError;
|
18
21
|
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
19
|
-
Trilogy_ConnectionClosedError,
|
22
|
+
Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError,
|
23
|
+
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result;
|
20
24
|
|
21
25
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
22
26
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
23
27
|
id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
|
24
28
|
id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
25
|
-
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement,
|
26
|
-
id_connection_options;
|
29
|
+
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement,
|
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
|
},
|
@@ -78,6 +89,19 @@ static struct trilogy_ctx *get_open_ctx(VALUE obj)
|
|
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,12 +112,7 @@ 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
|
-
|
92
|
-
rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE, rbmsg);
|
93
|
-
} else {
|
94
|
-
// TODO: All syserr should be wrapped.
|
95
|
-
rb_syserr_fail_str(errno, rbmsg);
|
96
|
-
}
|
115
|
+
trilogy_syserr_fail_str(errno, rbmsg);
|
97
116
|
|
98
117
|
case TRILOGY_ERR: {
|
99
118
|
VALUE message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
|
@@ -106,13 +125,7 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
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);
|
109
|
-
|
110
|
-
if (err_reason == ECONNREFUSED || err_reason == ECONNRESET) {
|
111
|
-
rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE, rbmsg);
|
112
|
-
} else {
|
113
|
-
// TODO: All syserr should be wrapped.
|
114
|
-
rb_syserr_fail_str(err_reason, rbmsg);
|
115
|
-
}
|
128
|
+
trilogy_syserr_fail_str(err_reason, rbmsg);
|
116
129
|
}
|
117
130
|
// We can't recover from OpenSSL level errors if there's
|
118
131
|
// an active connection.
|
@@ -140,13 +153,8 @@ static VALUE allocate_trilogy(VALUE klass)
|
|
140
153
|
ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
|
141
154
|
|
142
155
|
if (trilogy_init(&ctx->conn) < 0) {
|
143
|
-
|
144
|
-
|
145
|
-
} else {
|
146
|
-
// TODO: All syserr should be wrapped.
|
147
|
-
VALUE rbmsg = rb_str_new("trilogy_init", 13);
|
148
|
-
rb_syserr_fail_str(errno, rbmsg);
|
149
|
-
}
|
156
|
+
VALUE rbmsg = rb_str_new("trilogy_init", 13);
|
157
|
+
trilogy_syserr_fail_str(errno, rbmsg);
|
150
158
|
}
|
151
159
|
|
152
160
|
return obj;
|
@@ -358,13 +366,16 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
358
366
|
}
|
359
367
|
}
|
360
368
|
|
361
|
-
static VALUE rb_trilogy_initialize(VALUE self, VALUE opts)
|
369
|
+
static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VALUE opts)
|
362
370
|
{
|
363
371
|
struct trilogy_ctx *ctx = get_ctx(self);
|
364
372
|
trilogy_sockopt_t connopt = {0};
|
365
373
|
trilogy_handshake_t handshake;
|
366
374
|
VALUE val;
|
367
375
|
|
376
|
+
RB_OBJ_WRITE(self, &ctx->encoding, encoding);
|
377
|
+
connopt.encoding = NUM2INT(charset);
|
378
|
+
|
368
379
|
Check_Type(opts, T_HASH);
|
369
380
|
rb_ivar_set(self, id_connection_options, opts);
|
370
381
|
|
@@ -554,10 +565,45 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
554
565
|
return Qtrue;
|
555
566
|
}
|
556
567
|
|
568
|
+
static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
569
|
+
{
|
570
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
571
|
+
|
572
|
+
int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
|
573
|
+
|
574
|
+
if (rc == TRILOGY_AGAIN) {
|
575
|
+
rc = flush_writes(ctx);
|
576
|
+
}
|
577
|
+
|
578
|
+
if (rc != TRILOGY_OK) {
|
579
|
+
handle_trilogy_error(ctx, rc, "trilogy_set_option_send");
|
580
|
+
}
|
581
|
+
|
582
|
+
while (1) {
|
583
|
+
rc = trilogy_set_option_recv(&ctx->conn);
|
584
|
+
|
585
|
+
if (rc == TRILOGY_OK) {
|
586
|
+
break;
|
587
|
+
}
|
588
|
+
|
589
|
+
if (rc != TRILOGY_AGAIN) {
|
590
|
+
handle_trilogy_error(ctx, rc, "trilogy_set_option_recv");
|
591
|
+
}
|
592
|
+
|
593
|
+
if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
|
594
|
+
rb_raise(Trilogy_TimeoutError, "trilogy_set_option_recv");
|
595
|
+
}
|
596
|
+
}
|
597
|
+
|
598
|
+
return Qtrue;
|
599
|
+
}
|
600
|
+
|
601
|
+
|
557
602
|
static void load_query_options(unsigned int query_flags, struct rb_trilogy_cast_options *cast_options)
|
558
603
|
{
|
559
604
|
cast_options->cast = (query_flags & TRILOGY_FLAGS_CAST) != 0;
|
560
605
|
cast_options->cast_booleans = (query_flags & TRILOGY_FLAGS_CAST_BOOLEANS) != 0;
|
606
|
+
cast_options->cast_decimals_to_bigdecimals = (query_flags & TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS) != 0;
|
561
607
|
cast_options->database_local_time = (query_flags & TRILOGY_FLAGS_LOCAL_TIMEZONE) != 0;
|
562
608
|
cast_options->flatten_rows = (query_flags & TRILOGY_FLAGS_FLATTEN_ROWS) != 0;
|
563
609
|
}
|
@@ -566,10 +612,6 @@ struct read_query_response_state {
|
|
566
612
|
struct rb_trilogy_cast_options *cast_options;
|
567
613
|
struct trilogy_ctx *ctx;
|
568
614
|
|
569
|
-
// to free by caller:
|
570
|
-
struct column_info *column_info;
|
571
|
-
trilogy_value_t *row_values;
|
572
|
-
|
573
615
|
// Error state for tracking
|
574
616
|
const char *msg;
|
575
617
|
int rc;
|
@@ -648,10 +690,13 @@ static VALUE read_query_response(VALUE vargs)
|
|
648
690
|
rb_ivar_set(result, id_ivar_affected_rows, ULL2NUM(ctx->conn.affected_rows));
|
649
691
|
|
650
692
|
return result;
|
693
|
+
} else {
|
694
|
+
rb_ivar_set(result, id_ivar_last_insert_id, Qnil);
|
695
|
+
rb_ivar_set(result, id_ivar_affected_rows, Qnil);
|
651
696
|
}
|
652
697
|
|
653
|
-
|
654
|
-
|
698
|
+
VALUE rb_column_info;
|
699
|
+
struct column_info *column_info = ALLOCV_N(struct column_info, rb_column_info, column_count);
|
655
700
|
|
656
701
|
for (uint64_t i = 0; i < column_count; i++) {
|
657
702
|
trilogy_column_t column;
|
@@ -688,8 +733,8 @@ static VALUE read_query_response(VALUE vargs)
|
|
688
733
|
column_info[i].decimals = column.decimals;
|
689
734
|
}
|
690
735
|
|
691
|
-
|
692
|
-
|
736
|
+
VALUE rb_row_values;
|
737
|
+
trilogy_value_t *row_values = ALLOCV_N(trilogy_value_t, rb_row_values, column_count);
|
693
738
|
|
694
739
|
while (1) {
|
695
740
|
int rc = trilogy_read_row(&ctx->conn, row_values);
|
@@ -732,9 +777,7 @@ static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
|
732
777
|
|
733
778
|
struct read_query_response_state args = {
|
734
779
|
.cast_options = &cast_options,
|
735
|
-
.column_info = NULL,
|
736
780
|
.ctx = ctx,
|
737
|
-
.row_values = NULL,
|
738
781
|
.rc = TRILOGY_OK,
|
739
782
|
.msg = NULL,
|
740
783
|
};
|
@@ -742,9 +785,6 @@ static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
|
742
785
|
int state = 0;
|
743
786
|
VALUE result = rb_protect(read_query_response, (VALUE)&args, &state);
|
744
787
|
|
745
|
-
xfree(args.column_info);
|
746
|
-
xfree(args.row_values);
|
747
|
-
|
748
788
|
// If we have seen an unexpected exception, jump to it so it gets raised.
|
749
789
|
if (state) {
|
750
790
|
trilogy_sock_shutdown(ctx->conn.socket);
|
@@ -787,6 +827,7 @@ static VALUE rb_trilogy_query(VALUE self, VALUE query)
|
|
787
827
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
788
828
|
|
789
829
|
StringValue(query);
|
830
|
+
query = rb_str_export_to_enc(query, rb_to_encoding(ctx->encoding));
|
790
831
|
|
791
832
|
int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
|
792
833
|
|
@@ -902,6 +943,25 @@ static VALUE rb_trilogy_closed(VALUE self)
|
|
902
943
|
}
|
903
944
|
}
|
904
945
|
|
946
|
+
static VALUE rb_trilogy_discard(VALUE self)
|
947
|
+
{
|
948
|
+
struct trilogy_ctx *ctx = get_ctx(self);
|
949
|
+
|
950
|
+
if (ctx->conn.socket == NULL) {
|
951
|
+
return Qtrue;
|
952
|
+
}
|
953
|
+
|
954
|
+
int rc = trilogy_discard(&ctx->conn);
|
955
|
+
switch (rc) {
|
956
|
+
case TRILOGY_OK:
|
957
|
+
return Qtrue;
|
958
|
+
case TRILOGY_SYSERR:
|
959
|
+
trilogy_syserr_fail_str(errno, rb_str_new_cstr("Failed to discard connection"));
|
960
|
+
UNREACHABLE_RETURN(Qfalse);
|
961
|
+
}
|
962
|
+
return Qfalse;
|
963
|
+
}
|
964
|
+
|
905
965
|
static VALUE rb_trilogy_last_insert_id(VALUE self) { return ULL2NUM(get_open_ctx(self)->conn.last_insert_id); }
|
906
966
|
|
907
967
|
static VALUE rb_trilogy_affected_rows(VALUE self) { return ULL2NUM(get_open_ctx(self)->conn.affected_rows); }
|
@@ -961,18 +1021,19 @@ static VALUE rb_trilogy_server_status(VALUE self) { return LONG2FIX(get_open_ctx
|
|
961
1021
|
|
962
1022
|
static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_open_ctx(self)->server_version); }
|
963
1023
|
|
964
|
-
void Init_cext()
|
1024
|
+
RUBY_FUNC_EXPORTED void Init_cext()
|
965
1025
|
{
|
966
1026
|
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
967
1027
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
968
1028
|
|
969
|
-
|
1029
|
+
rb_define_private_method(Trilogy, "_initialize", rb_trilogy_initialize, 3);
|
970
1030
|
rb_define_method(Trilogy, "change_db", rb_trilogy_change_db, 1);
|
971
1031
|
rb_define_method(Trilogy, "query", rb_trilogy_query, 1);
|
972
1032
|
rb_define_method(Trilogy, "ping", rb_trilogy_ping, 0);
|
973
1033
|
rb_define_method(Trilogy, "escape", rb_trilogy_escape, 1);
|
974
1034
|
rb_define_method(Trilogy, "close", rb_trilogy_close, 0);
|
975
1035
|
rb_define_method(Trilogy, "closed?", rb_trilogy_closed, 0);
|
1036
|
+
rb_define_method(Trilogy, "discard!", rb_trilogy_discard, 0);
|
976
1037
|
rb_define_method(Trilogy, "last_insert_id", rb_trilogy_last_insert_id, 0);
|
977
1038
|
rb_define_method(Trilogy, "affected_rows", rb_trilogy_affected_rows, 0);
|
978
1039
|
rb_define_method(Trilogy, "warning_count", rb_trilogy_warning_count, 0);
|
@@ -987,6 +1048,7 @@ void Init_cext()
|
|
987
1048
|
rb_define_method(Trilogy, "server_version", rb_trilogy_server_version, 0);
|
988
1049
|
rb_define_method(Trilogy, "more_results_exist?", rb_trilogy_more_results_exist, 0);
|
989
1050
|
rb_define_method(Trilogy, "next_result", rb_trilogy_next_result, 0);
|
1051
|
+
rb_define_method(Trilogy, "set_server_option", rb_trilogy_set_server_option, 1);
|
990
1052
|
rb_define_const(Trilogy, "TLS_VERSION_10", INT2NUM(TRILOGY_TLS_VERSION_10));
|
991
1053
|
rb_define_const(Trilogy, "TLS_VERSION_11", INT2NUM(TRILOGY_TLS_VERSION_11));
|
992
1054
|
rb_define_const(Trilogy, "TLS_VERSION_12", INT2NUM(TRILOGY_TLS_VERSION_12));
|
@@ -1001,6 +1063,7 @@ void Init_cext()
|
|
1001
1063
|
rb_define_const(Trilogy, "QUERY_FLAGS_NONE", INT2NUM(0));
|
1002
1064
|
rb_define_const(Trilogy, "QUERY_FLAGS_CAST", INT2NUM(TRILOGY_FLAGS_CAST));
|
1003
1065
|
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_BOOLEANS", INT2NUM(TRILOGY_FLAGS_CAST_BOOLEANS));
|
1066
|
+
rb_define_const(Trilogy, "QUERY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS", INT2NUM(TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS));
|
1004
1067
|
rb_define_const(Trilogy, "QUERY_FLAGS_LOCAL_TIMEZONE", INT2NUM(TRILOGY_FLAGS_LOCAL_TIMEZONE));
|
1005
1068
|
rb_define_const(Trilogy, "QUERY_FLAGS_FLATTEN_ROWS", INT2NUM(TRILOGY_FLAGS_FLATTEN_ROWS));
|
1006
1069
|
rb_define_const(Trilogy, "QUERY_FLAGS_DEFAULT", INT2NUM(TRILOGY_FLAGS_DEFAULT));
|
@@ -1017,6 +1080,12 @@ void Init_cext()
|
|
1017
1080
|
Trilogy_TimeoutError = rb_const_get(Trilogy, rb_intern("TimeoutError"));
|
1018
1081
|
rb_global_variable(&Trilogy_TimeoutError);
|
1019
1082
|
|
1083
|
+
Trilogy_ConnectionRefusedError = rb_const_get(Trilogy, rb_intern("ConnectionRefusedError"));
|
1084
|
+
rb_global_variable(&Trilogy_ConnectionRefusedError);
|
1085
|
+
|
1086
|
+
Trilogy_ConnectionResetError = rb_const_get(Trilogy, rb_intern("ConnectionResetError"));
|
1087
|
+
rb_global_variable(&Trilogy_ConnectionResetError);
|
1088
|
+
|
1020
1089
|
Trilogy_BaseConnectionError = rb_const_get(Trilogy, rb_intern("BaseConnectionError"));
|
1021
1090
|
rb_global_variable(&Trilogy_BaseConnectionError);
|
1022
1091
|
|
@@ -1026,12 +1095,12 @@ void Init_cext()
|
|
1026
1095
|
Trilogy_Result = rb_const_get(Trilogy, rb_intern("Result"));
|
1027
1096
|
rb_global_variable(&Trilogy_Result);
|
1028
1097
|
|
1098
|
+
Trilogy_SyscallError = rb_const_get(Trilogy, rb_intern("SyscallError"));
|
1099
|
+
rb_global_variable(&Trilogy_SyscallError);
|
1100
|
+
|
1029
1101
|
Trilogy_CastError = rb_const_get(Trilogy, rb_intern("CastError"));
|
1030
1102
|
rb_global_variable(&Trilogy_CastError);
|
1031
1103
|
|
1032
|
-
rb_define_attr(Trilogy_Result, "affected_rows", 1, 0);
|
1033
|
-
rb_define_attr(Trilogy_Result, "last_insert_id", 1, 0);
|
1034
|
-
|
1035
1104
|
id_socket = rb_intern("socket");
|
1036
1105
|
id_host = rb_intern("host");
|
1037
1106
|
id_port = rb_intern("port");
|
@@ -1059,6 +1128,7 @@ void Init_cext()
|
|
1059
1128
|
id_tls_max_version = rb_intern("tls_max_version");
|
1060
1129
|
id_multi_statement = rb_intern("multi_statement");
|
1061
1130
|
id_from_code = rb_intern("from_code");
|
1131
|
+
id_from_errno = rb_intern("from_errno");
|
1062
1132
|
id_ivar_affected_rows = rb_intern("@affected_rows");
|
1063
1133
|
id_ivar_fields = rb_intern("@fields");
|
1064
1134
|
id_ivar_last_insert_id = rb_intern("@last_insert_id");
|
@@ -1072,4 +1142,14 @@ void Init_cext()
|
|
1072
1142
|
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1073
1143
|
TRILOGY_SERVER_STATUS(XX)
|
1074
1144
|
#undef XX
|
1145
|
+
|
1146
|
+
// set_server_option options
|
1147
|
+
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1148
|
+
TRILOGY_SET_SERVER_OPTION(XX)
|
1149
|
+
#undef XX
|
1150
|
+
|
1151
|
+
// charsets
|
1152
|
+
#define XX(name, code) rb_const_set(Trilogy, rb_intern((char *)#name + strlen("TRILOGY_")), LONG2NUM(name));
|
1153
|
+
TRILOGY_CHARSETS(XX)
|
1154
|
+
#undef XX
|
1075
1155
|
}
|
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
|
@@ -299,6 +299,50 @@ int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_l
|
|
299
299
|
*/
|
300
300
|
int trilogy_change_db_recv(trilogy_conn_t *conn);
|
301
301
|
|
302
|
+
/* trilogy_set_option_send - Send a set option command to the server. This
|
303
|
+
* will change server capabilities based on the option selected.
|
304
|
+
*
|
305
|
+
* This should only be called while the connection is ready for commands.
|
306
|
+
*
|
307
|
+
* conn - A connected trilogy_conn_t pointer. Using a disconnected
|
308
|
+
* trilogy_conn_t is undefined.
|
309
|
+
* option - The server option to send.
|
310
|
+
*
|
311
|
+
* Return values:
|
312
|
+
* TRILOGY_OK - The change database command was successfully sent to the
|
313
|
+
* server.
|
314
|
+
* TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
|
315
|
+
* for writeability using `conn->sock`. Then call
|
316
|
+
* trilogy_flush_writes.
|
317
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
318
|
+
*/
|
319
|
+
int trilogy_set_option_send(trilogy_conn_t *conn, const uint16_t option);
|
320
|
+
|
321
|
+
/* trilogy_set_option_recv - Read the set option command response from the
|
322
|
+
* server.
|
323
|
+
*
|
324
|
+
* This should be called after all data written by trilogy_set_option_send is
|
325
|
+
* flushed to the network. Calling this at any other time during the connection
|
326
|
+
* lifecycle is undefined.
|
327
|
+
*
|
328
|
+
* conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
|
329
|
+
* undefined.
|
330
|
+
*
|
331
|
+
* Return values:
|
332
|
+
* TRILOGY_OK - The set option command was successfully
|
333
|
+
* sent to the server.
|
334
|
+
* TRILOGY_AGAIN - The socket wasn't ready for reading. The
|
335
|
+
* caller should wait for readability using
|
336
|
+
* `conn->sock`. Then call this function until
|
337
|
+
* it returns a different value.
|
338
|
+
* TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
|
339
|
+
* TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
|
340
|
+
* packet.
|
341
|
+
* TRILOGY_CLOSED_CONNECTION - The connection is closed.
|
342
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
343
|
+
*/
|
344
|
+
int trilogy_set_option_recv(trilogy_conn_t *conn);
|
345
|
+
|
302
346
|
/* trilogy_query_send - Send a query command to the server.
|
303
347
|
*
|
304
348
|
* This should only be called while the connection is ready for commands.
|
@@ -543,4 +587,18 @@ int trilogy_close_recv(trilogy_conn_t *conn);
|
|
543
587
|
*/
|
544
588
|
void trilogy_free(trilogy_conn_t *conn);
|
545
589
|
|
590
|
+
/* trilogy_free - Discard the connection and free any internal buffers.
|
591
|
+
*
|
592
|
+
* The server won't be notified that connection was closed. This is useful to
|
593
|
+
* silently close connections that were inherited after forking without disrupting
|
594
|
+
* the parent's process connections.
|
595
|
+
*
|
596
|
+
* conn - A pre-initialized trilogy_conn_t pointer.
|
597
|
+
*
|
598
|
+
* Return values:
|
599
|
+
* TRILOGY_OK - The connection was successfuly discarded and freed.
|
600
|
+
* TRILOGY_SYSERR - A system error occurred, check errno. The connection wasn't freed.
|
601
|
+
*/
|
602
|
+
int trilogy_discard(trilogy_conn_t *conn);
|
603
|
+
|
546
604
|
#endif
|
@@ -90,16 +90,14 @@
|
|
90
90
|
* From client: the client is interactive. \
|
91
91
|
*/ \
|
92
92
|
XX(TRILOGY_CAPABILITIES_INTERACTIVE, 0x00000400) \
|
93
|
-
/*
|
94
|
-
* \
|
95
|
-
* From server: the server supports ssl. \
|
93
|
+
/* From server: the server supports ssl. \
|
96
94
|
* \
|
97
95
|
* From client: tells the server it should switch to an ssl connection. \
|
98
96
|
*/ \
|
99
97
|
XX(TRILOGY_CAPABILITIES_SSL, 0x00000800) \
|
100
|
-
/*
|
98
|
+
/* From server: the server supports transactions and is capable of reporting transaction status. \
|
101
99
|
* \
|
102
|
-
*
|
100
|
+
* From client: the client is aware of servers that support transactions. \
|
103
101
|
*/ \
|
104
102
|
XX(TRILOGY_CAPABILITIES_TRANSACTIONS, 0x00002000) \
|
105
103
|
/* Not used. \
|
@@ -112,9 +110,7 @@
|
|
112
110
|
* scheme. This will always be set. \
|
113
111
|
*/ \
|
114
112
|
XX(TRILOGY_CAPABILITIES_SECURE_CONNECTION, 0x00008000) \
|
115
|
-
/*
|
116
|
-
* \
|
117
|
-
* From server: the server can handle multiple statements per \
|
113
|
+
/* From server: the server can handle multiple statements per \
|
118
114
|
* query/prepared statement. \
|
119
115
|
* \
|
120
116
|
* From client: tells the server it may send multiple statements per \
|
@@ -191,7 +187,8 @@ typedef enum {
|
|
191
187
|
/* A convenience bitmask with common client capabilities set. */
|
192
188
|
TRILOGY_CAPABILITIES_CLIENT = (TRILOGY_CAPABILITIES_PROTOCOL_41 | TRILOGY_CAPABILITIES_SECURE_CONNECTION |
|
193
189
|
TRILOGY_CAPABILITIES_DEPRECATE_EOF | TRILOGY_CAPABILITIES_SESSION_TRACK |
|
194
|
-
TRILOGY_CAPABILITIES_PLUGIN_AUTH | TRILOGY_CAPABILITIES_TRANSACTIONS
|
190
|
+
TRILOGY_CAPABILITIES_PLUGIN_AUTH | TRILOGY_CAPABILITIES_TRANSACTIONS |
|
191
|
+
TRILOGY_CAPABILITIES_MULTI_RESULTS)
|
195
192
|
} TRILOGY_CAPABILITIES_t;
|
196
193
|
|
197
194
|
#define TRILOGY_SERVER_STATUS(XX) \
|
@@ -397,22 +394,34 @@ typedef enum {
|
|
397
394
|
#undef XX
|
398
395
|
} TRILOGY_SESSION_TRACK_TYPE_t;
|
399
396
|
|
397
|
+
#define TRILOGY_SET_SERVER_OPTION(XX) \
|
398
|
+
XX(TRILOGY_SET_SERVER_MULTI_STATEMENTS_ON, 0x00) \
|
399
|
+
XX(TRILOGY_SET_SERVER_MULTI_STATEMENTS_OFF, 0x01) \
|
400
|
+
|
401
|
+
typedef enum {
|
402
|
+
#define XX(name, code) name = code,
|
403
|
+
TRILOGY_SET_SERVER_OPTION(XX)
|
404
|
+
#undef XX
|
405
|
+
} TRILOGY_SET_SERVER_OPTION_TYPE_t;
|
406
|
+
|
400
407
|
/* trilogy_build_auth_packet - Build a handshake response (or authentication)
|
401
408
|
* packet.
|
402
409
|
*
|
403
410
|
* This should be sent in response to the initial handshake packet the server
|
404
411
|
* sends upon connection.
|
405
412
|
*
|
406
|
-
* builder
|
407
|
-
* user
|
408
|
-
* pass
|
409
|
-
* pass_len
|
410
|
-
*
|
411
|
-
*
|
412
|
-
*
|
413
|
-
*
|
414
|
-
*
|
415
|
-
*
|
413
|
+
* builder - A pointer to a pre-initialized trilogy_builder_t.
|
414
|
+
* user - The username to use for authentication. Must be a C-string.
|
415
|
+
* pass - The password to use for authentication. Optional, and can be NULL.
|
416
|
+
* pass_len - The length of password in bytes.
|
417
|
+
* database - The initial database to connect to. Optional, and can be NULL.
|
418
|
+
* client_encoding - The charset to use for the connection.
|
419
|
+
* auth_plugin - Plugin authentication mechanism that the server requested.
|
420
|
+
* scramble - The scramble value the server sent in the initial handshake.
|
421
|
+
* flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
|
422
|
+
* The TRILOGY_CAPABILITIES_PROTOCOL_41 and
|
423
|
+
* TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
|
424
|
+
* internally.
|
416
425
|
*
|
417
426
|
* Return values:
|
418
427
|
* TRILOGY_OK - The packet was successfully built and written to the
|
@@ -420,8 +429,8 @@ typedef enum {
|
|
420
429
|
* TRILOGY_SYSERR - A system error occurred, check errno.
|
421
430
|
*/
|
422
431
|
int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
|
423
|
-
const char *database,
|
424
|
-
TRILOGY_CAPABILITIES_t flags);
|
432
|
+
const char *database, TRILOGY_CHARSET_t client_encoding, const char *auth_plugin,
|
433
|
+
const char *scramble, TRILOGY_CAPABILITIES_t flags);
|
425
434
|
|
426
435
|
/* trilogy_build_auth_switch_response_packet - Build a response for when
|
427
436
|
* authentication switching it requested.
|
@@ -447,7 +456,7 @@ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const
|
|
447
456
|
* command will change the default database for the connection.
|
448
457
|
*
|
449
458
|
* builder - A pointer to a pre-initialized trilogy_builder_t.
|
450
|
-
* name - The name of the
|
459
|
+
* name - The name of the database to set as the default.
|
451
460
|
* name_len - The length of name in bytes.
|
452
461
|
*
|
453
462
|
* Return values:
|
@@ -457,6 +466,20 @@ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const
|
|
457
466
|
*/
|
458
467
|
int trilogy_build_change_db_packet(trilogy_builder_t *builder, const char *name, size_t name_len);
|
459
468
|
|
469
|
+
/* trilogy_build_set_option_packet - Build a set option command packet. This
|
470
|
+
* command will enable/disable server capabilities for the connection. Options
|
471
|
+
* must be one of `enum_mysql_set_option`.
|
472
|
+
*
|
473
|
+
* builder - A pointer to a pre-initialized trilogy_builder_t.
|
474
|
+
* option - An integer corresponding to the operation to perform.
|
475
|
+
*
|
476
|
+
* Return values:
|
477
|
+
* TRILOGY_OK - The packet was successfully built and written to the
|
478
|
+
* builder's internal buffer.
|
479
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
480
|
+
*/
|
481
|
+
int trilogy_build_set_option_packet(trilogy_builder_t *builder, const uint16_t option);
|
482
|
+
|
460
483
|
/* trilogy_build_ping_packet - Build a ping command packet.
|
461
484
|
*
|
462
485
|
* builder - A pointer to a pre-initialized trilogy_builder_t.
|
@@ -497,19 +520,21 @@ int trilogy_build_quit_packet(trilogy_builder_t *builder);
|
|
497
520
|
* sends upon connection, where an auth packet would normally be sent. A regular
|
498
521
|
* auth packet is to be sent after the SSL handshake completes.
|
499
522
|
*
|
500
|
-
* builder
|
501
|
-
* flags
|
502
|
-
*
|
503
|
-
*
|
504
|
-
*
|
505
|
-
*
|
523
|
+
* builder - A pointer to a pre-initialized trilogy_builder_t.
|
524
|
+
* flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
|
525
|
+
* The TRILOGY_CAPABILITIES_PROTOCOL_41 and
|
526
|
+
* TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
|
527
|
+
* internally.
|
528
|
+
* The TRILOGY_CAPABILITIES_SSL flag will also be set.
|
529
|
+
* client_encoding - The charset to use for the connection.
|
506
530
|
*
|
507
531
|
* Return values:
|
508
532
|
* TRILOGY_OK - The packet was successfully built and written to the
|
509
533
|
* builder's internal buffer.
|
510
534
|
* TRILOGY_SYSERR - A system error occurred, check errno.
|
511
535
|
*/
|
512
|
-
int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags
|
536
|
+
int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags,
|
537
|
+
TRILOGY_CHARSET_t client_encoding);
|
513
538
|
|
514
539
|
#define TRILOGY_SERVER_VERSION_SIZE 32
|
515
540
|
|
@@ -41,6 +41,7 @@ typedef struct {
|
|
41
41
|
char *username;
|
42
42
|
char *password;
|
43
43
|
size_t password_len;
|
44
|
+
uint8_t encoding;
|
44
45
|
|
45
46
|
trilogy_ssl_mode_t ssl_mode;
|
46
47
|
trilogy_tls_version_t tls_min_version;
|
@@ -107,5 +108,6 @@ static inline int trilogy_sock_fd(trilogy_sock_t *sock) { return sock->fd_cb(soc
|
|
107
108
|
trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts);
|
108
109
|
int trilogy_sock_resolve(trilogy_sock_t *raw);
|
109
110
|
int trilogy_sock_upgrade_ssl(trilogy_sock_t *raw);
|
111
|
+
int trilogy_sock_discard(trilogy_sock_t *sock);
|
110
112
|
|
111
113
|
#endif
|
@@ -139,6 +139,29 @@ int trilogy_change_db(trilogy_conn_t *conn, const char *name, size_t name_len)
|
|
139
139
|
}
|
140
140
|
}
|
141
141
|
|
142
|
+
int trilogy_set_option(trilogy_conn_t *conn, const uint16_t option)
|
143
|
+
{
|
144
|
+
int rc = trilogy_set_option_send(conn, option);
|
145
|
+
|
146
|
+
if (rc == TRILOGY_AGAIN) {
|
147
|
+
rc = flush_full(conn);
|
148
|
+
}
|
149
|
+
|
150
|
+
if (rc < 0) {
|
151
|
+
return rc;
|
152
|
+
}
|
153
|
+
|
154
|
+
while (1) {
|
155
|
+
rc = trilogy_set_option_recv(conn);
|
156
|
+
|
157
|
+
if (rc != TRILOGY_AGAIN) {
|
158
|
+
return rc;
|
159
|
+
}
|
160
|
+
|
161
|
+
CHECKED(trilogy_sock_wait_read(conn->socket));
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
142
165
|
int trilogy_ping(trilogy_conn_t *conn)
|
143
166
|
{
|
144
167
|
int rc = trilogy_ping_send(conn);
|
@@ -357,8 +357,9 @@ int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake
|
|
357
357
|
}
|
358
358
|
|
359
359
|
rc = trilogy_build_auth_packet(&builder, conn->socket->opts.username, conn->socket->opts.password,
|
360
|
-
conn->socket->opts.password_len, conn->socket->opts.database,
|
361
|
-
|
360
|
+
conn->socket->opts.password_len, conn->socket->opts.database,
|
361
|
+
conn->socket->opts.encoding, handshake->auth_plugin, handshake->scramble,
|
362
|
+
conn->socket->opts.flags);
|
362
363
|
|
363
364
|
if (rc < 0) {
|
364
365
|
return rc;
|
@@ -378,7 +379,7 @@ int trilogy_ssl_request_send(trilogy_conn_t *conn)
|
|
378
379
|
}
|
379
380
|
|
380
381
|
conn->socket->opts.flags |= TRILOGY_CAPABILITIES_SSL;
|
381
|
-
rc = trilogy_build_ssl_request_packet(&builder, conn->socket->opts.flags);
|
382
|
+
rc = trilogy_build_ssl_request_packet(&builder, conn->socket->opts.flags, conn->socket->opts.encoding);
|
382
383
|
|
383
384
|
if (rc < 0) {
|
384
385
|
return rc;
|
@@ -466,6 +467,44 @@ int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_l
|
|
466
467
|
|
467
468
|
int trilogy_change_db_recv(trilogy_conn_t *conn) { return read_generic_response(conn); }
|
468
469
|
|
470
|
+
int trilogy_set_option_send(trilogy_conn_t *conn, const uint16_t option)
|
471
|
+
{
|
472
|
+
trilogy_builder_t builder;
|
473
|
+
int err = begin_command_phase(&builder, conn, 0);
|
474
|
+
if (err < 0) {
|
475
|
+
return err;
|
476
|
+
}
|
477
|
+
|
478
|
+
err = trilogy_build_set_option_packet(&builder, option);
|
479
|
+
|
480
|
+
if (err < 0) {
|
481
|
+
return err;
|
482
|
+
}
|
483
|
+
|
484
|
+
return begin_write(conn);
|
485
|
+
}
|
486
|
+
|
487
|
+
int trilogy_set_option_recv(trilogy_conn_t *conn) {
|
488
|
+
int rc = read_packet(conn);
|
489
|
+
|
490
|
+
if (rc < 0) {
|
491
|
+
return rc;
|
492
|
+
}
|
493
|
+
|
494
|
+
switch (current_packet_type(conn)) {
|
495
|
+
case TRILOGY_PACKET_OK:
|
496
|
+
case TRILOGY_PACKET_EOF: // COM_SET_OPTION returns an EOF packet, but it should be treated as an OK packet.
|
497
|
+
return read_ok_packet(conn);
|
498
|
+
|
499
|
+
case TRILOGY_PACKET_ERR:
|
500
|
+
return read_err_packet(conn);
|
501
|
+
|
502
|
+
default:
|
503
|
+
return TRILOGY_UNEXPECTED_PACKET;
|
504
|
+
}
|
505
|
+
}
|
506
|
+
|
507
|
+
|
469
508
|
int trilogy_ping_send(trilogy_conn_t *conn)
|
470
509
|
{
|
471
510
|
trilogy_builder_t builder;
|
@@ -725,4 +764,13 @@ void trilogy_free(trilogy_conn_t *conn)
|
|
725
764
|
trilogy_buffer_free(&conn->packet_buffer);
|
726
765
|
}
|
727
766
|
|
767
|
+
int trilogy_discard(trilogy_conn_t *conn)
|
768
|
+
{
|
769
|
+
int rc = trilogy_sock_discard(conn->socket);
|
770
|
+
if (rc == TRILOGY_OK) {
|
771
|
+
trilogy_free(conn);
|
772
|
+
}
|
773
|
+
return rc;
|
774
|
+
}
|
775
|
+
|
728
776
|
#undef CHECKED
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#define TRILOGY_CMD_CHANGE_DB 0x02
|
11
11
|
#define TRILOGY_CMD_QUERY 0x03
|
12
12
|
#define TRILOGY_CMD_PING 0x0e
|
13
|
+
#define TRILOGY_CMD_SET_OPTION 0x1b
|
13
14
|
|
14
15
|
#define SCRAMBLE_LEN 20
|
15
16
|
|
@@ -493,8 +494,8 @@ static void trilogy_pack_scramble_sha2_hash(const char *scramble, const char *pa
|
|
493
494
|
}
|
494
495
|
|
495
496
|
int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
|
496
|
-
const char *database,
|
497
|
-
TRILOGY_CAPABILITIES_t flags)
|
497
|
+
const char *database, TRILOGY_CHARSET_t client_encoding, const char *auth_plugin,
|
498
|
+
const char *scramble, TRILOGY_CAPABILITIES_t flags)
|
498
499
|
{
|
499
500
|
int rc = TRILOGY_OK;
|
500
501
|
|
@@ -506,8 +507,6 @@ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, cons
|
|
506
507
|
|
507
508
|
uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
|
508
509
|
|
509
|
-
uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
|
510
|
-
|
511
510
|
unsigned int auth_response_len = 0;
|
512
511
|
uint8_t auth_response[EVP_MAX_MD_SIZE];
|
513
512
|
|
@@ -646,12 +645,28 @@ fail:
|
|
646
645
|
return rc;
|
647
646
|
}
|
648
647
|
|
649
|
-
int
|
648
|
+
int trilogy_build_set_option_packet(trilogy_builder_t *builder, const uint16_t option)
|
649
|
+
{
|
650
|
+
int rc = TRILOGY_OK;
|
651
|
+
|
652
|
+
CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_SET_OPTION));
|
653
|
+
CHECKED(trilogy_builder_write_uint16(builder, option));
|
654
|
+
|
655
|
+
trilogy_builder_finalize(builder);
|
656
|
+
|
657
|
+
return TRILOGY_OK;
|
658
|
+
|
659
|
+
fail:
|
660
|
+
return rc;
|
661
|
+
}
|
662
|
+
|
663
|
+
|
664
|
+
int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags,
|
665
|
+
TRILOGY_CHARSET_t client_encoding)
|
650
666
|
{
|
651
667
|
static const char zeroes[23] = {0};
|
652
668
|
|
653
669
|
const uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
|
654
|
-
const uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
|
655
670
|
const uint32_t capabilities = flags | TRILOGY_CAPABILITIES_CLIENT | TRILOGY_CAPABILITIES_SSL;
|
656
671
|
|
657
672
|
int rc = TRILOGY_OK;
|
@@ -621,3 +621,28 @@ fail:
|
|
621
621
|
sock->ssl = NULL;
|
622
622
|
return TRILOGY_OPENSSL_ERR;
|
623
623
|
}
|
624
|
+
|
625
|
+
int trilogy_sock_discard(trilogy_sock_t *_sock)
|
626
|
+
{
|
627
|
+
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
628
|
+
|
629
|
+
if (sock->fd < 0) {
|
630
|
+
return TRILOGY_OK;
|
631
|
+
}
|
632
|
+
|
633
|
+
int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
|
634
|
+
if (null_fd < 0) {
|
635
|
+
return TRILOGY_SYSERR;
|
636
|
+
}
|
637
|
+
|
638
|
+
if (dup2(null_fd, sock->fd) < 0) {
|
639
|
+
close(null_fd);
|
640
|
+
return TRILOGY_SYSERR;
|
641
|
+
}
|
642
|
+
|
643
|
+
if (close(null_fd) < 0) {
|
644
|
+
return TRILOGY_SYSERR;
|
645
|
+
}
|
646
|
+
|
647
|
+
return TRILOGY_OK;
|
648
|
+
}
|
@@ -9,6 +9,7 @@
|
|
9
9
|
#define TRILOGY_FLAGS_CAST_BOOLEANS 2
|
10
10
|
#define TRILOGY_FLAGS_LOCAL_TIMEZONE 4
|
11
11
|
#define TRILOGY_FLAGS_FLATTEN_ROWS 8
|
12
|
+
#define TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS 16
|
12
13
|
#define TRILOGY_FLAGS_DEFAULT (TRILOGY_FLAGS_CAST)
|
13
14
|
|
14
15
|
struct rb_trilogy_cast_options {
|
@@ -16,6 +17,7 @@ struct rb_trilogy_cast_options {
|
|
16
17
|
bool cast_booleans;
|
17
18
|
bool database_local_time;
|
18
19
|
bool flatten_rows;
|
20
|
+
bool cast_decimals_to_bigdecimals;
|
19
21
|
};
|
20
22
|
|
21
23
|
struct column_info {
|
data/lib/trilogy/version.rb
CHANGED
data/lib/trilogy.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "trilogy/version"
|
2
4
|
|
3
5
|
class Trilogy
|
4
6
|
# Trilogy::Error is the base error type. All errors raised by Trilogy
|
5
7
|
# should be descendants of Trilogy::Error
|
6
8
|
module Error
|
9
|
+
attr_reader :error_code
|
7
10
|
end
|
8
11
|
|
9
12
|
# Trilogy::ConnectionError is the base error type for all potentially transient
|
@@ -12,11 +15,30 @@ class Trilogy
|
|
12
15
|
include Error
|
13
16
|
end
|
14
17
|
|
18
|
+
# Trilogy may raise various syscall errors, which we treat as Trilogy::Errors.
|
19
|
+
class SyscallError
|
20
|
+
ERRORS = {}
|
21
|
+
|
22
|
+
Errno.constants
|
23
|
+
.map { |c| Errno.const_get(c) }.uniq
|
24
|
+
.select { |c| c.is_a?(Class) && c < SystemCallError }
|
25
|
+
.each do |c|
|
26
|
+
errno_name = c.to_s.split('::').last
|
27
|
+
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::Error })
|
28
|
+
end
|
29
|
+
|
30
|
+
ERRORS.freeze
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def from_errno(errno, message)
|
34
|
+
ERRORS[errno].new(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
15
39
|
class BaseError < StandardError
|
16
40
|
include Error
|
17
41
|
|
18
|
-
attr_reader :error_code
|
19
|
-
|
20
42
|
def initialize(error_message = nil, error_code = nil)
|
21
43
|
message = error_code ? "#{error_code}: #{error_message}" : error_message
|
22
44
|
super(message)
|
@@ -43,14 +65,20 @@ class Trilogy
|
|
43
65
|
class TimeoutError < Errno::ETIMEDOUT
|
44
66
|
include ConnectionError
|
45
67
|
|
46
|
-
attr_reader :error_code
|
47
|
-
|
48
68
|
def initialize(error_message = nil, error_code = nil)
|
49
69
|
super
|
50
70
|
@error_code = error_code
|
51
71
|
end
|
52
72
|
end
|
53
73
|
|
74
|
+
class ConnectionRefusedError < Errno::ECONNREFUSED
|
75
|
+
include ConnectionError
|
76
|
+
end
|
77
|
+
|
78
|
+
class ConnectionResetError < Errno::ECONNRESET
|
79
|
+
include ConnectionError
|
80
|
+
end
|
81
|
+
|
54
82
|
# DatabaseError was replaced by ProtocolError, but we'll keep it around as an
|
55
83
|
# ancestor of ProtocolError for compatibility reasons (e.g. so `rescue DatabaseError`
|
56
84
|
# still works. We can remove this class in the next major release.
|
@@ -92,6 +120,60 @@ class Trilogy
|
|
92
120
|
include ConnectionError
|
93
121
|
end
|
94
122
|
|
123
|
+
MYSQL_TO_RUBY_ENCODINGS_MAP = {
|
124
|
+
"big5" => "Big5",
|
125
|
+
"dec8" => nil,
|
126
|
+
"cp850" => "CP850",
|
127
|
+
"hp8" => nil,
|
128
|
+
"koi8r" => "KOI8-R",
|
129
|
+
"latin1" => "ISO-8859-1",
|
130
|
+
"latin2" => "ISO-8859-2",
|
131
|
+
"swe7" => nil,
|
132
|
+
"ascii" => "US-ASCII",
|
133
|
+
"ujis" => "eucJP-ms",
|
134
|
+
"sjis" => "Shift_JIS",
|
135
|
+
"hebrew" => "ISO-8859-8",
|
136
|
+
"tis620" => "TIS-620",
|
137
|
+
"euckr" => "EUC-KR",
|
138
|
+
"koi8u" => "KOI8-R",
|
139
|
+
"gb2312" => "GB2312",
|
140
|
+
"greek" => "ISO-8859-7",
|
141
|
+
"cp1250" => "Windows-1250",
|
142
|
+
"gbk" => "GBK",
|
143
|
+
"latin5" => "ISO-8859-9",
|
144
|
+
"armscii8" => nil,
|
145
|
+
"utf8" => "UTF-8",
|
146
|
+
"ucs2" => "UTF-16BE",
|
147
|
+
"cp866" => "IBM866",
|
148
|
+
"keybcs2" => nil,
|
149
|
+
"macce" => "macCentEuro",
|
150
|
+
"macroman" => "macRoman",
|
151
|
+
"cp852" => "CP852",
|
152
|
+
"latin7" => "ISO-8859-13",
|
153
|
+
"utf8mb4" => "UTF-8",
|
154
|
+
"cp1251" => "Windows-1251",
|
155
|
+
"utf16" => "UTF-16",
|
156
|
+
"cp1256" => "Windows-1256",
|
157
|
+
"cp1257" => "Windows-1257",
|
158
|
+
"utf32" => "UTF-32",
|
159
|
+
"binary" => "ASCII-8BIT",
|
160
|
+
"geostd8" => nil,
|
161
|
+
"cp932" => "Windows-31J",
|
162
|
+
"eucjpms" => "eucJP-ms",
|
163
|
+
"utf16le" => "UTF-16LE",
|
164
|
+
"gb18030" => "GB18030",
|
165
|
+
}.freeze
|
166
|
+
|
167
|
+
def initialize(options = {})
|
168
|
+
mysql_encoding = options[:encoding] || "utf8mb4"
|
169
|
+
unless rb_encoding = MYSQL_TO_RUBY_ENCODINGS_MAP[mysql_encoding]
|
170
|
+
raise ArgumentError, "Unknown or unsupported encoding: #{mysql_encoding}"
|
171
|
+
end
|
172
|
+
encoding = Encoding.find(rb_encoding)
|
173
|
+
charset = charset_for_mysql_encoding(mysql_encoding)
|
174
|
+
_initialize(encoding, charset, **options)
|
175
|
+
end
|
176
|
+
|
95
177
|
def connection_options
|
96
178
|
@connection_options.dup.freeze
|
97
179
|
end
|
@@ -124,7 +206,7 @@ class Trilogy
|
|
124
206
|
end
|
125
207
|
|
126
208
|
class Result
|
127
|
-
attr_reader :fields, :rows, :query_time
|
209
|
+
attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
|
128
210
|
|
129
211
|
def count
|
130
212
|
rows.count
|
@@ -154,6 +236,49 @@ class Trilogy
|
|
154
236
|
|
155
237
|
include Enumerable
|
156
238
|
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def charset_for_mysql_encoding(mysql_encoding)
|
243
|
+
@mysql_encodings_map ||= {
|
244
|
+
"big5" => CHARSET_BIG5_CHINESE_CI,
|
245
|
+
"cp850" => CHARSET_CP850_GENERAL_CI,
|
246
|
+
"koi8r" => CHARSET_KOI8R_GENERAL_CI,
|
247
|
+
"latin1" => CHARSET_LATIN1_GENERAL_CI,
|
248
|
+
"latin2" => CHARSET_LATIN2_GENERAL_CI,
|
249
|
+
"ascii" => CHARSET_ASCII_GENERAL_CI,
|
250
|
+
"ujis" => CHARSET_UJIS_JAPANESE_CI,
|
251
|
+
"sjis" => CHARSET_SJIS_JAPANESE_CI,
|
252
|
+
"hebrew" => CHARSET_HEBREW_GENERAL_CI,
|
253
|
+
"tis620" => CHARSET_TIS620_THAI_CI,
|
254
|
+
"euckr" => CHARSET_EUCKR_KOREAN_CI,
|
255
|
+
"koi8u" => CHARSET_KOI8U_GENERAL_CI,
|
256
|
+
"gb2312" => CHARSET_GB2312_CHINESE_CI,
|
257
|
+
"greek" => CHARSET_GREEK_GENERAL_CI,
|
258
|
+
"cp1250" => CHARSET_CP1250_GENERAL_CI,
|
259
|
+
"gbk" => CHARSET_GBK_CHINESE_CI,
|
260
|
+
"latin5" => CHARSET_LATIN5_TURKISH_CI,
|
261
|
+
"utf8" => CHARSET_UTF8_GENERAL_CI,
|
262
|
+
"ucs2" => CHARSET_UCS2_GENERAL_CI,
|
263
|
+
"cp866" => CHARSET_CP866_GENERAL_CI,
|
264
|
+
"cp932" => CHARSET_CP932_JAPANESE_CI,
|
265
|
+
"eucjpms" => CHARSET_EUCJPMS_JAPANESE_CI,
|
266
|
+
"utf16le" => CHARSET_UTF16_GENERAL_CI,
|
267
|
+
"gb18030" => CHARSET_GB18030_CHINESE_CI,
|
268
|
+
"macce" => CHARSET_MACCE_GENERAL_CI,
|
269
|
+
"macroman" => CHARSET_MACROMAN_GENERAL_CI,
|
270
|
+
"cp852" => CHARSET_CP852_GENERAL_CI,
|
271
|
+
"latin7" => CHARSET_LATIN7_GENERAL_CI,
|
272
|
+
"utf8mb4" => CHARSET_UTF8MB4_GENERAL_CI,
|
273
|
+
"cp1251" => CHARSET_CP1251_GENERAL_CI,
|
274
|
+
"utf16" => CHARSET_UTF16_GENERAL_CI,
|
275
|
+
"cp1256" => CHARSET_CP1256_GENERAL_CI,
|
276
|
+
"cp1257" => CHARSET_CP1257_GENERAL_CI,
|
277
|
+
"utf32" => CHARSET_UTF32_GENERAL_CI,
|
278
|
+
"binary" => CHARSET_BINARY,
|
279
|
+
}.freeze
|
280
|
+
@mysql_encodings_map[mysql_encoding]
|
281
|
+
end
|
157
282
|
end
|
158
283
|
|
159
284
|
require "trilogy/cext"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trilogy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|