trilogy_w_prepared_statements 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +80 -0
  4. data/Rakefile +22 -0
  5. data/ext/trilogy-ruby/cast.c +277 -0
  6. data/ext/trilogy-ruby/cext.c +1048 -0
  7. data/ext/trilogy-ruby/extconf.rb +17 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +281 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +165 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +760 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +44 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +1014 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +216 -0
  17. data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
  18. data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
  19. data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
  20. data/ext/trilogy-ruby/inc/trilogy.h +8 -0
  21. data/ext/trilogy-ruby/src/blocking.c +358 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +236 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +903 -0
  26. data/ext/trilogy-ruby/src/error.c +17 -0
  27. data/ext/trilogy-ruby/src/packet_parser.c +140 -0
  28. data/ext/trilogy-ruby/src/protocol.c +1175 -0
  29. data/ext/trilogy-ruby/src/reader.c +282 -0
  30. data/ext/trilogy-ruby/src/socket.c +623 -0
  31. data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
  32. data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
  33. data/ext/trilogy-ruby/trilogy-ruby.h +37 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +107 -0
@@ -0,0 +1,903 @@
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
+ int trilogy_stmt_prepare_send(trilogy_conn_t *conn, const char *stmt, size_t stmt_len)
729
+ {
730
+ trilogy_builder_t builder;
731
+ int err = begin_command_phase(&builder, conn, 0);
732
+ if (err < 0) {
733
+ return err;
734
+ }
735
+
736
+ err = trilogy_build_stmt_prepare_packet(&builder, stmt, stmt_len);
737
+ if (err < 0) {
738
+ return err;
739
+ }
740
+
741
+ return begin_write(conn);
742
+ }
743
+
744
+ int trilogy_stmt_prepare_recv(trilogy_conn_t *conn, trilogy_stmt_t *stmt_out)
745
+ {
746
+ int err = read_packet(conn);
747
+
748
+ if (err < 0) {
749
+ return err;
750
+ }
751
+
752
+ switch (current_packet_type(conn)) {
753
+ case TRILOGY_PACKET_OK: {
754
+ err = trilogy_parse_stmt_ok_packet(conn->packet_buffer.buff, conn->packet_buffer.len, stmt_out);
755
+
756
+ if (err < 0) {
757
+ return err;
758
+ }
759
+
760
+ conn->warning_count = stmt_out->warning_count;
761
+
762
+ return TRILOGY_OK;
763
+ }
764
+
765
+ case TRILOGY_PACKET_ERR:
766
+ return read_err_packet(conn);
767
+
768
+ default:
769
+ return TRILOGY_UNEXPECTED_PACKET;
770
+ }
771
+ }
772
+
773
+ int trilogy_stmt_execute_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint8_t flags, trilogy_binary_value_t *binds)
774
+ {
775
+ trilogy_builder_t builder;
776
+ int err = begin_command_phase(&builder, conn, 0);
777
+ if (err < 0) {
778
+ return err;
779
+ }
780
+
781
+ err = trilogy_build_stmt_execute_packet(&builder, stmt->id, flags, binds, stmt->parameter_count);
782
+
783
+ if (err < 0) {
784
+ return err;
785
+ }
786
+
787
+ conn->packet_parser.sequence_number = builder.seq;
788
+
789
+ return begin_write(conn);
790
+ }
791
+
792
+ int trilogy_stmt_execute_recv(trilogy_conn_t *conn, uint64_t *column_count_out)
793
+ {
794
+ int err = read_packet(conn);
795
+
796
+ if (err < 0) {
797
+ return err;
798
+ }
799
+
800
+ switch (current_packet_type(conn)) {
801
+ case TRILOGY_PACKET_OK:
802
+ return read_ok_packet(conn);
803
+
804
+ case TRILOGY_PACKET_ERR:
805
+ return read_err_packet(conn);
806
+
807
+ default: {
808
+ trilogy_result_packet_t result_packet;
809
+ err = trilogy_parse_result_packet(conn->packet_buffer.buff, conn->packet_buffer.len, &result_packet);
810
+
811
+ if (err < 0) {
812
+ return err;
813
+ }
814
+
815
+ conn->column_count = result_packet.column_count;
816
+ *column_count_out = result_packet.column_count;
817
+
818
+ return TRILOGY_OK;
819
+ }
820
+ }
821
+ }
822
+
823
+ int trilogy_stmt_bind_data_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint16_t param_num, uint8_t *data,
824
+ size_t data_len)
825
+ {
826
+ trilogy_builder_t builder;
827
+ int err = begin_command_phase(&builder, conn, 0);
828
+ if (err < 0) {
829
+ return err;
830
+ }
831
+
832
+ err = trilogy_build_stmt_bind_data_packet(&builder, stmt->id, param_num, data, data_len);
833
+
834
+ if (err < 0) {
835
+ return err;
836
+ }
837
+
838
+ return begin_write(conn);
839
+ }
840
+
841
+ int trilogy_stmt_read_row(trilogy_conn_t *conn, trilogy_stmt_t *stmt, trilogy_column_packet_t *columns,
842
+ trilogy_binary_value_t *values_out)
843
+ {
844
+ int err = read_packet(conn);
845
+
846
+ if (err < 0) {
847
+ return err;
848
+ }
849
+
850
+ if (conn->capabilities & TRILOGY_CAPABILITIES_DEPRECATE_EOF && current_packet_type(conn) == TRILOGY_PACKET_EOF) {
851
+ if ((err = read_ok_packet(conn)) != TRILOGY_OK) {
852
+ return err;
853
+ }
854
+
855
+ return TRILOGY_EOF;
856
+ } else if (current_packet_type(conn) == TRILOGY_PACKET_EOF && conn->packet_buffer.len < 9) {
857
+ return read_eof_packet(conn);
858
+ } else if (current_packet_type(conn) == TRILOGY_PACKET_ERR) {
859
+ return read_err_packet(conn);
860
+ } else {
861
+ return trilogy_parse_stmt_row_packet(conn->packet_buffer.buff, conn->packet_buffer.len, columns,
862
+ stmt->column_count, values_out);
863
+ }
864
+ }
865
+
866
+ int trilogy_stmt_reset_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt)
867
+ {
868
+ trilogy_builder_t builder;
869
+ int err = begin_command_phase(&builder, conn, 0);
870
+ if (err < 0) {
871
+ return err;
872
+ }
873
+
874
+ err = trilogy_build_stmt_reset_packet(&builder, stmt->id);
875
+ if (err < 0) {
876
+ return err;
877
+ }
878
+
879
+ return begin_write(conn);
880
+ }
881
+
882
+ int trilogy_stmt_reset_recv(trilogy_conn_t *conn) {
883
+ return read_generic_response(conn);
884
+ }
885
+
886
+ int trilogy_stmt_close_send(trilogy_conn_t *conn, trilogy_stmt_t *stmt)
887
+ {
888
+ trilogy_builder_t builder;
889
+ int err = begin_command_phase(&builder, conn, 0);
890
+ if (err < 0) {
891
+ return err;
892
+ }
893
+
894
+ err = trilogy_build_stmt_close_packet(&builder, stmt->id);
895
+
896
+ if (err < 0) {
897
+ return err;
898
+ }
899
+
900
+ return begin_write(conn);
901
+ }
902
+
903
+ #undef CHECKED