trilogy 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of trilogy might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +74 -0
- data/Rakefile +18 -0
- data/ext/trilogy-ruby/cast.c +272 -0
- data/ext/trilogy-ruby/cext.c +933 -0
- data/ext/trilogy-ruby/extconf.rb +16 -0
- data/ext/trilogy-ruby/inc/trilogy/blocking.h +163 -0
- data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
- data/ext/trilogy-ruby/inc/trilogy/builder.h +161 -0
- data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
- data/ext/trilogy-ruby/inc/trilogy/client.h +546 -0
- data/ext/trilogy-ruby/inc/trilogy/error.h +43 -0
- data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +756 -0
- data/ext/trilogy-ruby/inc/trilogy/reader.h +212 -0
- data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
- data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
- data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
- data/ext/trilogy-ruby/inc/trilogy.h +8 -0
- data/ext/trilogy-ruby/src/blocking.c +241 -0
- data/ext/trilogy-ruby/src/buffer.c +60 -0
- data/ext/trilogy-ruby/src/builder.c +198 -0
- data/ext/trilogy-ruby/src/charset.c +212 -0
- data/ext/trilogy-ruby/src/client.c +728 -0
- data/ext/trilogy-ruby/src/error.c +17 -0
- data/ext/trilogy-ruby/src/packet_parser.c +140 -0
- data/ext/trilogy-ruby/src/protocol.c +676 -0
- data/ext/trilogy-ruby/src/reader.c +244 -0
- data/ext/trilogy-ruby/src/socket.c +623 -0
- data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
- data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
- data/ext/trilogy-ruby/trilogy-ruby.h +36 -0
- data/lib/trilogy/version.rb +3 -0
- data/lib/trilogy.rb +61 -0
- data/trilogy.gemspec +27 -0
- metadata +106 -0
@@ -0,0 +1,728 @@
|
|
1
|
+
#include <errno.h>
|
2
|
+
#include <fcntl.h>
|
3
|
+
|
4
|
+
#include "trilogy/client.h"
|
5
|
+
#include "trilogy/error.h"
|
6
|
+
|
7
|
+
#define CHECKED(expr) \
|
8
|
+
if ((rc = (expr)) < 0) { \
|
9
|
+
return rc; \
|
10
|
+
}
|
11
|
+
|
12
|
+
static inline TRILOGY_PACKET_TYPE_t current_packet_type(trilogy_conn_t *conn)
|
13
|
+
{
|
14
|
+
return (TRILOGY_PACKET_TYPE_t)conn->packet_buffer.buff[0];
|
15
|
+
}
|
16
|
+
|
17
|
+
static int on_packet_begin(void *opaque)
|
18
|
+
{
|
19
|
+
trilogy_buffer_t *buff = opaque;
|
20
|
+
|
21
|
+
buff->len = 0;
|
22
|
+
|
23
|
+
return 0;
|
24
|
+
}
|
25
|
+
|
26
|
+
static int on_packet_data(void *opaque, const uint8_t *data, size_t len)
|
27
|
+
{
|
28
|
+
trilogy_buffer_t *buff = opaque;
|
29
|
+
int rc = TRILOGY_OK;
|
30
|
+
|
31
|
+
rc = trilogy_buffer_expand(buff, len);
|
32
|
+
if (rc < 0)
|
33
|
+
return rc;
|
34
|
+
|
35
|
+
memcpy(buff->buff + buff->len, data, len);
|
36
|
+
buff->len += len;
|
37
|
+
|
38
|
+
return 0;
|
39
|
+
}
|
40
|
+
|
41
|
+
static int on_packet_end(void *opaque)
|
42
|
+
{
|
43
|
+
(void)opaque;
|
44
|
+
|
45
|
+
// pause packet parsing so we can return the packet we just read to the
|
46
|
+
// caller
|
47
|
+
return 1;
|
48
|
+
}
|
49
|
+
|
50
|
+
static trilogy_packet_parser_callbacks_t packet_parser_callbacks = {
|
51
|
+
.on_packet_begin = on_packet_begin,
|
52
|
+
.on_packet_data = on_packet_data,
|
53
|
+
.on_packet_end = on_packet_end,
|
54
|
+
};
|
55
|
+
|
56
|
+
static int begin_command_phase(trilogy_builder_t *builder, trilogy_conn_t *conn, uint8_t seq)
|
57
|
+
{
|
58
|
+
int rc = trilogy_builder_init(builder, &conn->packet_buffer, seq);
|
59
|
+
if (rc < 0) {
|
60
|
+
return rc;
|
61
|
+
}
|
62
|
+
|
63
|
+
conn->packet_parser.sequence_number = seq + 1;
|
64
|
+
|
65
|
+
return 0;
|
66
|
+
}
|
67
|
+
|
68
|
+
static int read_packet(trilogy_conn_t *conn)
|
69
|
+
{
|
70
|
+
if (conn->recv_buff_pos == conn->recv_buff_len) {
|
71
|
+
ssize_t nread = trilogy_sock_read(conn->socket, conn->recv_buff, sizeof(conn->recv_buff));
|
72
|
+
|
73
|
+
if (nread < 0) {
|
74
|
+
int rc = (int)nread;
|
75
|
+
if (rc == TRILOGY_SYSERR) {
|
76
|
+
if (errno == EINTR || errno == EAGAIN) {
|
77
|
+
return TRILOGY_AGAIN;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
return rc;
|
81
|
+
}
|
82
|
+
|
83
|
+
if (nread == 0) {
|
84
|
+
return TRILOGY_CLOSED_CONNECTION;
|
85
|
+
}
|
86
|
+
|
87
|
+
conn->recv_buff_len = (size_t)nread;
|
88
|
+
conn->recv_buff_pos = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
const uint8_t *ptr = conn->recv_buff + conn->recv_buff_pos;
|
92
|
+
size_t len = conn->recv_buff_len - conn->recv_buff_pos;
|
93
|
+
|
94
|
+
int rc;
|
95
|
+
conn->recv_buff_pos += trilogy_packet_parser_execute(&conn->packet_parser, ptr, len, &rc);
|
96
|
+
|
97
|
+
if (rc < 0) {
|
98
|
+
// an error occurred in one of the callbacks
|
99
|
+
return rc;
|
100
|
+
}
|
101
|
+
|
102
|
+
if (rc > 0) {
|
103
|
+
// on_packet_end paused the parser, meaning we read a complete packet
|
104
|
+
return TRILOGY_OK;
|
105
|
+
}
|
106
|
+
|
107
|
+
// we didn't read a complete packet yet, return TRILOGY_AGAIN so the caller
|
108
|
+
// can retry
|
109
|
+
return TRILOGY_AGAIN;
|
110
|
+
}
|
111
|
+
|
112
|
+
static int begin_write(trilogy_conn_t *conn)
|
113
|
+
{
|
114
|
+
conn->packet_buffer_written = 0;
|
115
|
+
|
116
|
+
// perform a single write(2), if this does not end up writing the entire
|
117
|
+
// packet buffer, then we'll end up returning TRILOGY_AGAIN here and it'll be
|
118
|
+
// up to the caller to pump trilogy_flush_writes() until it returns TRILOGY_OK
|
119
|
+
return trilogy_flush_writes(conn);
|
120
|
+
}
|
121
|
+
|
122
|
+
int trilogy_init(trilogy_conn_t *conn)
|
123
|
+
{
|
124
|
+
int rc;
|
125
|
+
|
126
|
+
conn->affected_rows = 0;
|
127
|
+
conn->last_insert_id = 0;
|
128
|
+
conn->warning_count = 0;
|
129
|
+
conn->last_gtid_len = 0;
|
130
|
+
|
131
|
+
memset(conn->last_gtid, 0, TRILOGY_MAX_LAST_GTID_LEN);
|
132
|
+
conn->error_code = 0;
|
133
|
+
conn->error_message = NULL;
|
134
|
+
conn->error_message_len = 0;
|
135
|
+
|
136
|
+
conn->capabilities = 0;
|
137
|
+
conn->server_status = 0;
|
138
|
+
|
139
|
+
conn->socket = NULL;
|
140
|
+
|
141
|
+
conn->recv_buff_pos = 0;
|
142
|
+
conn->recv_buff_len = 0;
|
143
|
+
|
144
|
+
trilogy_packet_parser_init(&conn->packet_parser, &packet_parser_callbacks);
|
145
|
+
conn->packet_parser.user_data = &conn->packet_buffer;
|
146
|
+
|
147
|
+
CHECKED(trilogy_buffer_init(&conn->packet_buffer, TRILOGY_DEFAULT_BUF_SIZE));
|
148
|
+
|
149
|
+
return TRILOGY_OK;
|
150
|
+
}
|
151
|
+
|
152
|
+
int trilogy_flush_writes(trilogy_conn_t *conn)
|
153
|
+
{
|
154
|
+
void *ptr = conn->packet_buffer.buff + conn->packet_buffer_written;
|
155
|
+
size_t len = conn->packet_buffer.len - conn->packet_buffer_written;
|
156
|
+
|
157
|
+
ssize_t bytes = trilogy_sock_write(conn->socket, ptr, len);
|
158
|
+
|
159
|
+
if (bytes < 0) {
|
160
|
+
int rc = (int)bytes;
|
161
|
+
if (rc == TRILOGY_SYSERR) {
|
162
|
+
if (errno == EINTR || errno == EAGAIN) {
|
163
|
+
return TRILOGY_AGAIN;
|
164
|
+
}
|
165
|
+
|
166
|
+
if (errno == EPIPE) {
|
167
|
+
return TRILOGY_CLOSED_CONNECTION;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
return rc;
|
172
|
+
}
|
173
|
+
|
174
|
+
conn->packet_buffer_written += (size_t)bytes;
|
175
|
+
|
176
|
+
if (conn->packet_buffer_written < conn->packet_buffer.len) {
|
177
|
+
return TRILOGY_AGAIN;
|
178
|
+
}
|
179
|
+
|
180
|
+
return TRILOGY_OK;
|
181
|
+
}
|
182
|
+
|
183
|
+
static void set_error(trilogy_conn_t *conn, const trilogy_err_packet_t *packet)
|
184
|
+
{
|
185
|
+
conn->error_code = packet->error_code;
|
186
|
+
conn->error_message = packet->error_message;
|
187
|
+
conn->error_message_len = packet->error_message_len;
|
188
|
+
}
|
189
|
+
|
190
|
+
static int read_ok_packet(trilogy_conn_t *conn)
|
191
|
+
{
|
192
|
+
trilogy_ok_packet_t ok_packet;
|
193
|
+
|
194
|
+
int rc = trilogy_parse_ok_packet(conn->packet_buffer.buff, conn->packet_buffer.len, conn->capabilities, &ok_packet);
|
195
|
+
|
196
|
+
if (rc != TRILOGY_OK) {
|
197
|
+
return rc;
|
198
|
+
}
|
199
|
+
|
200
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
|
201
|
+
conn->warning_count = ok_packet.warning_count;
|
202
|
+
conn->server_status = ok_packet.status_flags;
|
203
|
+
}
|
204
|
+
|
205
|
+
conn->affected_rows = ok_packet.affected_rows;
|
206
|
+
conn->last_insert_id = ok_packet.last_insert_id;
|
207
|
+
|
208
|
+
if (ok_packet.last_gtid_len > 0 && ok_packet.last_gtid_len < TRILOGY_MAX_LAST_GTID_LEN) {
|
209
|
+
memcpy(conn->last_gtid, ok_packet.last_gtid, ok_packet.last_gtid_len);
|
210
|
+
conn->last_gtid_len = ok_packet.last_gtid_len;
|
211
|
+
}
|
212
|
+
|
213
|
+
return TRILOGY_OK;
|
214
|
+
}
|
215
|
+
|
216
|
+
static int read_err_packet(trilogy_conn_t *conn)
|
217
|
+
{
|
218
|
+
trilogy_err_packet_t err_packet;
|
219
|
+
|
220
|
+
int rc =
|
221
|
+
trilogy_parse_err_packet(conn->packet_buffer.buff, conn->packet_buffer.len, conn->capabilities, &err_packet);
|
222
|
+
|
223
|
+
if (rc != TRILOGY_OK) {
|
224
|
+
return rc;
|
225
|
+
}
|
226
|
+
|
227
|
+
set_error(conn, &err_packet);
|
228
|
+
|
229
|
+
return TRILOGY_ERR;
|
230
|
+
}
|
231
|
+
|
232
|
+
static int read_eof_packet(trilogy_conn_t *conn)
|
233
|
+
{
|
234
|
+
trilogy_eof_packet_t eof_packet;
|
235
|
+
|
236
|
+
int rc =
|
237
|
+
trilogy_parse_eof_packet(conn->packet_buffer.buff, conn->packet_buffer.len, conn->capabilities, &eof_packet);
|
238
|
+
|
239
|
+
if (rc != TRILOGY_OK) {
|
240
|
+
return rc;
|
241
|
+
}
|
242
|
+
|
243
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
|
244
|
+
conn->warning_count = eof_packet.warning_count;
|
245
|
+
conn->server_status = eof_packet.status_flags;
|
246
|
+
}
|
247
|
+
|
248
|
+
return TRILOGY_EOF;
|
249
|
+
}
|
250
|
+
|
251
|
+
static int read_auth_switch_packet(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
252
|
+
{
|
253
|
+
trilogy_auth_switch_request_packet_t auth_switch_packet;
|
254
|
+
|
255
|
+
int rc = trilogy_parse_auth_switch_request_packet(conn->packet_buffer.buff, conn->packet_buffer.len,
|
256
|
+
conn->capabilities, &auth_switch_packet);
|
257
|
+
|
258
|
+
if (rc != TRILOGY_OK) {
|
259
|
+
return rc;
|
260
|
+
}
|
261
|
+
|
262
|
+
if (strcmp("mysql_native_password", auth_switch_packet.auth_plugin) &&
|
263
|
+
strcmp("caching_sha2_password", auth_switch_packet.auth_plugin)) {
|
264
|
+
// Only support native password & caching sha2 password here.
|
265
|
+
return TRILOGY_PROTOCOL_VIOLATION;
|
266
|
+
}
|
267
|
+
|
268
|
+
memcpy(handshake->auth_plugin, auth_switch_packet.auth_plugin, sizeof(auth_switch_packet.auth_plugin));
|
269
|
+
memcpy(handshake->scramble, auth_switch_packet.scramble, sizeof(auth_switch_packet.scramble));
|
270
|
+
return TRILOGY_AUTH_SWITCH;
|
271
|
+
}
|
272
|
+
|
273
|
+
static int read_generic_response(trilogy_conn_t *conn)
|
274
|
+
{
|
275
|
+
int rc = read_packet(conn);
|
276
|
+
|
277
|
+
if (rc < 0) {
|
278
|
+
return rc;
|
279
|
+
}
|
280
|
+
|
281
|
+
switch (current_packet_type(conn)) {
|
282
|
+
case TRILOGY_PACKET_OK:
|
283
|
+
return read_ok_packet(conn);
|
284
|
+
|
285
|
+
case TRILOGY_PACKET_ERR:
|
286
|
+
return read_err_packet(conn);
|
287
|
+
|
288
|
+
default:
|
289
|
+
return TRILOGY_UNEXPECTED_PACKET;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
int trilogy_connect_send(trilogy_conn_t *conn, const trilogy_sockopt_t *opts)
|
294
|
+
{
|
295
|
+
trilogy_sock_t *sock = trilogy_sock_new(opts);
|
296
|
+
if (sock == NULL) {
|
297
|
+
return TRILOGY_ERR;
|
298
|
+
}
|
299
|
+
|
300
|
+
int rc = trilogy_sock_resolve(sock);
|
301
|
+
if (rc < 0) {
|
302
|
+
return rc;
|
303
|
+
}
|
304
|
+
|
305
|
+
return trilogy_connect_send_socket(conn, sock);
|
306
|
+
}
|
307
|
+
|
308
|
+
int trilogy_connect_send_socket(trilogy_conn_t *conn, trilogy_sock_t *sock)
|
309
|
+
{
|
310
|
+
int rc = trilogy_sock_connect(sock);
|
311
|
+
if (rc < 0)
|
312
|
+
return rc;
|
313
|
+
|
314
|
+
conn->socket = sock;
|
315
|
+
return TRILOGY_OK;
|
316
|
+
}
|
317
|
+
|
318
|
+
int trilogy_connect_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake_out)
|
319
|
+
{
|
320
|
+
// reset the sequence number with each connect recv attempt
|
321
|
+
conn->packet_parser.sequence_number = 0;
|
322
|
+
|
323
|
+
int rc = read_packet(conn);
|
324
|
+
|
325
|
+
if (rc < 0) {
|
326
|
+
return rc;
|
327
|
+
}
|
328
|
+
|
329
|
+
// In rare cases, the server will actually send an error packet as the
|
330
|
+
// initial packet instead of a handshake packet. For example, if there are
|
331
|
+
// too many connected clients already.
|
332
|
+
if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
|
333
|
+
return read_err_packet(conn);
|
334
|
+
}
|
335
|
+
|
336
|
+
rc = trilogy_parse_handshake_packet(conn->packet_buffer.buff, conn->packet_buffer.len, handshake_out);
|
337
|
+
|
338
|
+
if (rc < 0) {
|
339
|
+
return rc;
|
340
|
+
}
|
341
|
+
|
342
|
+
conn->capabilities = handshake_out->capabilities;
|
343
|
+
conn->server_status = handshake_out->server_status;
|
344
|
+
|
345
|
+
return TRILOGY_OK;
|
346
|
+
}
|
347
|
+
|
348
|
+
int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake)
|
349
|
+
{
|
350
|
+
trilogy_builder_t builder;
|
351
|
+
bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
|
352
|
+
|
353
|
+
int rc = begin_command_phase(&builder, conn, use_ssl ? 2 : 1);
|
354
|
+
|
355
|
+
if (rc < 0) {
|
356
|
+
return rc;
|
357
|
+
}
|
358
|
+
|
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, handshake->auth_plugin,
|
361
|
+
handshake->scramble, conn->socket->opts.flags);
|
362
|
+
|
363
|
+
if (rc < 0) {
|
364
|
+
return rc;
|
365
|
+
}
|
366
|
+
|
367
|
+
return begin_write(conn);
|
368
|
+
}
|
369
|
+
|
370
|
+
int trilogy_ssl_request_send(trilogy_conn_t *conn)
|
371
|
+
{
|
372
|
+
trilogy_builder_t builder;
|
373
|
+
|
374
|
+
int rc = begin_command_phase(&builder, conn, 1);
|
375
|
+
|
376
|
+
if (rc < 0) {
|
377
|
+
return rc;
|
378
|
+
}
|
379
|
+
|
380
|
+
conn->socket->opts.flags |= TRILOGY_CAPABILITIES_SSL;
|
381
|
+
rc = trilogy_build_ssl_request_packet(&builder, conn->socket->opts.flags);
|
382
|
+
|
383
|
+
if (rc < 0) {
|
384
|
+
return rc;
|
385
|
+
}
|
386
|
+
|
387
|
+
return begin_write(conn);
|
388
|
+
}
|
389
|
+
|
390
|
+
int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake)
|
391
|
+
{
|
392
|
+
trilogy_builder_t builder;
|
393
|
+
|
394
|
+
bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
|
395
|
+
int rc = begin_command_phase(&builder, conn, use_ssl ? 4 : 3);
|
396
|
+
|
397
|
+
if (rc < 0) {
|
398
|
+
return rc;
|
399
|
+
}
|
400
|
+
|
401
|
+
rc = trilogy_build_auth_switch_response_packet(&builder, conn->socket->opts.password,
|
402
|
+
conn->socket->opts.password_len, handshake->auth_plugin,
|
403
|
+
handshake->scramble);
|
404
|
+
|
405
|
+
if (rc < 0) {
|
406
|
+
return rc;
|
407
|
+
}
|
408
|
+
|
409
|
+
return begin_write(conn);
|
410
|
+
}
|
411
|
+
|
412
|
+
void trilogy_auth_clear_password(trilogy_conn_t *conn)
|
413
|
+
{
|
414
|
+
if (conn->socket->opts.password) {
|
415
|
+
memset(conn->socket->opts.password, 0, conn->socket->opts.password_len);
|
416
|
+
}
|
417
|
+
}
|
418
|
+
|
419
|
+
int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
420
|
+
{
|
421
|
+
int rc = read_packet(conn);
|
422
|
+
|
423
|
+
if (rc < 0) {
|
424
|
+
return rc;
|
425
|
+
}
|
426
|
+
|
427
|
+
switch (current_packet_type(conn)) {
|
428
|
+
case TRILOGY_PACKET_OK:
|
429
|
+
trilogy_auth_clear_password(conn);
|
430
|
+
return read_ok_packet(conn);
|
431
|
+
|
432
|
+
case TRILOGY_PACKET_ERR:
|
433
|
+
trilogy_auth_clear_password(conn);
|
434
|
+
return read_err_packet(conn);
|
435
|
+
|
436
|
+
case TRILOGY_PACKET_EOF:
|
437
|
+
// EOF is returned here if an auth switch is requested.
|
438
|
+
// We still need the password for the switch, it will be cleared
|
439
|
+
// in a follow up call to this function after the switch.
|
440
|
+
return read_auth_switch_packet(conn, handshake);
|
441
|
+
|
442
|
+
default:
|
443
|
+
trilogy_auth_clear_password(conn);
|
444
|
+
return TRILOGY_UNEXPECTED_PACKET;
|
445
|
+
}
|
446
|
+
|
447
|
+
return read_generic_response(conn);
|
448
|
+
}
|
449
|
+
|
450
|
+
int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_len)
|
451
|
+
{
|
452
|
+
trilogy_builder_t builder;
|
453
|
+
int err = begin_command_phase(&builder, conn, 0);
|
454
|
+
if (err < 0) {
|
455
|
+
return err;
|
456
|
+
}
|
457
|
+
|
458
|
+
err = trilogy_build_change_db_packet(&builder, name, name_len);
|
459
|
+
|
460
|
+
if (err < 0) {
|
461
|
+
return err;
|
462
|
+
}
|
463
|
+
|
464
|
+
return begin_write(conn);
|
465
|
+
}
|
466
|
+
|
467
|
+
int trilogy_change_db_recv(trilogy_conn_t *conn) { return read_generic_response(conn); }
|
468
|
+
|
469
|
+
int trilogy_ping_send(trilogy_conn_t *conn)
|
470
|
+
{
|
471
|
+
trilogy_builder_t builder;
|
472
|
+
int err = begin_command_phase(&builder, conn, 0);
|
473
|
+
if (err < 0) {
|
474
|
+
return err;
|
475
|
+
}
|
476
|
+
|
477
|
+
err = trilogy_build_ping_packet(&builder);
|
478
|
+
|
479
|
+
if (err < 0) {
|
480
|
+
return err;
|
481
|
+
}
|
482
|
+
|
483
|
+
return begin_write(conn);
|
484
|
+
}
|
485
|
+
|
486
|
+
int trilogy_ping_recv(trilogy_conn_t *conn) { return read_generic_response(conn); }
|
487
|
+
|
488
|
+
int trilogy_query_send(trilogy_conn_t *conn, const char *query, size_t query_len)
|
489
|
+
{
|
490
|
+
int err = 0;
|
491
|
+
|
492
|
+
trilogy_builder_t builder;
|
493
|
+
err = begin_command_phase(&builder, conn, 0);
|
494
|
+
if (err < 0) {
|
495
|
+
return err;
|
496
|
+
}
|
497
|
+
|
498
|
+
err = trilogy_build_query_packet(&builder, query, query_len);
|
499
|
+
if (err < 0) {
|
500
|
+
return err;
|
501
|
+
}
|
502
|
+
|
503
|
+
conn->packet_parser.sequence_number = builder.seq;
|
504
|
+
|
505
|
+
return begin_write(conn);
|
506
|
+
}
|
507
|
+
|
508
|
+
int trilogy_query_recv(trilogy_conn_t *conn, uint64_t *column_count_out)
|
509
|
+
{
|
510
|
+
int err = read_packet(conn);
|
511
|
+
|
512
|
+
if (err < 0) {
|
513
|
+
return err;
|
514
|
+
}
|
515
|
+
|
516
|
+
switch (current_packet_type(conn)) {
|
517
|
+
case TRILOGY_PACKET_OK:
|
518
|
+
return read_ok_packet(conn);
|
519
|
+
|
520
|
+
case TRILOGY_PACKET_ERR:
|
521
|
+
return read_err_packet(conn);
|
522
|
+
|
523
|
+
default: {
|
524
|
+
trilogy_result_packet_t result_packet;
|
525
|
+
err = trilogy_parse_result_packet(conn->packet_buffer.buff, conn->packet_buffer.len, &result_packet);
|
526
|
+
|
527
|
+
if (err < 0) {
|
528
|
+
return err;
|
529
|
+
}
|
530
|
+
|
531
|
+
conn->column_count = result_packet.column_count;
|
532
|
+
*column_count_out = result_packet.column_count;
|
533
|
+
conn->started_reading_rows = false;
|
534
|
+
|
535
|
+
return TRILOGY_HAVE_RESULTS;
|
536
|
+
}
|
537
|
+
}
|
538
|
+
}
|
539
|
+
|
540
|
+
int trilogy_read_column(trilogy_conn_t *conn, trilogy_column_t *column_out)
|
541
|
+
{
|
542
|
+
int err = read_packet(conn);
|
543
|
+
|
544
|
+
if (err < 0) {
|
545
|
+
return err;
|
546
|
+
}
|
547
|
+
|
548
|
+
return trilogy_parse_column_packet(conn->packet_buffer.buff, conn->packet_buffer.len, 0, column_out);
|
549
|
+
}
|
550
|
+
|
551
|
+
static int read_eof(trilogy_conn_t *conn)
|
552
|
+
{
|
553
|
+
int rc = read_packet(conn);
|
554
|
+
|
555
|
+
if (rc < 0) {
|
556
|
+
return rc;
|
557
|
+
}
|
558
|
+
|
559
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) {
|
560
|
+
return read_ok_packet(conn);
|
561
|
+
} else {
|
562
|
+
if ((rc = read_eof_packet(conn)) != TRILOGY_EOF) {
|
563
|
+
return rc;
|
564
|
+
}
|
565
|
+
|
566
|
+
return TRILOGY_OK;
|
567
|
+
}
|
568
|
+
}
|
569
|
+
|
570
|
+
int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
|
571
|
+
{
|
572
|
+
if (!conn->started_reading_rows) {
|
573
|
+
if ((conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF) == 0) {
|
574
|
+
// we need to skip over the EOF packet that arrives after the column
|
575
|
+
// packets
|
576
|
+
int rc = read_eof(conn);
|
577
|
+
|
578
|
+
if (rc < 0) {
|
579
|
+
return rc;
|
580
|
+
}
|
581
|
+
}
|
582
|
+
|
583
|
+
conn->started_reading_rows = true;
|
584
|
+
}
|
585
|
+
|
586
|
+
int rc = read_packet(conn);
|
587
|
+
|
588
|
+
if (rc < 0) {
|
589
|
+
return rc;
|
590
|
+
}
|
591
|
+
|
592
|
+
if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF && current_packet_type(conn) == TRILOGY_PACKET_EOF) {
|
593
|
+
if ((rc = read_ok_packet(conn)) != TRILOGY_OK) {
|
594
|
+
return rc;
|
595
|
+
}
|
596
|
+
|
597
|
+
return TRILOGY_EOF;
|
598
|
+
} else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
599
|
+
return read_eof_packet(conn);
|
600
|
+
} else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
|
601
|
+
return read_err_packet(conn);
|
602
|
+
} else {
|
603
|
+
return trilogy_parse_row_packet(conn->packet_buffer.buff, conn->packet_buffer.len, conn->column_count,
|
604
|
+
values_out);
|
605
|
+
}
|
606
|
+
}
|
607
|
+
|
608
|
+
int trilogy_drain_results(trilogy_conn_t *conn)
|
609
|
+
{
|
610
|
+
if (!conn->started_reading_rows) {
|
611
|
+
// we need to skip over the EOF packet that arrives after the column
|
612
|
+
// packets
|
613
|
+
int rc = read_eof(conn);
|
614
|
+
|
615
|
+
if (rc < 0) {
|
616
|
+
return rc;
|
617
|
+
}
|
618
|
+
|
619
|
+
conn->started_reading_rows = true;
|
620
|
+
}
|
621
|
+
|
622
|
+
while (1) {
|
623
|
+
int rc = read_packet(conn);
|
624
|
+
|
625
|
+
if (rc < 0) {
|
626
|
+
return rc;
|
627
|
+
}
|
628
|
+
|
629
|
+
if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
|
630
|
+
return TRILOGY_OK;
|
631
|
+
}
|
632
|
+
}
|
633
|
+
}
|
634
|
+
|
635
|
+
static uint8_t escape_lookup_table[256] = {
|
636
|
+
['"'] = '"', ['\0'] = '0', ['\''] = '\'', ['\\'] = '\\', ['\n'] = 'n', ['\r'] = 'r', [26] = 'Z',
|
637
|
+
};
|
638
|
+
|
639
|
+
int trilogy_escape(trilogy_conn_t *conn, const char *str, size_t len, const char **escaped_str_out,
|
640
|
+
size_t *escaped_len_out)
|
641
|
+
{
|
642
|
+
int rc;
|
643
|
+
|
644
|
+
trilogy_buffer_t *b = &conn->packet_buffer;
|
645
|
+
|
646
|
+
b->len = 0;
|
647
|
+
|
648
|
+
if (conn->server_status & TRILOGY_SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
|
649
|
+
for (size_t i = 0; i < len; i++) {
|
650
|
+
const uint8_t c = (uint8_t)str[i];
|
651
|
+
|
652
|
+
if (c == '\'') {
|
653
|
+
CHECKED(trilogy_buffer_putc(b, '\''));
|
654
|
+
CHECKED(trilogy_buffer_putc(b, '\''));
|
655
|
+
} else {
|
656
|
+
CHECKED(trilogy_buffer_putc(b, c));
|
657
|
+
}
|
658
|
+
}
|
659
|
+
} else {
|
660
|
+
for (size_t i = 0; i < len; i++) {
|
661
|
+
const uint8_t c = (uint8_t)str[i];
|
662
|
+
|
663
|
+
uint8_t escaped = escape_lookup_table[(uint8_t)c];
|
664
|
+
|
665
|
+
if (escaped) {
|
666
|
+
CHECKED(trilogy_buffer_putc(b, '\\'));
|
667
|
+
CHECKED(trilogy_buffer_putc(b, escaped));
|
668
|
+
} else {
|
669
|
+
CHECKED(trilogy_buffer_putc(b, c));
|
670
|
+
}
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
*escaped_str_out = (const char *)b->buff;
|
675
|
+
*escaped_len_out = b->len;
|
676
|
+
|
677
|
+
return TRILOGY_OK;
|
678
|
+
}
|
679
|
+
|
680
|
+
int trilogy_close_send(trilogy_conn_t *conn)
|
681
|
+
{
|
682
|
+
trilogy_builder_t builder;
|
683
|
+
int rc = begin_command_phase(&builder, conn, 0);
|
684
|
+
if (rc < 0) {
|
685
|
+
return rc;
|
686
|
+
}
|
687
|
+
|
688
|
+
rc = trilogy_build_quit_packet(&builder);
|
689
|
+
|
690
|
+
if (rc < 0) {
|
691
|
+
return rc;
|
692
|
+
}
|
693
|
+
|
694
|
+
return begin_write(conn);
|
695
|
+
}
|
696
|
+
|
697
|
+
int trilogy_close_recv(trilogy_conn_t *conn)
|
698
|
+
{
|
699
|
+
trilogy_sock_shutdown(conn->socket);
|
700
|
+
|
701
|
+
int rc = read_packet(conn);
|
702
|
+
|
703
|
+
switch (rc) {
|
704
|
+
case TRILOGY_CLOSED_CONNECTION:
|
705
|
+
return TRILOGY_OK;
|
706
|
+
|
707
|
+
case TRILOGY_OK:
|
708
|
+
// we need to handle TRILOGY_OK specially and translate it into
|
709
|
+
// TRILOGY_PROTOCOL_VIOLATION so we don't end up returning TRILOGY_OK
|
710
|
+
// in the default case
|
711
|
+
return TRILOGY_PROTOCOL_VIOLATION;
|
712
|
+
|
713
|
+
default:
|
714
|
+
return rc;
|
715
|
+
}
|
716
|
+
}
|
717
|
+
|
718
|
+
void trilogy_free(trilogy_conn_t *conn)
|
719
|
+
{
|
720
|
+
if (conn->socket != NULL) {
|
721
|
+
trilogy_sock_close(conn->socket);
|
722
|
+
conn->socket = NULL;
|
723
|
+
}
|
724
|
+
|
725
|
+
trilogy_buffer_free(&conn->packet_buffer);
|
726
|
+
}
|
727
|
+
|
728
|
+
#undef CHECKED
|