trilogy 2.11.1 → 2.12.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/ext/trilogy-ruby/cast.c +184 -56
- data/ext/trilogy-ruby/cext.c +79 -84
- data/ext/trilogy-ruby/extconf.rb +1 -1
- data/ext/trilogy-ruby/inc/trilogy/allocator.h +61 -0
- data/ext/trilogy-ruby/inc/trilogy.h +1 -0
- data/ext/trilogy-ruby/src/buffer.c +4 -3
- data/ext/trilogy-ruby/src/client.c +29 -13
- data/ext/trilogy-ruby/src/socket.c +33 -29
- data/ext/trilogy-ruby/trilogy-ruby.h +4 -2
- data/ext/trilogy-ruby/trilogy_xallocator.h +1 -0
- data/lib/trilogy/result.rb +16 -0
- data/lib/trilogy/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9159fca1baf9c5d9f2a23ef0850ca007ba4f0fc2d1f70ed678bde01dedb0e9d8
|
|
4
|
+
data.tar.gz: f8239356e08a8fe724f0ae3c2fc2d628eed88a9a15a6ab1ef5b7b696bec6a8b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cec828b0440de7874f7e2df56738e8e99b024649a2d40c256ea955b652ef9375a345bc0021c4ce083c7f0fb4ce56b0cfd84524ce4d055c0d934ae702399b4f79
|
|
7
|
+
data.tar.gz: a92b013118f91b5c7ff34b9cf3d0cc4eca2bf64199ced3191fc5f17ea9f450e2c2a860d20ed82acc659a2b057e7bf366a31525f8d8fee1bede64b794c2f1a66e
|
data/ext/trilogy-ruby/cast.c
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
2
|
#include <ruby/encoding.h>
|
|
3
|
-
|
|
4
|
-
#include <
|
|
3
|
+
#include <time.h>
|
|
4
|
+
#include <limits.h>
|
|
5
5
|
|
|
6
6
|
#include "trilogy-ruby.h"
|
|
7
7
|
|
|
8
8
|
#define CAST_STACK_SIZE 64
|
|
9
9
|
|
|
10
|
-
static ID id_BigDecimal, id_Integer, id_new
|
|
10
|
+
static ID id_BigDecimal, id_Integer, id_new;
|
|
11
11
|
|
|
12
12
|
static const char *ruby_encoding_name_map[] = {
|
|
13
13
|
[TRILOGY_ENCODING_ARMSCII8] = NULL,
|
|
@@ -54,17 +54,20 @@ static const char *ruby_encoding_name_map[] = {
|
|
|
54
54
|
[TRILOGY_ENCODING_MAX] = NULL,
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
static
|
|
57
|
+
static rb_encoding * encoding_for_charset(TRILOGY_CHARSET_t charset)
|
|
58
58
|
{
|
|
59
|
-
static
|
|
59
|
+
static rb_encoding * map[TRILOGY_CHARSET_MAX];
|
|
60
60
|
|
|
61
|
-
if (map[charset]) {
|
|
61
|
+
if (RB_LIKELY(map[charset])) {
|
|
62
62
|
return map[charset];
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const char *encoding_name = ruby_encoding_name_map[trilogy_encoding_from_charset(charset)];
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
map[charset] = rb_enc_find(encoding_name);
|
|
67
|
+
if (!map[charset]) {
|
|
68
|
+
map[charset] = rb_ascii8bit_encoding();
|
|
69
|
+
}
|
|
70
|
+
return map[charset];
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
static void cstr_from_value(char *buf, const trilogy_value_t *value, const char *errmsg)
|
|
@@ -78,6 +81,92 @@ static void cstr_from_value(char *buf, const trilogy_value_t *value, const char
|
|
|
78
81
|
buf[value->data_len] = 0;
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
// For UTC: uses the Hinnant civil_to_days algorithm (C++20 std::chrono
|
|
85
|
+
// foundation, handles the full MySQL 1000-9999 year range without timegm).
|
|
86
|
+
// For local: uses mktime (standard C) which consults the system timezone.
|
|
87
|
+
// http://howardhinnant.github.io/date_algorithms.html
|
|
88
|
+
static time_t civil_to_epoch_utc(int year, int month, int day, int hour, int min, int sec)
|
|
89
|
+
{
|
|
90
|
+
year -= (month <= 2);
|
|
91
|
+
int era = (year >= 0 ? year : year - 399) / 400;
|
|
92
|
+
unsigned yoe = (unsigned)(year - era * 400);
|
|
93
|
+
unsigned doy = (153 * (month > 2 ? month - 3 : month + 9) + 2) / 5 + (unsigned)day - 1;
|
|
94
|
+
unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
|
|
95
|
+
long days = (long)era * 146097 + (long)doe - 719468;
|
|
96
|
+
return (time_t)(days * 86400 + hour * 3600 + min * 60 + sec);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static VALUE trilogy_make_time(int year, int month, int day, int hour, int min, int sec,
|
|
100
|
+
int usec, int local)
|
|
101
|
+
{
|
|
102
|
+
struct timespec ts;
|
|
103
|
+
if (local) {
|
|
104
|
+
struct tm tm = {
|
|
105
|
+
.tm_year = year - 1900,
|
|
106
|
+
.tm_mon = month - 1,
|
|
107
|
+
.tm_mday = day,
|
|
108
|
+
.tm_hour = hour,
|
|
109
|
+
.tm_min = min,
|
|
110
|
+
.tm_sec = sec,
|
|
111
|
+
.tm_isdst = -1,
|
|
112
|
+
};
|
|
113
|
+
ts.tv_sec = mktime(&tm);
|
|
114
|
+
} else {
|
|
115
|
+
ts.tv_sec = civil_to_epoch_utc(year, month, day, hour, min, sec);
|
|
116
|
+
}
|
|
117
|
+
ts.tv_nsec = (long)usec * 1000;
|
|
118
|
+
return rb_time_timespec_new(&ts, local ? INT_MAX : INT_MAX - 1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Byte-arithmetic datetime parsing helpers (inspired by Go's go-sql-driver/mysql)
|
|
122
|
+
// These avoid sscanf overhead by parsing ASCII digits directly.
|
|
123
|
+
|
|
124
|
+
static inline int byte_to_digit(const char b)
|
|
125
|
+
{
|
|
126
|
+
if (b < '0' || b > '9')
|
|
127
|
+
return -1;
|
|
128
|
+
return b - '0';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static inline int parse_2digits(const char *p)
|
|
132
|
+
{
|
|
133
|
+
int d1 = byte_to_digit(p[0]);
|
|
134
|
+
int d2 = byte_to_digit(p[1]);
|
|
135
|
+
if (d1 < 0 || d2 < 0)
|
|
136
|
+
return -1;
|
|
137
|
+
return d1 * 10 + d2;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static inline int parse_4digits(const char *p)
|
|
141
|
+
{
|
|
142
|
+
int d0 = byte_to_digit(p[0]);
|
|
143
|
+
int d1 = byte_to_digit(p[1]);
|
|
144
|
+
int d2 = byte_to_digit(p[2]);
|
|
145
|
+
int d3 = byte_to_digit(p[3]);
|
|
146
|
+
if (d0 < 0 || d1 < 0 || d2 < 0 || d3 < 0)
|
|
147
|
+
return -1;
|
|
148
|
+
return d0 * 1000 + d1 * 100 + d2 * 10 + d3;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Parse 1-6 fractional digits into microseconds (6-digit value).
|
|
152
|
+
// "1" => 100000
|
|
153
|
+
// "12" => 120000
|
|
154
|
+
// "123" => 123000
|
|
155
|
+
// "123456" => 123456
|
|
156
|
+
static inline int parse_microseconds(const char *p, size_t len)
|
|
157
|
+
{
|
|
158
|
+
int usec = 0;
|
|
159
|
+
int multiplier = 100000;
|
|
160
|
+
for (size_t i = 0; i < len && i < 6; i++) {
|
|
161
|
+
int d = byte_to_digit(p[i]);
|
|
162
|
+
if (d < 0)
|
|
163
|
+
return -1;
|
|
164
|
+
usec += d * multiplier;
|
|
165
|
+
multiplier /= 10;
|
|
166
|
+
}
|
|
167
|
+
return usec;
|
|
168
|
+
}
|
|
169
|
+
|
|
81
170
|
static unsigned long long ull_from_buf(const char *digits, size_t len)
|
|
82
171
|
{
|
|
83
172
|
if (!len)
|
|
@@ -166,16 +255,54 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
|
166
255
|
}
|
|
167
256
|
case TRILOGY_TYPE_TIMESTAMP:
|
|
168
257
|
case TRILOGY_TYPE_DATETIME: {
|
|
169
|
-
|
|
170
|
-
|
|
258
|
+
const char *p = (const char *)value->data;
|
|
259
|
+
size_t len = value->data_len;
|
|
260
|
+
int year, month, day, hour = 0, min = 0, sec = 0, usec = 0;
|
|
261
|
+
|
|
262
|
+
// Length-based dispatch like Go's parseDateTime:
|
|
263
|
+
// 10 = "YYYY-MM-DD"
|
|
264
|
+
// 19 = "YYYY-MM-DD HH:MM:SS"
|
|
265
|
+
// 21-26 = "YYYY-MM-DD HH:MM:SS.F" through "YYYY-MM-DD HH:MM:SS.FFFFFF"
|
|
266
|
+
if (len < 10)
|
|
267
|
+
return Qnil;
|
|
171
268
|
|
|
172
|
-
|
|
173
|
-
|
|
269
|
+
year = parse_4digits(p);
|
|
270
|
+
if (year < 0 || p[4] != '-')
|
|
271
|
+
return Qnil;
|
|
272
|
+
|
|
273
|
+
month = parse_2digits(p + 5);
|
|
274
|
+
if (month < 0 || p[7] != '-')
|
|
275
|
+
return Qnil;
|
|
276
|
+
|
|
277
|
+
day = parse_2digits(p + 8);
|
|
278
|
+
if (day < 0)
|
|
279
|
+
return Qnil;
|
|
280
|
+
|
|
281
|
+
if (len >= 19) {
|
|
282
|
+
if (p[10] != ' ')
|
|
283
|
+
return Qnil;
|
|
174
284
|
|
|
175
|
-
|
|
285
|
+
hour = parse_2digits(p + 11);
|
|
286
|
+
if (hour < 0 || p[13] != ':')
|
|
287
|
+
return Qnil;
|
|
176
288
|
|
|
177
|
-
|
|
178
|
-
|
|
289
|
+
min = parse_2digits(p + 14);
|
|
290
|
+
if (min < 0 || p[16] != ':')
|
|
291
|
+
return Qnil;
|
|
292
|
+
|
|
293
|
+
sec = parse_2digits(p + 17);
|
|
294
|
+
if (sec < 0)
|
|
295
|
+
return Qnil;
|
|
296
|
+
|
|
297
|
+
if (len > 19) {
|
|
298
|
+
if (p[19] != '.' || len < 21 || len > 26)
|
|
299
|
+
return Qnil;
|
|
300
|
+
|
|
301
|
+
usec = parse_microseconds(p + 20, len - 20);
|
|
302
|
+
if (usec < 0)
|
|
303
|
+
return Qnil;
|
|
304
|
+
}
|
|
305
|
+
} else if (len != 10) {
|
|
179
306
|
return Qnil;
|
|
180
307
|
}
|
|
181
308
|
|
|
@@ -187,28 +314,29 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
|
187
314
|
rb_raise(Trilogy_CastError, "Invalid date: %.*s", (int)value->data_len, (char *)value->data);
|
|
188
315
|
}
|
|
189
316
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
for (size_t i = strlen(msec_char); i < sizeof(msec_char) - 1; i++) {
|
|
193
|
-
msec_char[i] = '0';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return rb_funcall(rb_cTime, options->database_local_time ? id_local : id_utc, 7, INT2NUM(year),
|
|
197
|
-
INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec),
|
|
198
|
-
INT2NUM(atoi(msec_char)));
|
|
317
|
+
return trilogy_make_time(year, month, day, hour, min, sec, usec,
|
|
318
|
+
options->database_local_time);
|
|
199
319
|
}
|
|
200
320
|
case TRILOGY_TYPE_DATE: {
|
|
201
|
-
|
|
321
|
+
const char *p = (const char *)value->data;
|
|
322
|
+
size_t len = value->data_len;
|
|
202
323
|
|
|
203
|
-
|
|
204
|
-
|
|
324
|
+
if (len != 10)
|
|
325
|
+
return Qnil;
|
|
205
326
|
|
|
206
|
-
int
|
|
207
|
-
|
|
327
|
+
int year = parse_4digits(p);
|
|
328
|
+
if (year < 0 || p[4] != '-')
|
|
329
|
+
return Qnil;
|
|
208
330
|
|
|
209
|
-
|
|
331
|
+
int month = parse_2digits(p + 5);
|
|
332
|
+
if (month < 0 || p[7] != '-')
|
|
210
333
|
return Qnil;
|
|
211
|
-
|
|
334
|
+
|
|
335
|
+
int day = parse_2digits(p + 8);
|
|
336
|
+
if (day < 0)
|
|
337
|
+
return Qnil;
|
|
338
|
+
|
|
339
|
+
VALUE Date = rb_const_get(rb_cObject, rb_intern("Date"));
|
|
212
340
|
|
|
213
341
|
if (year == 0 && month == 0 && day == 0) {
|
|
214
342
|
return Qnil;
|
|
@@ -221,26 +349,37 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
|
221
349
|
return rb_funcall(Date, id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
|
|
222
350
|
}
|
|
223
351
|
case TRILOGY_TYPE_TIME: {
|
|
224
|
-
|
|
225
|
-
|
|
352
|
+
const char *p = (const char *)value->data;
|
|
353
|
+
size_t len = value->data_len;
|
|
226
354
|
|
|
227
|
-
|
|
228
|
-
|
|
355
|
+
// Expected: "HH:MM:SS" (8) or "HH:MM:SS.F" through "HH:MM:SS.FFFFFF" (10-15)
|
|
356
|
+
if (len < 8)
|
|
357
|
+
return Qnil;
|
|
229
358
|
|
|
230
|
-
int
|
|
359
|
+
int hour = parse_2digits(p);
|
|
360
|
+
if (hour < 0 || p[2] != ':')
|
|
361
|
+
return Qnil;
|
|
231
362
|
|
|
232
|
-
|
|
363
|
+
int min = parse_2digits(p + 3);
|
|
364
|
+
if (min < 0 || p[5] != ':')
|
|
233
365
|
return Qnil;
|
|
234
|
-
}
|
|
235
366
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
367
|
+
int sec = parse_2digits(p + 6);
|
|
368
|
+
if (sec < 0)
|
|
369
|
+
return Qnil;
|
|
370
|
+
|
|
371
|
+
int usec = 0;
|
|
372
|
+
if (len > 8) {
|
|
373
|
+
if (p[8] != '.' || len < 10 || len > 15)
|
|
374
|
+
return Qnil;
|
|
375
|
+
|
|
376
|
+
usec = parse_microseconds(p + 9, len - 9);
|
|
377
|
+
if (usec < 0)
|
|
378
|
+
return Qnil;
|
|
240
379
|
}
|
|
241
380
|
|
|
242
|
-
return
|
|
243
|
-
|
|
381
|
+
return trilogy_make_time(2000, 1, 1, hour, min, sec, usec,
|
|
382
|
+
options->database_local_time);
|
|
244
383
|
}
|
|
245
384
|
default:
|
|
246
385
|
break;
|
|
@@ -248,15 +387,7 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
|
|
|
248
387
|
}
|
|
249
388
|
|
|
250
389
|
// for all other types, just return a string
|
|
251
|
-
|
|
252
|
-
VALUE str = rb_str_new(value->data, value->data_len);
|
|
253
|
-
|
|
254
|
-
int encoding_index = encoding_for_charset(column->charset);
|
|
255
|
-
if (encoding_index != -1) {
|
|
256
|
-
rb_enc_associate_index(str, encoding_index);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return str;
|
|
390
|
+
return rb_enc_str_new(value->data, value->data_len, encoding_for_charset(column->charset));
|
|
260
391
|
}
|
|
261
392
|
|
|
262
393
|
void rb_trilogy_cast_init(void)
|
|
@@ -267,7 +398,4 @@ void rb_trilogy_cast_init(void)
|
|
|
267
398
|
id_BigDecimal = rb_intern("BigDecimal");
|
|
268
399
|
id_Integer = rb_intern("Integer");
|
|
269
400
|
id_new = rb_intern("new");
|
|
270
|
-
id_local = rb_intern("local");
|
|
271
|
-
id_localtime = rb_intern("localtime");
|
|
272
|
-
id_utc = rb_intern("utc");
|
|
273
401
|
}
|
data/ext/trilogy-ruby/cext.c
CHANGED
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
#include <unistd.h>
|
|
12
12
|
#include <fcntl.h>
|
|
13
13
|
|
|
14
|
-
#include <trilogy.h>
|
|
15
|
-
|
|
16
14
|
#include "trilogy-ruby.h"
|
|
17
15
|
|
|
18
16
|
typedef struct _buffer_pool_entry_struct {
|
|
@@ -41,9 +39,7 @@ static void buffer_pool_free(void *data)
|
|
|
41
39
|
buffer_pool *pool = (buffer_pool *)data;
|
|
42
40
|
if (pool->capa) {
|
|
43
41
|
for (size_t index = 0; index < pool->len; index++) {
|
|
44
|
-
|
|
45
|
-
// hence we must use raw `free`.
|
|
46
|
-
free(pool->entries[index].buff);
|
|
42
|
+
xfree(pool->entries[index].buff);
|
|
47
43
|
}
|
|
48
44
|
xfree(pool->entries);
|
|
49
45
|
}
|
|
@@ -124,7 +120,7 @@ static void buffer_checkout(trilogy_buffer_t *buffer, size_t initial_capacity)
|
|
|
124
120
|
buffer->buff = pool->entries[pool->len].buff;
|
|
125
121
|
buffer->cap = pool->entries[pool->len].cap;
|
|
126
122
|
} else {
|
|
127
|
-
buffer->buff =
|
|
123
|
+
buffer->buff = xmalloc(initial_capacity);
|
|
128
124
|
buffer->cap = initial_capacity;
|
|
129
125
|
}
|
|
130
126
|
}
|
|
@@ -134,7 +130,7 @@ static bool buffer_checkin(trilogy_buffer_t *buffer)
|
|
|
134
130
|
buffer_pool * pool = get_buffer_pool();
|
|
135
131
|
|
|
136
132
|
if (pool->len >= BUFFER_POOL_MAX_SIZE) {
|
|
137
|
-
|
|
133
|
+
xfree(buffer->buff);
|
|
138
134
|
buffer->buff = NULL;
|
|
139
135
|
buffer->cap = 0;
|
|
140
136
|
return false;
|
|
@@ -165,10 +161,10 @@ static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLErro
|
|
|
165
161
|
|
|
166
162
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
|
167
163
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
id_password, id_database, id_enable_cleartext_plugin,
|
|
165
|
+
id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
|
170
166
|
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
|
|
171
|
-
id_from_code, id_from_errno,
|
|
167
|
+
id_from_code, id_from_errno, id_max_allowed_packet;
|
|
172
168
|
|
|
173
169
|
struct trilogy_ctx {
|
|
174
170
|
trilogy_conn_t conn;
|
|
@@ -938,102 +934,107 @@ static VALUE read_query_response(VALUE vargs)
|
|
|
938
934
|
double query_time = finish.tv_sec - start.tv_sec;
|
|
939
935
|
query_time += (double)(finish.tv_nsec - start.tv_nsec) / 1000000000.0;
|
|
940
936
|
|
|
941
|
-
VALUE
|
|
942
|
-
|
|
943
|
-
VALUE column_names = rb_ary_new2(column_count);
|
|
944
|
-
rb_ivar_set(result, id_ivar_fields, column_names);
|
|
937
|
+
VALUE column_names = 0;
|
|
945
938
|
|
|
946
939
|
VALUE rows = rb_ary_new();
|
|
947
|
-
rb_ivar_set(result, id_ivar_rows, rows);
|
|
948
|
-
|
|
949
|
-
rb_ivar_set(result, id_ivar_query_time, DBL2NUM(query_time));
|
|
950
940
|
|
|
941
|
+
VALUE last_insert_id = Qnil, affected_rows = Qnil;
|
|
951
942
|
if (rc == TRILOGY_OK) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
rb_ivar_set(result, id_ivar_affected_rows, ULL2NUM(ctx->conn.affected_rows));
|
|
955
|
-
|
|
956
|
-
return result;
|
|
957
|
-
} else {
|
|
958
|
-
rb_ivar_set(result, id_ivar_last_insert_id, Qnil);
|
|
959
|
-
rb_ivar_set(result, id_ivar_affected_rows, Qnil);
|
|
943
|
+
last_insert_id = ULL2NUM(ctx->conn.last_insert_id);
|
|
944
|
+
affected_rows = ULL2NUM(ctx->conn.affected_rows);
|
|
960
945
|
}
|
|
946
|
+
else {
|
|
947
|
+
VALUE rb_column_info;
|
|
948
|
+
struct column_info *column_info = ALLOCV_N(struct column_info, rb_column_info, column_count);
|
|
949
|
+
VALUE rb_ruby_values;
|
|
950
|
+
VALUE *row_ruby_values = ALLOCV_N(VALUE, rb_ruby_values, column_count);
|
|
961
951
|
|
|
962
|
-
|
|
963
|
-
|
|
952
|
+
for (uint64_t i = 0; i < column_count; i++) {
|
|
953
|
+
trilogy_column_t column;
|
|
964
954
|
|
|
965
|
-
|
|
966
|
-
|
|
955
|
+
while (1) {
|
|
956
|
+
rc = trilogy_read_column(&ctx->conn, &column);
|
|
967
957
|
|
|
968
|
-
|
|
969
|
-
|
|
958
|
+
if (rc == TRILOGY_OK) {
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
970
961
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
962
|
+
if (rc != TRILOGY_AGAIN) {
|
|
963
|
+
return read_query_error(args, rc, "trilogy_read_column");
|
|
964
|
+
}
|
|
974
965
|
|
|
975
|
-
|
|
976
|
-
|
|
966
|
+
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
967
|
+
if (rc != TRILOGY_OK) {
|
|
968
|
+
return read_query_error(args, rc, "trilogy_read_column");
|
|
969
|
+
}
|
|
977
970
|
}
|
|
978
971
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
972
|
+
#ifdef HAVE_RB_ENC_INTERNED_STR
|
|
973
|
+
row_ruby_values[i] = rb_enc_interned_str(column.name, column.name_len, ctx->encoding);
|
|
974
|
+
#else
|
|
975
|
+
row_ruby_values[i] = rb_enc_str_new(column.name, column.name_len, ctx->encoding);
|
|
976
|
+
OBJ_FREEZE(row_ruby_values[i]);
|
|
977
|
+
#endif
|
|
978
|
+
|
|
979
|
+
column_info[i].type = column.type;
|
|
980
|
+
column_info[i].flags = column.flags;
|
|
981
|
+
column_info[i].len = column.len;
|
|
982
|
+
column_info[i].charset = column.charset;
|
|
983
|
+
column_info[i].decimals = column.decimals;
|
|
983
984
|
}
|
|
984
985
|
|
|
985
|
-
|
|
986
|
-
VALUE column_name = rb_enc_interned_str(column.name, column.name_len, ctx->encoding);
|
|
987
|
-
#else
|
|
988
|
-
VALUE column_name = rb_enc_str_new(column.name, column.name_len, ctx->encoding);
|
|
989
|
-
OBJ_FREEZE(column_name);
|
|
990
|
-
#endif
|
|
986
|
+
column_names = rb_ary_new_from_values(column_count, row_ruby_values);
|
|
991
987
|
|
|
992
|
-
|
|
988
|
+
VALUE rb_trilogy_values;
|
|
989
|
+
trilogy_value_t *row_trilogy_values = ALLOCV_N(trilogy_value_t, rb_trilogy_values, column_count);
|
|
993
990
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
column_info[i].len = column.len;
|
|
997
|
-
column_info[i].charset = column.charset;
|
|
998
|
-
column_info[i].decimals = column.decimals;
|
|
999
|
-
}
|
|
991
|
+
while (1) {
|
|
992
|
+
int rc = trilogy_read_row(&ctx->conn, row_trilogy_values);
|
|
1000
993
|
|
|
1001
|
-
|
|
1002
|
-
|
|
994
|
+
if (rc == TRILOGY_AGAIN) {
|
|
995
|
+
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
996
|
+
if (rc != TRILOGY_OK) {
|
|
997
|
+
return read_query_error(args, rc, "trilogy_read_row");
|
|
998
|
+
}
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1003
1001
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1002
|
+
if (rc == TRILOGY_EOF) {
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1006
1005
|
|
|
1007
|
-
if (rc == TRILOGY_AGAIN) {
|
|
1008
|
-
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
|
1009
1006
|
if (rc != TRILOGY_OK) {
|
|
1010
1007
|
return read_query_error(args, rc, "trilogy_read_row");
|
|
1011
1008
|
}
|
|
1012
|
-
continue;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
if (rc == TRILOGY_EOF) {
|
|
1016
|
-
break;
|
|
1017
|
-
}
|
|
1018
1009
|
|
|
1019
|
-
if (rc != TRILOGY_OK) {
|
|
1020
|
-
return read_query_error(args, rc, "trilogy_read_row");
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (args->cast_options->flatten_rows) {
|
|
1024
1010
|
for (uint64_t i = 0; i < column_count; i++) {
|
|
1025
|
-
|
|
1011
|
+
row_ruby_values[i] = rb_trilogy_cast_value(row_trilogy_values + i, column_info + i, args->cast_options);
|
|
1026
1012
|
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1013
|
+
|
|
1014
|
+
if (args->cast_options->flatten_rows) {
|
|
1015
|
+
rb_ary_cat(rows, row_ruby_values, column_count);
|
|
1016
|
+
} else {
|
|
1017
|
+
rb_ary_push(rows, rb_ary_new_from_values(column_count, row_ruby_values));
|
|
1031
1018
|
}
|
|
1032
|
-
rb_ary_push(rows, row);
|
|
1033
1019
|
}
|
|
1034
|
-
}
|
|
1035
1020
|
|
|
1036
|
-
|
|
1021
|
+
ALLOCV_END(rb_column_info);
|
|
1022
|
+
ALLOCV_END(rb_trilogy_values);
|
|
1023
|
+
ALLOCV_END(rb_ruby_values);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
return rb_class_new_instance(
|
|
1027
|
+
6,
|
|
1028
|
+
(VALUE []){
|
|
1029
|
+
column_names,
|
|
1030
|
+
rows,
|
|
1031
|
+
DBL2NUM(query_time),
|
|
1032
|
+
(ctx->conn.server_status & TRILOGY_SERVER_STATUS_IN_TRANS) ? Qtrue : Qfalse,
|
|
1033
|
+
affected_rows,
|
|
1034
|
+
last_insert_id,
|
|
1035
|
+
},
|
|
1036
|
+
Trilogy_Result
|
|
1037
|
+
);
|
|
1037
1038
|
}
|
|
1038
1039
|
|
|
1039
1040
|
static VALUE execute_read_query_response(struct trilogy_ctx *ctx)
|
|
@@ -1466,12 +1467,6 @@ RUBY_FUNC_EXPORTED void Init_cext(void)
|
|
|
1466
1467
|
id_multi_result = rb_intern("multi_result");
|
|
1467
1468
|
id_from_code = rb_intern("from_code");
|
|
1468
1469
|
id_from_errno = rb_intern("from_errno");
|
|
1469
|
-
id_ivar_affected_rows = rb_intern("@affected_rows");
|
|
1470
|
-
id_ivar_fields = rb_intern("@fields");
|
|
1471
|
-
id_ivar_last_insert_id = rb_intern("@last_insert_id");
|
|
1472
|
-
id_ivar_rows = rb_intern("@rows");
|
|
1473
|
-
id_ivar_query_time = rb_intern("@query_time");
|
|
1474
|
-
id_connection_options = rb_intern("@connection_options");
|
|
1475
1470
|
|
|
1476
1471
|
rb_trilogy_cast_init();
|
|
1477
1472
|
|
data/ext/trilogy-ruby/extconf.rb
CHANGED
|
@@ -10,7 +10,7 @@ File.binwrite("trilogy.c",
|
|
|
10
10
|
}.join)
|
|
11
11
|
|
|
12
12
|
$objs = %w[trilogy.o cast.o cext.o]
|
|
13
|
-
append_cflags(["-I #{__dir__}/inc", "-std=gnu99", "-fvisibility=hidden"])
|
|
13
|
+
append_cflags(["-I #{__dir__}/inc", "-std=gnu99", "-fvisibility=hidden", "-DTRILOGY_XALLOCATOR", "-g"])
|
|
14
14
|
|
|
15
15
|
dir_config("openssl").any? || pkg_config("openssl")
|
|
16
16
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#ifndef TRILOGY_INTERNAL_ALLOCATOR_H
|
|
2
|
+
#define TRILOGY_INTERNAL_ALLOCATOR_H
|
|
3
|
+
|
|
4
|
+
/* If you build Trilogy with a custom allocator, configure it with
|
|
5
|
+
* "-D TRILOGY_XALLOCATOR" to use your own allocator that defines xmalloc,
|
|
6
|
+
* xrealloc, xcalloc, and xfree.
|
|
7
|
+
*
|
|
8
|
+
* For example, your `trilogy_xallocator.h` file could look like this:
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* #ifndef TRILOGY_XALLOCATOR_H
|
|
12
|
+
* #define TRILOGY_XALLOCATOR_H
|
|
13
|
+
* #define xmalloc my_malloc
|
|
14
|
+
* #define xrealloc my_realloc
|
|
15
|
+
* #define xcalloc my_calloc
|
|
16
|
+
* #define xfree my_free
|
|
17
|
+
* #endif
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
#ifdef TRILOGY_XALLOCATOR
|
|
21
|
+
#include "trilogy_xallocator.h"
|
|
22
|
+
#else
|
|
23
|
+
#ifndef xmalloc
|
|
24
|
+
/* The malloc function that should be used. This can be overridden with
|
|
25
|
+
* the TRILOGY_XALLOCATOR define. */
|
|
26
|
+
#define xmalloc malloc
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
#ifndef xrealloc
|
|
30
|
+
/* The realloc function that should be used. This can be overridden with
|
|
31
|
+
* the TRILOGY_XALLOCATOR define. */
|
|
32
|
+
#define xrealloc realloc
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
#ifndef xcalloc
|
|
36
|
+
/* The calloc function that should be used. This can be overridden with
|
|
37
|
+
* the TRILOGY_XALLOCATOR define. */
|
|
38
|
+
#define xcalloc calloc
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
#ifndef xfree
|
|
42
|
+
/* The free function that should be used. This can be overridden with
|
|
43
|
+
* the TRILOGY_XALLOCATOR define. */
|
|
44
|
+
#define xfree free
|
|
45
|
+
#endif
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
#include <string.h>
|
|
49
|
+
static inline char *
|
|
50
|
+
xstrdup(const char *str)
|
|
51
|
+
{
|
|
52
|
+
char *tmp;
|
|
53
|
+
size_t len = strlen(str) + 1;
|
|
54
|
+
|
|
55
|
+
tmp = xmalloc(len);
|
|
56
|
+
memcpy(tmp, str, len);
|
|
57
|
+
|
|
58
|
+
return tmp;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#endif
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#include <stdlib.h>
|
|
3
3
|
#include <string.h>
|
|
4
4
|
|
|
5
|
+
#include "trilogy/allocator.h"
|
|
5
6
|
#include "trilogy/buffer.h"
|
|
6
7
|
#include "trilogy/error.h"
|
|
7
8
|
|
|
@@ -9,7 +10,7 @@ int trilogy_buffer_init(trilogy_buffer_t *buffer, size_t initial_capacity)
|
|
|
9
10
|
{
|
|
10
11
|
buffer->len = 0;
|
|
11
12
|
buffer->cap = initial_capacity;
|
|
12
|
-
buffer->buff =
|
|
13
|
+
buffer->buff = xmalloc(initial_capacity);
|
|
13
14
|
|
|
14
15
|
if (buffer->buff == NULL) {
|
|
15
16
|
return TRILOGY_SYSERR;
|
|
@@ -37,7 +38,7 @@ int trilogy_buffer_expand(trilogy_buffer_t *buffer, size_t needed)
|
|
|
37
38
|
new_cap *= EXPAND_MULTIPLIER;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
uint8_t *new_buff =
|
|
41
|
+
uint8_t *new_buff = xrealloc(buffer->buff, new_cap);
|
|
41
42
|
if (new_buff == NULL)
|
|
42
43
|
return TRILOGY_SYSERR;
|
|
43
44
|
|
|
@@ -77,7 +78,7 @@ int trilogy_buffer_write(trilogy_buffer_t *buffer, const uint8_t *ptr, size_t le
|
|
|
77
78
|
void trilogy_buffer_free(trilogy_buffer_t *buffer)
|
|
78
79
|
{
|
|
79
80
|
if (buffer->buff) {
|
|
80
|
-
|
|
81
|
+
xfree(buffer->buff);
|
|
81
82
|
buffer->buff = NULL;
|
|
82
83
|
buffer->len = buffer->cap = 0;
|
|
83
84
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include <stdlib.h>
|
|
8
8
|
#include <string.h>
|
|
9
9
|
|
|
10
|
+
#include "trilogy/allocator.h"
|
|
10
11
|
#include "trilogy/client.h"
|
|
11
12
|
#include "trilogy/error.h"
|
|
12
13
|
|
|
@@ -279,6 +280,21 @@ static int read_deprecated_eof_packet(trilogy_conn_t *conn)
|
|
|
279
280
|
return TRILOGY_EOF;
|
|
280
281
|
}
|
|
281
282
|
|
|
283
|
+
bool is_eof_packet(trilogy_conn_t *conn)
|
|
284
|
+
{
|
|
285
|
+
// An EOF packet first byte can mark an EOF/OK packet, a deprecated EOF packet, or a huge data packet.
|
|
286
|
+
if (current_packet_type(conn) == TRILOGY_PACKET_EOF) {
|
|
287
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) {
|
|
288
|
+
// The EOF/OK packet can contain an info message and/or session state info up to max packet length.
|
|
289
|
+
return conn->packet_buffer.len <= TRILOGY_MAX_PACKET_LEN;
|
|
290
|
+
} else {
|
|
291
|
+
// The deprecated EOF packet must be smaller than 9 bytes (one 8-byte length-encoded integer).
|
|
292
|
+
return conn->packet_buffer.len < 9;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
|
|
282
298
|
static int read_eof_packet(trilogy_conn_t *conn)
|
|
283
299
|
{
|
|
284
300
|
int rc;
|
|
@@ -566,7 +582,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
566
582
|
return TRILOGY_MEM_ERROR;
|
|
567
583
|
}
|
|
568
584
|
size_t plaintext_len = password_len + 1;
|
|
569
|
-
uint8_t *plaintext =
|
|
585
|
+
uint8_t *plaintext = xmalloc(plaintext_len);
|
|
570
586
|
|
|
571
587
|
if (plaintext == NULL) {
|
|
572
588
|
return TRILOGY_MEM_ERROR;
|
|
@@ -585,7 +601,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
585
601
|
|
|
586
602
|
BIO *bio = BIO_new_mem_buf((void *)key_data, (int)key_data_len);
|
|
587
603
|
if (bio == NULL) {
|
|
588
|
-
|
|
604
|
+
xfree(plaintext);
|
|
589
605
|
return TRILOGY_OPENSSL_ERR;
|
|
590
606
|
}
|
|
591
607
|
|
|
@@ -600,7 +616,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
600
616
|
if (public_key == NULL) {
|
|
601
617
|
ERR_clear_error();
|
|
602
618
|
memset(plaintext, 0, plaintext_len);
|
|
603
|
-
|
|
619
|
+
xfree(plaintext);
|
|
604
620
|
return TRILOGY_AUTH_PLUGIN_ERROR;
|
|
605
621
|
}
|
|
606
622
|
|
|
@@ -609,7 +625,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
609
625
|
if (key_size <= 0) {
|
|
610
626
|
EVP_PKEY_free(public_key);
|
|
611
627
|
memset(plaintext, 0, plaintext_len);
|
|
612
|
-
|
|
628
|
+
xfree(plaintext);
|
|
613
629
|
return TRILOGY_AUTH_PLUGIN_ERROR;
|
|
614
630
|
}
|
|
615
631
|
ciphertext_len = (size_t)key_size;
|
|
@@ -628,11 +644,11 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
628
644
|
RSA_free(public_key);
|
|
629
645
|
#endif
|
|
630
646
|
memset(plaintext, 0, plaintext_len);
|
|
631
|
-
|
|
647
|
+
xfree(plaintext);
|
|
632
648
|
return TRILOGY_AUTH_PLUGIN_ERROR;
|
|
633
649
|
}
|
|
634
650
|
|
|
635
|
-
ciphertext =
|
|
651
|
+
ciphertext = xmalloc(ciphertext_len);
|
|
636
652
|
|
|
637
653
|
if (ciphertext == NULL) {
|
|
638
654
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
@@ -641,7 +657,7 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
641
657
|
RSA_free(public_key);
|
|
642
658
|
#endif
|
|
643
659
|
memset(plaintext, 0, plaintext_len);
|
|
644
|
-
|
|
660
|
+
xfree(plaintext);
|
|
645
661
|
return TRILOGY_MEM_ERROR;
|
|
646
662
|
}
|
|
647
663
|
|
|
@@ -676,13 +692,13 @@ static int encrypt_password_with_public_key(const uint8_t *scramble, size_t scra
|
|
|
676
692
|
#endif
|
|
677
693
|
|
|
678
694
|
memset(plaintext, 0, plaintext_len);
|
|
679
|
-
|
|
695
|
+
xfree(plaintext);
|
|
680
696
|
|
|
681
697
|
if (rc == TRILOGY_OK) {
|
|
682
698
|
*encrypted_out = ciphertext;
|
|
683
699
|
} else {
|
|
684
700
|
memset(ciphertext, 0, ciphertext_len);
|
|
685
|
-
|
|
701
|
+
xfree(ciphertext);
|
|
686
702
|
}
|
|
687
703
|
|
|
688
704
|
return rc;
|
|
@@ -755,7 +771,7 @@ static int handle_fast_auth_fail(trilogy_conn_t *conn, trilogy_handshake_t *hand
|
|
|
755
771
|
|
|
756
772
|
rc = send_auth_buffer(conn, encrypted, encrypted_len);
|
|
757
773
|
memset(encrypted, 0, encrypted_len);
|
|
758
|
-
|
|
774
|
+
xfree(encrypted);
|
|
759
775
|
|
|
760
776
|
if (rc < 0) {
|
|
761
777
|
return rc;
|
|
@@ -982,7 +998,7 @@ int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
|
|
|
982
998
|
return rc;
|
|
983
999
|
}
|
|
984
1000
|
|
|
985
|
-
if (
|
|
1001
|
+
if (is_eof_packet(conn)) {
|
|
986
1002
|
if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
|
|
987
1003
|
return rc;
|
|
988
1004
|
}
|
|
@@ -1017,7 +1033,7 @@ int trilogy_drain_results(trilogy_conn_t *conn)
|
|
|
1017
1033
|
return rc;
|
|
1018
1034
|
}
|
|
1019
1035
|
|
|
1020
|
-
if (
|
|
1036
|
+
if (is_eof_packet(conn)) {
|
|
1021
1037
|
read_eof_packet(conn);
|
|
1022
1038
|
return TRILOGY_OK;
|
|
1023
1039
|
}
|
|
@@ -1260,7 +1276,7 @@ int trilogy_stmt_read_row(trilogy_conn_t *conn, trilogy_stmt_t *stmt, trilogy_co
|
|
|
1260
1276
|
return rc;
|
|
1261
1277
|
}
|
|
1262
1278
|
|
|
1263
|
-
if (
|
|
1279
|
+
if (is_eof_packet(conn)) {
|
|
1264
1280
|
if ((rc = read_eof_packet(conn)) != TRILOGY_OK) {
|
|
1265
1281
|
return rc;
|
|
1266
1282
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <stdlib.h>
|
|
12
12
|
#include <unistd.h>
|
|
13
13
|
|
|
14
|
+
#include "trilogy/allocator.h"
|
|
14
15
|
#include "trilogy/error.h"
|
|
15
16
|
#include "trilogy/socket.h"
|
|
16
17
|
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
struct trilogy_sock {
|
|
22
23
|
trilogy_sock_t base;
|
|
23
24
|
struct addrinfo *addr;
|
|
24
|
-
int fd;
|
|
25
25
|
SSL *ssl;
|
|
26
|
+
int fd;
|
|
27
|
+
bool freeaddrinfo;
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
void trilogy_sock_set_fd(trilogy_sock_t *_sock, int fd)
|
|
@@ -109,30 +111,30 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
if (sock->addr) {
|
|
112
|
-
if (sock->
|
|
113
|
-
/* We created these with calloc so must free them instead of calling freeaddrinfo */
|
|
114
|
-
free(sock->addr->ai_addr);
|
|
115
|
-
free(sock->addr);
|
|
116
|
-
} else {
|
|
114
|
+
if (sock->freeaddrinfo) {
|
|
117
115
|
freeaddrinfo(sock->addr);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
116
|
+
} else {
|
|
117
|
+
/* We created these with xcalloc so must free them instead of calling freeaddrinfo */
|
|
118
|
+
xfree(sock->addr->ai_addr);
|
|
119
|
+
xfree(sock->addr);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
xfree(sock->base.opts.hostname);
|
|
124
|
+
xfree(sock->base.opts.path);
|
|
125
|
+
xfree(sock->base.opts.database);
|
|
126
|
+
xfree(sock->base.opts.username);
|
|
127
|
+
xfree(sock->base.opts.password);
|
|
128
|
+
xfree(sock->base.opts.ssl_ca);
|
|
129
|
+
xfree(sock->base.opts.ssl_capath);
|
|
130
|
+
xfree(sock->base.opts.ssl_cert);
|
|
131
|
+
xfree(sock->base.opts.ssl_cipher);
|
|
132
|
+
xfree(sock->base.opts.ssl_crl);
|
|
133
|
+
xfree(sock->base.opts.ssl_crlpath);
|
|
134
|
+
xfree(sock->base.opts.ssl_key);
|
|
135
|
+
xfree(sock->base.opts.tls_ciphersuites);
|
|
136
|
+
|
|
137
|
+
xfree(sock);
|
|
136
138
|
return rc;
|
|
137
139
|
}
|
|
138
140
|
|
|
@@ -306,12 +308,12 @@ static char *strdupnullok(const char *str)
|
|
|
306
308
|
if (str == NULL) {
|
|
307
309
|
return NULL;
|
|
308
310
|
}
|
|
309
|
-
return
|
|
311
|
+
return xstrdup(str);
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
|
|
313
315
|
{
|
|
314
|
-
struct trilogy_sock *sock =
|
|
316
|
+
struct trilogy_sock *sock = xmalloc(sizeof(struct trilogy_sock));
|
|
315
317
|
|
|
316
318
|
sock->base.connect_cb = _cb_raw_connect;
|
|
317
319
|
sock->base.read_cb = _cb_raw_read;
|
|
@@ -328,7 +330,7 @@ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts)
|
|
|
328
330
|
sock->base.opts.username = strdupnullok(opts->username);
|
|
329
331
|
|
|
330
332
|
if (sock->base.opts.password) {
|
|
331
|
-
sock->base.opts.password =
|
|
333
|
+
sock->base.opts.password = xmalloc(opts->password_len);
|
|
332
334
|
memcpy(sock->base.opts.password, opts->password, opts->password_len);
|
|
333
335
|
}
|
|
334
336
|
|
|
@@ -358,6 +360,7 @@ int trilogy_sock_resolve(trilogy_sock_t *_sock)
|
|
|
358
360
|
char port[6];
|
|
359
361
|
snprintf(port, sizeof(port), "%hu", sock->base.opts.port);
|
|
360
362
|
|
|
363
|
+
sock->freeaddrinfo = true;
|
|
361
364
|
if (getaddrinfo(sock->base.opts.hostname, port, &hint, &sock->addr) != 0) {
|
|
362
365
|
return TRILOGY_DNS_ERR;
|
|
363
366
|
}
|
|
@@ -368,15 +371,16 @@ int trilogy_sock_resolve(trilogy_sock_t *_sock)
|
|
|
368
371
|
goto fail;
|
|
369
372
|
}
|
|
370
373
|
|
|
371
|
-
sa =
|
|
374
|
+
sa = xcalloc(1, sizeof(struct sockaddr_un));
|
|
372
375
|
sa->sun_family = AF_UNIX;
|
|
373
376
|
strcpy(sa->sun_path, sock->base.opts.path);
|
|
374
377
|
|
|
375
|
-
sock->addr =
|
|
378
|
+
sock->addr = xcalloc(1, sizeof(struct addrinfo));
|
|
376
379
|
sock->addr->ai_family = PF_UNIX;
|
|
377
380
|
sock->addr->ai_socktype = SOCK_STREAM;
|
|
378
381
|
sock->addr->ai_addr = (struct sockaddr *)sa;
|
|
379
382
|
sock->addr->ai_addrlen = sizeof(struct sockaddr_un);
|
|
383
|
+
sock->freeaddrinfo = false;
|
|
380
384
|
} else {
|
|
381
385
|
goto fail;
|
|
382
386
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#ifndef TRILOGY_RUBY_H
|
|
2
2
|
#define TRILOGY_RUBY_H
|
|
3
3
|
|
|
4
|
-
#include <
|
|
5
|
-
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
#include <trilogy_xallocator.h>
|
|
6
6
|
#include <trilogy.h>
|
|
7
7
|
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
|
|
8
10
|
#define TRILOGY_FLAGS_CAST 1
|
|
9
11
|
#define TRILOGY_FLAGS_CAST_BOOLEANS 2
|
|
10
12
|
#define TRILOGY_FLAGS_LOCAL_TIMEZONE 4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#include <ruby.h>
|
data/lib/trilogy/result.rb
CHANGED
|
@@ -2,6 +2,22 @@ class Trilogy
|
|
|
2
2
|
class Result
|
|
3
3
|
attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
|
|
4
4
|
|
|
5
|
+
EMPTY_ARRAY = [].freeze
|
|
6
|
+
private_constant :EMPTY_ARRAY
|
|
7
|
+
|
|
8
|
+
def initialize(fields, rows, query_time, in_transaction, affected_rows, last_insert_id)
|
|
9
|
+
@fields = fields || EMPTY_ARRAY
|
|
10
|
+
@rows = rows || EMPTY_ARRAY
|
|
11
|
+
@query_time = query_time
|
|
12
|
+
@in_transaction = in_transaction
|
|
13
|
+
@affected_rows = affected_rows
|
|
14
|
+
@last_insert_id = last_insert_id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def in_transaction?
|
|
18
|
+
@in_transaction
|
|
19
|
+
end
|
|
20
|
+
|
|
5
21
|
def count
|
|
6
22
|
rows.count
|
|
7
23
|
end
|
data/lib/trilogy/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trilogy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitHub Engineering
|
|
@@ -36,6 +36,7 @@ files:
|
|
|
36
36
|
- ext/trilogy-ruby/cext.c
|
|
37
37
|
- ext/trilogy-ruby/extconf.rb
|
|
38
38
|
- ext/trilogy-ruby/inc/trilogy.h
|
|
39
|
+
- ext/trilogy-ruby/inc/trilogy/allocator.h
|
|
39
40
|
- ext/trilogy-ruby/inc/trilogy/blocking.h
|
|
40
41
|
- ext/trilogy-ruby/inc/trilogy/buffer.h
|
|
41
42
|
- ext/trilogy-ruby/inc/trilogy/builder.h
|
|
@@ -61,6 +62,7 @@ files:
|
|
|
61
62
|
- ext/trilogy-ruby/src/vendor/curl_hostcheck.c
|
|
62
63
|
- ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c
|
|
63
64
|
- ext/trilogy-ruby/trilogy-ruby.h
|
|
65
|
+
- ext/trilogy-ruby/trilogy_xallocator.h
|
|
64
66
|
- lib/trilogy.rb
|
|
65
67
|
- lib/trilogy/encoding.rb
|
|
66
68
|
- lib/trilogy/error.rb
|
|
@@ -85,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
85
87
|
- !ruby/object:Gem::Version
|
|
86
88
|
version: '0'
|
|
87
89
|
requirements: []
|
|
88
|
-
rubygems_version:
|
|
90
|
+
rubygems_version: 3.6.9
|
|
89
91
|
specification_version: 4
|
|
90
92
|
summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
|
|
91
93
|
test_files: []
|