trilogy 2.8.1 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/ext/trilogy-ruby/cext.c +200 -3
- data/ext/trilogy-ruby/extconf.rb +2 -2
- data/ext/trilogy-ruby/inc/trilogy/buffer.h +13 -0
- data/ext/trilogy-ruby/inc/trilogy/client.h +9 -0
- data/ext/trilogy-ruby/inc/trilogy/error.h +2 -1
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +1 -0
- data/ext/trilogy-ruby/src/buffer.c +22 -3
- data/ext/trilogy-ruby/src/builder.c +1 -1
- data/ext/trilogy-ruby/src/client.c +59 -39
- data/ext/trilogy-ruby/src/protocol.c +3 -0
- data/lib/trilogy/encoding.rb +2 -0
- data/lib/trilogy/result.rb +2 -0
- data/lib/trilogy/version.rb +1 -1
- data/trilogy.gemspec +4 -0
- metadata +18 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e84050730e47a4bd826b9c15b226d0f825a46df8849c3c4a89c01011e27fb6c
|
|
4
|
+
data.tar.gz: eddfedb0481b09220bb95f1de423b473aa78f2ad8058de692b85c52bba1c0480
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a1fa8ecb46aa1b1595c6d6f1a20b5dd4267452d5c59b0571fe31c4cc854907aeb8f8ad1496099e53ba83b29c0594f88dc6f4f45586ede8b1ad53d70b0ff2a774
|
|
7
|
+
data.tar.gz: a18b393f8b035c8ee3315d42b23d8a46e1597f4ccbac0347acab0161a8c041572eeb8a13d4d323c97a63040f9f18baa04e0742c73e65df33d5763fdd27b6c581
|
data/README.md
CHANGED
data/ext/trilogy-ruby/cext.c
CHANGED
|
@@ -15,6 +15,149 @@
|
|
|
15
15
|
|
|
16
16
|
#include "trilogy-ruby.h"
|
|
17
17
|
|
|
18
|
+
typedef struct _buffer_pool_entry_struct {
|
|
19
|
+
size_t cap;
|
|
20
|
+
uint8_t *buff;
|
|
21
|
+
} buffer_pool_entry;
|
|
22
|
+
|
|
23
|
+
typedef struct _buffer_pool_struct {
|
|
24
|
+
size_t capa;
|
|
25
|
+
size_t len;
|
|
26
|
+
buffer_pool_entry *entries;
|
|
27
|
+
} buffer_pool;
|
|
28
|
+
|
|
29
|
+
#ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
30
|
+
static VALUE _global_buffer_pool = Qnil;
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#define BUFFER_POOL_MAX_SIZE 8
|
|
34
|
+
|
|
35
|
+
static void buffer_pool_free(void *data)
|
|
36
|
+
{
|
|
37
|
+
#ifndef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
38
|
+
_global_buffer_pool = Qnil;
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
buffer_pool *pool = (buffer_pool *)data;
|
|
42
|
+
if (pool->capa) {
|
|
43
|
+
for (size_t index = 0; index < pool->len; index++) {
|
|
44
|
+
// NB: buff was allocated by trilogy/buffer.h using raw `malloc`
|
|
45
|
+
// hence we must use raw `free`.
|
|
46
|
+
free(pool->entries[index].buff);
|
|
47
|
+
}
|
|
48
|
+
xfree(pool->entries);
|
|
49
|
+
}
|
|
50
|
+
xfree(pool);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static size_t buffer_pool_memsize(const void *data)
|
|
54
|
+
{
|
|
55
|
+
const buffer_pool *pool = (const buffer_pool *)data;
|
|
56
|
+
|
|
57
|
+
size_t memsize = sizeof(buffer_pool) + sizeof(buffer_pool_entry) * pool->capa;
|
|
58
|
+
|
|
59
|
+
if (pool->capa) {
|
|
60
|
+
for (size_t index = 0; index < pool->len; index++) {
|
|
61
|
+
memsize += pool->entries[index].cap;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return memsize;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static const rb_data_type_t buffer_pool_type = {
|
|
69
|
+
.wrap_struct_name = "trilogy/buffer_pool",
|
|
70
|
+
.function = {
|
|
71
|
+
.dmark = NULL,
|
|
72
|
+
.dfree = buffer_pool_free,
|
|
73
|
+
.dsize = buffer_pool_memsize,
|
|
74
|
+
},
|
|
75
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
static VALUE create_rb_buffer_pool(void)
|
|
79
|
+
{
|
|
80
|
+
buffer_pool *pool;
|
|
81
|
+
return TypedData_Make_Struct(Qfalse, buffer_pool, &buffer_pool_type, pool);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
85
|
+
#include <ruby/ractor.h>
|
|
86
|
+
static rb_ractor_local_key_t buffer_pool_key;
|
|
87
|
+
|
|
88
|
+
static VALUE get_rb_buffer_pool(void)
|
|
89
|
+
{
|
|
90
|
+
VALUE pool;
|
|
91
|
+
if (!rb_ractor_local_storage_value_lookup(buffer_pool_key, &pool)) {
|
|
92
|
+
pool = create_rb_buffer_pool();
|
|
93
|
+
rb_ractor_local_storage_value_set(buffer_pool_key, pool);
|
|
94
|
+
}
|
|
95
|
+
return pool;
|
|
96
|
+
}
|
|
97
|
+
#else
|
|
98
|
+
static VALUE get_rb_buffer_pool(void)
|
|
99
|
+
{
|
|
100
|
+
if (NIL_P(_global_buffer_pool)) {
|
|
101
|
+
_global_buffer_pool = create_rb_buffer_pool();
|
|
102
|
+
}
|
|
103
|
+
return _global_buffer_pool;
|
|
104
|
+
}
|
|
105
|
+
#endif
|
|
106
|
+
|
|
107
|
+
static inline buffer_pool *get_buffer_pool(void)
|
|
108
|
+
{
|
|
109
|
+
buffer_pool *pool;
|
|
110
|
+
VALUE rb_pool = get_rb_buffer_pool();
|
|
111
|
+
if (NIL_P(rb_pool)) {
|
|
112
|
+
return NULL;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
TypedData_Get_Struct(rb_pool, buffer_pool, &buffer_pool_type, pool);
|
|
116
|
+
return pool;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void buffer_checkout(trilogy_buffer_t *buffer, size_t initial_capacity)
|
|
120
|
+
{
|
|
121
|
+
buffer_pool * pool = get_buffer_pool();
|
|
122
|
+
if (pool->len) {
|
|
123
|
+
pool->len--;
|
|
124
|
+
buffer->buff = pool->entries[pool->len].buff;
|
|
125
|
+
buffer->cap = pool->entries[pool->len].cap;
|
|
126
|
+
} else {
|
|
127
|
+
buffer->buff = RB_ALLOC_N(uint8_t, initial_capacity);
|
|
128
|
+
buffer->cap = initial_capacity;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static bool buffer_checkin(trilogy_buffer_t *buffer)
|
|
133
|
+
{
|
|
134
|
+
buffer_pool * pool = get_buffer_pool();
|
|
135
|
+
|
|
136
|
+
if (pool->len >= BUFFER_POOL_MAX_SIZE) {
|
|
137
|
+
xfree(buffer->buff);
|
|
138
|
+
buffer->buff = NULL;
|
|
139
|
+
buffer->cap = 0;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!pool->capa) {
|
|
144
|
+
pool->entries = RB_ALLOC_N(buffer_pool_entry, 16);
|
|
145
|
+
pool->capa = 16;
|
|
146
|
+
} else if (pool->len >= pool->capa) {
|
|
147
|
+
pool->capa *= 2;
|
|
148
|
+
RB_REALLOC_N(pool->entries, buffer_pool_entry, pool->capa);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
pool->entries[pool->len].buff = buffer->buff;
|
|
152
|
+
pool->entries[pool->len].cap = buffer->cap;
|
|
153
|
+
pool->len++;
|
|
154
|
+
|
|
155
|
+
buffer->buff = NULL;
|
|
156
|
+
buffer->cap = 0;
|
|
157
|
+
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
18
161
|
VALUE Trilogy_CastError;
|
|
19
162
|
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
|
20
163
|
Trilogy_ConnectionClosedError,
|
|
@@ -34,6 +177,20 @@ struct trilogy_ctx {
|
|
|
34
177
|
VALUE encoding;
|
|
35
178
|
};
|
|
36
179
|
|
|
180
|
+
static void rb_trilogy_acquire_buffer(struct trilogy_ctx *ctx)
|
|
181
|
+
{
|
|
182
|
+
if (!ctx->conn.packet_buffer.buff) {
|
|
183
|
+
buffer_checkout(&ctx->conn.packet_buffer, TRILOGY_DEFAULT_BUF_SIZE);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static void rb_trilogy_release_buffer(struct trilogy_ctx *ctx)
|
|
188
|
+
{
|
|
189
|
+
if (ctx->conn.packet_buffer.buff) {
|
|
190
|
+
buffer_checkin(&ctx->conn.packet_buffer);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
37
194
|
static void mark_trilogy(void *ptr)
|
|
38
195
|
{
|
|
39
196
|
struct trilogy_ctx *ctx = ptr;
|
|
@@ -43,6 +200,7 @@ static void mark_trilogy(void *ptr)
|
|
|
43
200
|
static void free_trilogy(void *ptr)
|
|
44
201
|
{
|
|
45
202
|
struct trilogy_ctx *ctx = ptr;
|
|
203
|
+
|
|
46
204
|
trilogy_free(&ctx->conn);
|
|
47
205
|
xfree(ptr);
|
|
48
206
|
}
|
|
@@ -116,6 +274,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
|
116
274
|
VALUE rbmsg = rb_vsprintf(msg, args);
|
|
117
275
|
va_end(args);
|
|
118
276
|
|
|
277
|
+
rb_trilogy_release_buffer(ctx);
|
|
278
|
+
|
|
119
279
|
if (!trilogy_error_recoverable_p(rc)) {
|
|
120
280
|
if (ctx->conn.socket != NULL) {
|
|
121
281
|
// trilogy_sock_shutdown may affect errno
|
|
@@ -133,7 +293,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
|
133
293
|
rb_raise(Trilogy_TimeoutError, "%" PRIsVALUE, rbmsg);
|
|
134
294
|
|
|
135
295
|
case TRILOGY_ERR: {
|
|
136
|
-
VALUE
|
|
296
|
+
VALUE conn_message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
|
|
297
|
+
VALUE message = rb_sprintf("%" PRIsVALUE " (%" PRIsVALUE ")", conn_message, rbmsg);
|
|
137
298
|
VALUE exc = rb_funcall(Trilogy_ProtocolError, id_from_code, 2, message, INT2NUM(ctx->conn.error_code));
|
|
138
299
|
rb_exc_raise(exc);
|
|
139
300
|
}
|
|
@@ -177,7 +338,7 @@ static VALUE allocate_trilogy(VALUE klass)
|
|
|
177
338
|
|
|
178
339
|
ctx->query_flags = TRILOGY_FLAGS_DEFAULT;
|
|
179
340
|
|
|
180
|
-
if (
|
|
341
|
+
if (trilogy_init_no_buffer(&ctx->conn) < 0) {
|
|
181
342
|
VALUE rbmsg = rb_str_new("trilogy_init", 13);
|
|
182
343
|
trilogy_syserr_fail_str(errno, rbmsg);
|
|
183
344
|
}
|
|
@@ -601,6 +762,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
|
|
|
601
762
|
connopt.tls_max_version = NUM2INT(val);
|
|
602
763
|
}
|
|
603
764
|
|
|
765
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
766
|
+
|
|
604
767
|
int rc = try_connect(ctx, &handshake, &connopt);
|
|
605
768
|
if (rc != TRILOGY_OK) {
|
|
606
769
|
if (connopt.path) {
|
|
@@ -616,6 +779,8 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
|
|
|
616
779
|
|
|
617
780
|
authenticate(ctx, &handshake, connopt.ssl_mode);
|
|
618
781
|
|
|
782
|
+
rb_trilogy_release_buffer(ctx);
|
|
783
|
+
|
|
619
784
|
return Qnil;
|
|
620
785
|
}
|
|
621
786
|
|
|
@@ -625,6 +790,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
|
625
790
|
|
|
626
791
|
StringValue(database);
|
|
627
792
|
|
|
793
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
794
|
+
|
|
628
795
|
int rc = trilogy_change_db_send(&ctx->conn, RSTRING_PTR(database), RSTRING_LEN(database));
|
|
629
796
|
|
|
630
797
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -652,6 +819,8 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
|
|
|
652
819
|
}
|
|
653
820
|
}
|
|
654
821
|
|
|
822
|
+
rb_trilogy_release_buffer(ctx);
|
|
823
|
+
|
|
655
824
|
return Qtrue;
|
|
656
825
|
}
|
|
657
826
|
|
|
@@ -659,6 +828,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
|
|
659
828
|
{
|
|
660
829
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
661
830
|
|
|
831
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
832
|
+
|
|
662
833
|
int rc = trilogy_set_option_send(&ctx->conn, NUM2INT(option));
|
|
663
834
|
|
|
664
835
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -686,6 +857,8 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
|
|
|
686
857
|
}
|
|
687
858
|
}
|
|
688
859
|
|
|
860
|
+
rb_trilogy_release_buffer(ctx);
|
|
861
|
+
|
|
689
862
|
return Qtrue;
|
|
690
863
|
}
|
|
691
864
|
|
|
@@ -891,6 +1064,10 @@ static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
|
|
891
1064
|
handle_trilogy_error(ctx, args.rc, args.msg);
|
|
892
1065
|
}
|
|
893
1066
|
|
|
1067
|
+
if (!(ctx->conn.server_status & TRILOGY_SERVER_STATUS_MORE_RESULTS_EXISTS)) {
|
|
1068
|
+
rb_trilogy_release_buffer(ctx);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
894
1071
|
return result;
|
|
895
1072
|
}
|
|
896
1073
|
|
|
@@ -923,6 +1100,8 @@ static VALUE rb_trilogy_query(VALUE self, VALUE query)
|
|
|
923
1100
|
StringValue(query);
|
|
924
1101
|
query = rb_str_export_to_enc(query, rb_to_encoding(ctx->encoding));
|
|
925
1102
|
|
|
1103
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1104
|
+
|
|
926
1105
|
int rc = trilogy_query_send(&ctx->conn, RSTRING_PTR(query), RSTRING_LEN(query));
|
|
927
1106
|
|
|
928
1107
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -940,6 +1119,8 @@ static VALUE rb_trilogy_ping(VALUE self)
|
|
|
940
1119
|
{
|
|
941
1120
|
struct trilogy_ctx *ctx = get_open_ctx(self);
|
|
942
1121
|
|
|
1122
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1123
|
+
|
|
943
1124
|
int rc = trilogy_ping_send(&ctx->conn);
|
|
944
1125
|
|
|
945
1126
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -967,6 +1148,7 @@ static VALUE rb_trilogy_ping(VALUE self)
|
|
|
967
1148
|
}
|
|
968
1149
|
}
|
|
969
1150
|
|
|
1151
|
+
rb_trilogy_release_buffer(ctx);
|
|
970
1152
|
return Qtrue;
|
|
971
1153
|
}
|
|
972
1154
|
|
|
@@ -984,13 +1166,19 @@ static VALUE rb_trilogy_escape(VALUE self, VALUE str)
|
|
|
984
1166
|
const char *escaped_str;
|
|
985
1167
|
size_t escaped_len;
|
|
986
1168
|
|
|
1169
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1170
|
+
|
|
987
1171
|
int rc = trilogy_escape(&ctx->conn, RSTRING_PTR(str), RSTRING_LEN(str), &escaped_str, &escaped_len);
|
|
988
1172
|
|
|
989
1173
|
if (rc < 0) {
|
|
990
1174
|
handle_trilogy_error(ctx, rc, "trilogy_escape");
|
|
991
1175
|
}
|
|
992
1176
|
|
|
993
|
-
|
|
1177
|
+
VALUE escaped_string = rb_enc_str_new(escaped_str, escaped_len, str_enc);
|
|
1178
|
+
|
|
1179
|
+
rb_trilogy_release_buffer(ctx);
|
|
1180
|
+
|
|
1181
|
+
return escaped_string;
|
|
994
1182
|
}
|
|
995
1183
|
|
|
996
1184
|
static VALUE rb_trilogy_close(VALUE self)
|
|
@@ -1001,6 +1189,8 @@ static VALUE rb_trilogy_close(VALUE self)
|
|
|
1001
1189
|
return Qnil;
|
|
1002
1190
|
}
|
|
1003
1191
|
|
|
1192
|
+
rb_trilogy_acquire_buffer(ctx);
|
|
1193
|
+
|
|
1004
1194
|
int rc = trilogy_close_send(&ctx->conn);
|
|
1005
1195
|
|
|
1006
1196
|
if (rc == TRILOGY_AGAIN) {
|
|
@@ -1026,6 +1216,8 @@ static VALUE rb_trilogy_close(VALUE self)
|
|
|
1026
1216
|
// we must clear any SSL errors left in the queue from a read/write.
|
|
1027
1217
|
ERR_clear_error();
|
|
1028
1218
|
|
|
1219
|
+
rb_trilogy_release_buffer(ctx);
|
|
1220
|
+
|
|
1029
1221
|
trilogy_free(&ctx->conn);
|
|
1030
1222
|
|
|
1031
1223
|
return Qnil;
|
|
@@ -1133,6 +1325,11 @@ static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_
|
|
|
1133
1325
|
|
|
1134
1326
|
RUBY_FUNC_EXPORTED void Init_cext(void)
|
|
1135
1327
|
{
|
|
1328
|
+
#ifdef HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY
|
|
1329
|
+
rb_ext_ractor_safe(true);
|
|
1330
|
+
buffer_pool_key = rb_ractor_local_storage_value_newkey();
|
|
1331
|
+
#endif
|
|
1332
|
+
|
|
1136
1333
|
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
|
1137
1334
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
|
1138
1335
|
|
data/ext/trilogy-ruby/extconf.rb
CHANGED
|
@@ -10,12 +10,12 @@ File.binwrite("trilogy.c",
|
|
|
10
10
|
}.join)
|
|
11
11
|
|
|
12
12
|
$objs = %w[trilogy.o cast.o cext.o]
|
|
13
|
-
|
|
13
|
+
append_cflags(["-I #{__dir__}/inc", "-std=gnu99", "-fvisibility=hidden"])
|
|
14
14
|
|
|
15
15
|
dir_config("openssl")
|
|
16
16
|
|
|
17
17
|
have_library("crypto", "CRYPTO_malloc")
|
|
18
18
|
have_library("ssl", "SSL_new")
|
|
19
19
|
have_func("rb_interned_str", "ruby.h")
|
|
20
|
-
|
|
20
|
+
have_func("rb_ractor_local_storage_value_newkey", "ruby.h")
|
|
21
21
|
create_makefile "trilogy/cext"
|
|
@@ -53,6 +53,19 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed);
|
|
|
53
53
|
*/
|
|
54
54
|
int trilogy_buffer_putc(trilogy_buffer_t *buffer, uint8_t c);
|
|
55
55
|
|
|
56
|
+
/* trilogy_buffer_write - Appends multiple bytes to the buffer, resizing the underlying
|
|
57
|
+
* allocation if necessary.
|
|
58
|
+
*
|
|
59
|
+
* buffer - A pointer to a pre-initialized trilogy_buffer_t.
|
|
60
|
+
* ptr - The pointer to the byte array.
|
|
61
|
+
* len - How many bytes to append.
|
|
62
|
+
*
|
|
63
|
+
* Return values:
|
|
64
|
+
* TRILOGY_OK - The character was appended to the buffer
|
|
65
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
|
66
|
+
*/
|
|
67
|
+
int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t len);
|
|
68
|
+
|
|
56
69
|
/* trilogy_buffer_free - Free an trilogy_buffer_t's underlying storage. The buffer
|
|
57
70
|
* must be re-initialized with trilogy_buffer_init if it is to be reused. Any
|
|
58
71
|
* operations performed on an unintialized or freed buffer are undefined.
|
|
@@ -106,6 +106,15 @@ typedef struct {
|
|
|
106
106
|
*/
|
|
107
107
|
int trilogy_init(trilogy_conn_t *conn);
|
|
108
108
|
|
|
109
|
+
/* trilogy_init_no_buffer - Same as trilogy_init but doesn't allocate the packet buffer
|
|
110
|
+
*
|
|
111
|
+
* conn - A pre-allocated trilogy_conn_t pointer.
|
|
112
|
+
*
|
|
113
|
+
* Return values:
|
|
114
|
+
* TRILOGY_OK - The trilogy_conn_t pointer was properly initialized
|
|
115
|
+
*/
|
|
116
|
+
int trilogy_init_no_buffer(trilogy_conn_t *conn);
|
|
117
|
+
|
|
109
118
|
/* trilogy_flush_writes - Attempt to flush the internal packet buffer to the
|
|
110
119
|
* network. This must be used if a `_send` function returns TRILOGY_AGAIN, and
|
|
111
120
|
* should continue to be called until it returns a value other than
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
XX(TRILOGY_MAX_PACKET_EXCEEDED, -20) \
|
|
26
26
|
XX(TRILOGY_UNKNOWN_TYPE, -21) \
|
|
27
27
|
XX(TRILOGY_TIMEOUT, -22) \
|
|
28
|
-
XX(TRILOGY_AUTH_PLUGIN_ERROR, -23)
|
|
28
|
+
XX(TRILOGY_AUTH_PLUGIN_ERROR, -23) \
|
|
29
|
+
XX(TRILOGY_MEM_ERROR, -24)
|
|
29
30
|
|
|
30
31
|
enum {
|
|
31
32
|
#define XX(name, code) name = code,
|
|
@@ -289,6 +289,7 @@ typedef enum {
|
|
|
289
289
|
XX(TRILOGY_TYPE_YEAR, 0x0d) \
|
|
290
290
|
XX(TRILOGY_TYPE_VARCHAR, 0x0f) \
|
|
291
291
|
XX(TRILOGY_TYPE_BIT, 0x10) \
|
|
292
|
+
XX(TRILOGY_TYPE_VECTOR, 0xf2) \
|
|
292
293
|
XX(TRILOGY_TYPE_JSON, 0xf5) \
|
|
293
294
|
XX(TRILOGY_TYPE_NEWDECIMAL, 0xf6) \
|
|
294
295
|
XX(TRILOGY_TYPE_ENUM, 0xf7) \
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <stdint.h>
|
|
2
2
|
#include <stdlib.h>
|
|
3
|
+
#include <string.h>
|
|
3
4
|
|
|
4
5
|
#include "trilogy/buffer.h"
|
|
5
6
|
#include "trilogy/error.h"
|
|
@@ -23,6 +24,9 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed)
|
|
|
23
24
|
{
|
|
24
25
|
// expand buffer if necessary
|
|
25
26
|
if (buffer->len + needed > buffer->cap) {
|
|
27
|
+
if (buffer->buff == NULL)
|
|
28
|
+
return TRILOGY_MEM_ERROR;
|
|
29
|
+
|
|
26
30
|
size_t new_cap = buffer->cap;
|
|
27
31
|
|
|
28
32
|
while (buffer->len + needed > new_cap) {
|
|
@@ -57,9 +61,24 @@ int trilogy_buffer_putc(trilogy_buffer_t *buffer, uint8_t c)
|
|
|
57
61
|
return TRILOGY_OK;
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t len)
|
|
65
|
+
{
|
|
66
|
+
int rc = trilogy_buffer_expand(buffer, len);
|
|
67
|
+
if (rc) {
|
|
68
|
+
return rc;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
memcpy(buffer->buff + buffer->len, ptr, len);
|
|
72
|
+
buffer->len += len;
|
|
73
|
+
|
|
74
|
+
return TRILOGY_OK;
|
|
75
|
+
}
|
|
76
|
+
|
|
60
77
|
void trilogy_buffer_free(trilogy_buffer_t *buffer)
|
|
61
78
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
if (buffer->buff) {
|
|
80
|
+
free(buffer->buff);
|
|
81
|
+
buffer->buff = NULL;
|
|
82
|
+
buffer->len = buffer->cap = 0;
|
|
83
|
+
}
|
|
65
84
|
}
|
|
@@ -182,7 +182,7 @@ int trilogy_builder_write_buffer(trilogy_builder_t *builder, const void *data, s
|
|
|
182
182
|
|
|
183
183
|
size_t fragment_remaining = TRILOGY_MAX_PACKET_LEN - builder->fragment_length;
|
|
184
184
|
|
|
185
|
-
if (builder->packet_length >= builder->packet_max_length
|
|
185
|
+
if (builder->packet_length + len >= builder->packet_max_length) {
|
|
186
186
|
return TRILOGY_MAX_PACKET_EXCEEDED;
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include <fcntl.h>
|
|
2
|
+
#include <string.h>
|
|
2
3
|
|
|
3
4
|
#include "trilogy/client.h"
|
|
4
5
|
#include "trilogy/error.h"
|
|
@@ -117,10 +118,8 @@ static int begin_write(trilogy_conn_t *conn)
|
|
|
117
118
|
return trilogy_flush_writes(conn);
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
int
|
|
121
|
+
int trilogy_init_no_buffer(trilogy_conn_t *conn)
|
|
121
122
|
{
|
|
122
|
-
int rc;
|
|
123
|
-
|
|
124
123
|
conn->affected_rows = 0;
|
|
125
124
|
conn->last_insert_id = 0;
|
|
126
125
|
conn->warning_count = 0;
|
|
@@ -142,8 +141,14 @@ int trilogy_init(trilogy_conn_t *conn)
|
|
|
142
141
|
trilogy_packet_parser_init(&conn->packet_parser, &packet_parser_callbacks);
|
|
143
142
|
conn->packet_parser.user_data = &conn->packet_buffer;
|
|
144
143
|
|
|
145
|
-
|
|
144
|
+
return TRILOGY_OK;
|
|
145
|
+
}
|
|
146
146
|
|
|
147
|
+
int trilogy_init(trilogy_conn_t *conn)
|
|
148
|
+
{
|
|
149
|
+
int rc;
|
|
150
|
+
trilogy_init_no_buffer(conn);
|
|
151
|
+
CHECKED(trilogy_buffer_init(&conn->packet_buffer, TRILOGY_DEFAULT_BUF_SIZE));
|
|
147
152
|
return TRILOGY_OK;
|
|
148
153
|
}
|
|
149
154
|
|
|
@@ -217,7 +222,7 @@ static int read_err_packet(trilogy_conn_t *conn)
|
|
|
217
222
|
return TRILOGY_ERR;
|
|
218
223
|
}
|
|
219
224
|
|
|
220
|
-
static int
|
|
225
|
+
static int read_deprecated_eof_packet(trilogy_conn_t *conn)
|
|
221
226
|
{
|
|
222
227
|
trilogy_eof_packet_t eof_packet;
|
|
223
228
|
|
|
@@ -236,6 +241,21 @@ static int read_eof_packet(trilogy_conn_t *conn)
|
|
|
236
241
|
return TRILOGY_EOF;
|
|
237
242
|
}
|
|
238
243
|
|
|
244
|
+
static int read_eof_packet(trilogy_conn_t *conn)
|
|
245
|
+
{
|
|
246
|
+
int rc;
|
|
247
|
+
|
|
248
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) {
|
|
249
|
+
return read_ok_packet(conn);
|
|
250
|
+
} else {
|
|
251
|
+
if ((rc = read_deprecated_eof_packet(conn)) != TRILOGY_EOF) {
|
|
252
|
+
return rc;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return TRILOGY_OK;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
239
259
|
static int read_auth_switch_packet(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
|
240
260
|
{
|
|
241
261
|
trilogy_auth_switch_request_packet_t auth_switch_packet;
|
|
@@ -646,15 +666,7 @@ static int read_eof(trilogy_conn_t *conn)
|
|
|
646
666
|
return rc;
|
|
647
667
|
}
|
|
648
668
|
|
|
649
|
-
|
|
650
|
-
return read_ok_packet(conn);
|
|
651
|
-
} else {
|
|
652
|
-
if ((rc = read_eof_packet(conn)) != TRILOGY_EOF) {
|
|
653
|
-
return rc;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
return TRILOGY_OK;
|
|
657
|
-
}
|
|
669
|
+
return read_eof_packet(conn);
|
|
658
670
|
}
|
|
659
671
|
|
|
660
672
|
int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
|
|
@@ -679,14 +691,12 @@ int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
|
|
|
679
691
|
return rc;
|
|
680
692
|
}
|
|
681
693
|
|
|
682
|
-
if (conn
|
|
683
|
-
if ((rc =
|
|
694
|
+
if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
|
695
|
+
if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
|
|
684
696
|
return rc;
|
|
685
697
|
}
|
|
686
698
|
|
|
687
699
|
return TRILOGY_EOF;
|
|
688
|
-
} else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
|
689
|
-
return read_eof_packet(conn);
|
|
690
700
|
} else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
|
|
691
701
|
return read_err_packet(conn);
|
|
692
702
|
} else {
|
|
@@ -722,7 +732,7 @@ int trilogy_drain_results(trilogy_conn_t *conn)
|
|
|
722
732
|
}
|
|
723
733
|
}
|
|
724
734
|
|
|
725
|
-
static uint8_t escape_lookup_table[256] = {
|
|
735
|
+
static const uint8_t escape_lookup_table[256] = {
|
|
726
736
|
['"'] = '"', ['\0'] = '0', ['\''] = '\'', ['\\'] = '\\', ['\n'] = 'n', ['\r'] = 'r', [26] = 'Z',
|
|
727
737
|
};
|
|
728
738
|
|
|
@@ -735,28 +745,40 @@ int trilogy_escape(trilogy_conn_t *conn, const char *str, size_t len, const char
|
|
|
735
745
|
|
|
736
746
|
b->len = 0;
|
|
737
747
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
748
|
+
// Escaped string will be at least as large as the source string,
|
|
749
|
+
// so might as well pre-expand the buffer.
|
|
750
|
+
CHECKED(trilogy_buffer_expand(b, len));
|
|
751
|
+
|
|
752
|
+
const uint8_t *cursor = (const uint8_t *)str;
|
|
753
|
+
const uint8_t *end = cursor + len;
|
|
741
754
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
755
|
+
if (conn->server_status & TRILOGY_SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
|
|
756
|
+
while (cursor < end) {
|
|
757
|
+
uint8_t *next_escape = memchr(cursor, '\'', (size_t)(end - cursor));
|
|
758
|
+
if (next_escape) {
|
|
759
|
+
CHECKED(trilogy_buffer_write(b, cursor, (size_t)(next_escape - cursor)));
|
|
760
|
+
CHECKED(trilogy_buffer_write(b, (uint8_t *)"\'\'", 2));
|
|
761
|
+
cursor = next_escape + 1;
|
|
745
762
|
} else {
|
|
746
|
-
CHECKED(
|
|
763
|
+
CHECKED(trilogy_buffer_write(b, cursor, (size_t)(end - cursor)));
|
|
764
|
+
break;
|
|
747
765
|
}
|
|
748
766
|
}
|
|
749
767
|
} else {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
768
|
+
while (cursor < end) {
|
|
769
|
+
uint8_t escaped = 0;
|
|
770
|
+
const uint8_t *start = cursor;
|
|
771
|
+
while (cursor < end && !(escaped = escape_lookup_table[*cursor])) {
|
|
772
|
+
cursor++;
|
|
773
|
+
}
|
|
754
774
|
|
|
775
|
+
CHECKED(trilogy_buffer_write(b, start, (size_t)(cursor - start)));
|
|
755
776
|
if (escaped) {
|
|
756
777
|
CHECKED(trilogy_buffer_putc(b, '\\'));
|
|
757
778
|
CHECKED(trilogy_buffer_putc(b, escaped));
|
|
779
|
+
cursor++;
|
|
758
780
|
} else {
|
|
759
|
-
|
|
781
|
+
break;
|
|
760
782
|
}
|
|
761
783
|
}
|
|
762
784
|
}
|
|
@@ -940,20 +962,18 @@ int trilogy_stmt_bind_data_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint
|
|
|
940
962
|
int trilogy_stmt_read_row(trilogy_conn_t *conn, trilogy_stmt_t *stmt, trilogy_column_packet_t *columns,
|
|
941
963
|
trilogy_binary_value_t *values_out)
|
|
942
964
|
{
|
|
943
|
-
int
|
|
965
|
+
int rc = read_packet(conn);
|
|
944
966
|
|
|
945
|
-
if (
|
|
946
|
-
return
|
|
967
|
+
if (rc < 0) {
|
|
968
|
+
return rc;
|
|
947
969
|
}
|
|
948
970
|
|
|
949
|
-
if (conn
|
|
950
|
-
if ((
|
|
951
|
-
return
|
|
971
|
+
if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
|
972
|
+
if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
|
|
973
|
+
return rc;
|
|
952
974
|
}
|
|
953
975
|
|
|
954
976
|
return TRILOGY_EOF;
|
|
955
|
-
} else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
|
956
|
-
return read_eof_packet(conn);
|
|
957
977
|
} else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
|
|
958
978
|
return read_err_packet(conn);
|
|
959
979
|
} else {
|
|
@@ -926,6 +926,8 @@ int trilogy_build_stmt_execute_packet(trilogy_builder_t *builder, uint32_t stmt_
|
|
|
926
926
|
case TRILOGY_TYPE_VAR_STRING:
|
|
927
927
|
case TRILOGY_TYPE_STRING:
|
|
928
928
|
case TRILOGY_TYPE_GEOMETRY:
|
|
929
|
+
case TRILOGY_TYPE_JSON:
|
|
930
|
+
case TRILOGY_TYPE_VECTOR:
|
|
929
931
|
CHECKED(trilogy_builder_write_lenenc_buffer(builder, val.as.str.data, val.as.str.len));
|
|
930
932
|
|
|
931
933
|
break;
|
|
@@ -1059,6 +1061,7 @@ int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_colum
|
|
|
1059
1061
|
case TRILOGY_TYPE_DECIMAL:
|
|
1060
1062
|
case TRILOGY_TYPE_NEWDECIMAL:
|
|
1061
1063
|
case TRILOGY_TYPE_JSON:
|
|
1064
|
+
case TRILOGY_TYPE_VECTOR:
|
|
1062
1065
|
CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_values[i].as.str.len,
|
|
1063
1066
|
(const void **)&out_values[i].as.str.data));
|
|
1064
1067
|
|
data/lib/trilogy/encoding.rb
CHANGED
data/lib/trilogy/result.rb
CHANGED
data/lib/trilogy/version.rb
CHANGED
data/trilogy.gemspec
CHANGED
|
@@ -22,6 +22,10 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
|
|
23
23
|
s.require_paths = ["lib"]
|
|
24
24
|
|
|
25
|
+
s.required_ruby_version = ">= 3.0"
|
|
26
|
+
|
|
27
|
+
s.add_dependency "bigdecimal"
|
|
28
|
+
|
|
25
29
|
s.add_development_dependency "rake-compiler", "~> 1.0"
|
|
26
30
|
s.add_development_dependency "minitest", "~> 5.5"
|
|
27
31
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trilogy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitHub Engineering
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: bigdecimal
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
13
26
|
- !ruby/object:Gem::Dependency
|
|
14
27
|
name: rake-compiler
|
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,7 +51,6 @@ dependencies:
|
|
|
38
51
|
- - "~>"
|
|
39
52
|
- !ruby/object:Gem::Version
|
|
40
53
|
version: '5.5'
|
|
41
|
-
description:
|
|
42
54
|
email: opensource+trilogy@github.com
|
|
43
55
|
executables: []
|
|
44
56
|
extensions:
|
|
@@ -87,7 +99,6 @@ homepage: https://github.com/trilogy-libraries/trilogy
|
|
|
87
99
|
licenses:
|
|
88
100
|
- MIT
|
|
89
101
|
metadata: {}
|
|
90
|
-
post_install_message:
|
|
91
102
|
rdoc_options: []
|
|
92
103
|
require_paths:
|
|
93
104
|
- lib
|
|
@@ -95,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
95
106
|
requirements:
|
|
96
107
|
- - ">="
|
|
97
108
|
- !ruby/object:Gem::Version
|
|
98
|
-
version: '0'
|
|
109
|
+
version: '3.0'
|
|
99
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
111
|
requirements:
|
|
101
112
|
- - ">="
|
|
102
113
|
- !ruby/object:Gem::Version
|
|
103
114
|
version: '0'
|
|
104
115
|
requirements: []
|
|
105
|
-
rubygems_version: 3.
|
|
106
|
-
signing_key:
|
|
116
|
+
rubygems_version: 3.6.9
|
|
107
117
|
specification_version: 4
|
|
108
118
|
summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
|
|
109
119
|
test_files: []
|