trilogy 2.2.0 → 2.4.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.
@@ -299,6 +299,50 @@ int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_l
299
299
  */
300
300
  int trilogy_change_db_recv(trilogy_conn_t *conn);
301
301
 
302
+ /* trilogy_set_option_send - Send a set option command to the server. This
303
+ * will change server capabilities based on the option selected.
304
+ *
305
+ * This should only be called while the connection is ready for commands.
306
+ *
307
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
308
+ * trilogy_conn_t is undefined.
309
+ * option - The server option to send.
310
+ *
311
+ * Return values:
312
+ * TRILOGY_OK - The change database command was successfully sent to the
313
+ * server.
314
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
315
+ * for writeability using `conn->sock`. Then call
316
+ * trilogy_flush_writes.
317
+ * TRILOGY_SYSERR - A system error occurred, check errno.
318
+ */
319
+ int trilogy_set_option_send(trilogy_conn_t *conn, const uint16_t option);
320
+
321
+ /* trilogy_set_option_recv - Read the set option command response from the
322
+ * server.
323
+ *
324
+ * This should be called after all data written by trilogy_set_option_send is
325
+ * flushed to the network. Calling this at any other time during the connection
326
+ * lifecycle is undefined.
327
+ *
328
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
329
+ * undefined.
330
+ *
331
+ * Return values:
332
+ * TRILOGY_OK - The set option command was successfully
333
+ * sent to the server.
334
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The
335
+ * caller should wait for readability using
336
+ * `conn->sock`. Then call this function until
337
+ * it returns a different value.
338
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
339
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
340
+ * packet.
341
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
342
+ * TRILOGY_SYSERR - A system error occurred, check errno.
343
+ */
344
+ int trilogy_set_option_recv(trilogy_conn_t *conn);
345
+
302
346
  /* trilogy_query_send - Send a query command to the server.
303
347
  *
304
348
  * This should only be called while the connection is ready for commands.
@@ -543,4 +587,18 @@ int trilogy_close_recv(trilogy_conn_t *conn);
543
587
  */
544
588
  void trilogy_free(trilogy_conn_t *conn);
545
589
 
590
+ /* trilogy_free - Discard the connection and free any internal buffers.
591
+ *
592
+ * The server won't be notified that connection was closed. This is useful to
593
+ * silently close connections that were inherited after forking without disrupting
594
+ * the parent's process connections.
595
+ *
596
+ * conn - A pre-initialized trilogy_conn_t pointer.
597
+ *
598
+ * Return values:
599
+ * TRILOGY_OK - The connection was successfuly discarded and freed.
600
+ * TRILOGY_SYSERR - A system error occurred, check errno. The connection wasn't freed.
601
+ */
602
+ int trilogy_discard(trilogy_conn_t *conn);
603
+
546
604
  #endif
@@ -90,16 +90,14 @@
90
90
  * From client: the client is interactive. \
91
91
  */ \
92
92
  XX(TRILOGY_CAPABILITIES_INTERACTIVE, 0x00000400) \
93
- /* Not implemented. \
94
- * \
95
- * From server: the server supports ssl. \
93
+ /* From server: the server supports ssl. \
96
94
  * \
97
95
  * From client: tells the server it should switch to an ssl connection. \
98
96
  */ \
99
97
  XX(TRILOGY_CAPABILITIES_SSL, 0x00000800) \
100
- /* Not used. \
98
+ /* From server: the server supports transactions and is capable of reporting transaction status. \
101
99
  * \
102
- * This is assumed for the 4.1+ protocol. \
100
+ * From client: the client is aware of servers that support transactions. \
103
101
  */ \
104
102
  XX(TRILOGY_CAPABILITIES_TRANSACTIONS, 0x00002000) \
105
103
  /* Not used. \
@@ -112,27 +110,21 @@
112
110
  * scheme. This will always be set. \
113
111
  */ \
114
112
  XX(TRILOGY_CAPABILITIES_SECURE_CONNECTION, 0x00008000) \
115
- /* Not implemented. \
116
- * \
117
- * From server: the server can handle multiple statements per \
113
+ /* From server: the server can handle multiple statements per \
118
114
  * query/prepared statement. \
119
115
  * \
120
116
  * From client: tells the server it may send multiple statements per \
121
117
  * query/ prepared statement. \
122
118
  */ \
123
119
  XX(TRILOGY_CAPABILITIES_MULTI_STATEMENTS, 0x00010000) \
124
- /* Not implemented. \
125
- * \
126
- * From server: the server is capable of sending multiple result sets from \
120
+ /* From server: the server is capable of sending multiple result sets from \
127
121
  * a query. \
128
122
  * \
129
123
  * From client: tells the server it's capable of handling multiple result \
130
124
  * sets from a query. \
131
125
  */ \
132
126
  XX(TRILOGY_CAPABILITIES_MULTI_RESULTS, 0x00020000) \
133
- /* Not implemented. \
134
- * \
135
- * From server: the server is capable of sending multiple result sets from \
127
+ /* From server: the server is capable of sending multiple result sets from \
136
128
  * a prepared statement. \
137
129
  * \
138
130
  * From client: tells the server it's capable of handling multiple result \
@@ -193,7 +185,8 @@ typedef enum {
193
185
  /* A convenience bitmask with common client capabilities set. */
194
186
  TRILOGY_CAPABILITIES_CLIENT = (TRILOGY_CAPABILITIES_PROTOCOL_41 | TRILOGY_CAPABILITIES_SECURE_CONNECTION |
195
187
  TRILOGY_CAPABILITIES_DEPRECATE_EOF | TRILOGY_CAPABILITIES_SESSION_TRACK |
196
- TRILOGY_CAPABILITIES_PLUGIN_AUTH | TRILOGY_CAPABILITIES_TRANSACTIONS)
188
+ TRILOGY_CAPABILITIES_PLUGIN_AUTH | TRILOGY_CAPABILITIES_TRANSACTIONS |
189
+ TRILOGY_CAPABILITIES_MULTI_RESULTS)
197
190
  } TRILOGY_CAPABILITIES_t;
198
191
 
199
192
  #define TRILOGY_SERVER_STATUS(XX) \
@@ -399,22 +392,34 @@ typedef enum {
399
392
  #undef XX
400
393
  } TRILOGY_SESSION_TRACK_TYPE_t;
401
394
 
395
+ #define TRILOGY_SET_SERVER_OPTION(XX) \
396
+ XX(TRILOGY_SET_SERVER_MULTI_STATEMENTS_ON, 0x00) \
397
+ XX(TRILOGY_SET_SERVER_MULTI_STATEMENTS_OFF, 0x01) \
398
+
399
+ typedef enum {
400
+ #define XX(name, code) name = code,
401
+ TRILOGY_SET_SERVER_OPTION(XX)
402
+ #undef XX
403
+ } TRILOGY_SET_SERVER_OPTION_TYPE_t;
404
+
402
405
  /* trilogy_build_auth_packet - Build a handshake response (or authentication)
403
406
  * packet.
404
407
  *
405
408
  * This should be sent in response to the initial handshake packet the server
406
409
  * sends upon connection.
407
410
  *
408
- * builder - A pointer to a pre-initialized trilogy_builder_t.
409
- * user - The username to use for authentication. Must be a C-string.
410
- * pass - The password to use for authentication. Optional, and can be NULL.
411
- * pass_len - The length of password in bytes.
412
- * auth_plugin - Plugin authentication mechanism that the server requested.
413
- * scramble - The scramble value the server sent in the initial handshake.
414
- * flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
415
- * The TRILOGY_CAPABILITIES_PROTOCOL_41 and
416
- * TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
417
- * internally.
411
+ * builder - A pointer to a pre-initialized trilogy_builder_t.
412
+ * user - The username to use for authentication. Must be a C-string.
413
+ * pass - The password to use for authentication. Optional, and can be NULL.
414
+ * pass_len - The length of password in bytes.
415
+ * database - The initial database to connect to. Optional, and can be NULL.
416
+ * client_encoding - The charset to use for the connection.
417
+ * auth_plugin - Plugin authentication mechanism that the server requested.
418
+ * scramble - The scramble value the server sent in the initial handshake.
419
+ * flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
420
+ * The TRILOGY_CAPABILITIES_PROTOCOL_41 and
421
+ * TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
422
+ * internally.
418
423
  *
419
424
  * Return values:
420
425
  * TRILOGY_OK - The packet was successfully built and written to the
@@ -422,8 +427,8 @@ typedef enum {
422
427
  * TRILOGY_SYSERR - A system error occurred, check errno.
423
428
  */
424
429
  int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
425
- const char *database, const char *auth_plugin, const char *scramble,
426
- TRILOGY_CAPABILITIES_t flags);
430
+ const char *database, TRILOGY_CHARSET_t client_encoding, const char *auth_plugin,
431
+ const char *scramble, TRILOGY_CAPABILITIES_t flags);
427
432
 
428
433
  /* trilogy_build_auth_switch_response_packet - Build a response for when
429
434
  * authentication switching it requested.
@@ -449,7 +454,7 @@ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const
449
454
  * command will change the default database for the connection.
450
455
  *
451
456
  * builder - A pointer to a pre-initialized trilogy_builder_t.
452
- * name - The name of the databaset to set as the default.
457
+ * name - The name of the database to set as the default.
453
458
  * name_len - The length of name in bytes.
454
459
  *
455
460
  * Return values:
@@ -459,6 +464,20 @@ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const
459
464
  */
460
465
  int trilogy_build_change_db_packet(trilogy_builder_t *builder, const char *name, size_t name_len);
461
466
 
467
+ /* trilogy_build_set_option_packet - Build a set option command packet. This
468
+ * command will enable/disable server capabilities for the connection. Options
469
+ * must be one of `enum_mysql_set_option`.
470
+ *
471
+ * builder - A pointer to a pre-initialized trilogy_builder_t.
472
+ * option - An integer corresponding to the operation to perform.
473
+ *
474
+ * Return values:
475
+ * TRILOGY_OK - The packet was successfully built and written to the
476
+ * builder's internal buffer.
477
+ * TRILOGY_SYSERR - A system error occurred, check errno.
478
+ */
479
+ int trilogy_build_set_option_packet(trilogy_builder_t *builder, const uint16_t option);
480
+
462
481
  /* trilogy_build_ping_packet - Build a ping command packet.
463
482
  *
464
483
  * builder - A pointer to a pre-initialized trilogy_builder_t.
@@ -499,19 +518,21 @@ int trilogy_build_quit_packet(trilogy_builder_t *builder);
499
518
  * sends upon connection, where an auth packet would normally be sent. A regular
500
519
  * auth packet is to be sent after the SSL handshake completes.
501
520
  *
502
- * builder - A pointer to a pre-initialized trilogy_builder_t.
503
- * flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
504
- * The TRILOGY_CAPABILITIES_PROTOCOL_41 and
505
- * TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
506
- * internally.
507
- * The TRILOGY_CAPABILITIES_SSL flag will also be set.
521
+ * builder - A pointer to a pre-initialized trilogy_builder_t.
522
+ * flags - Bitmask of TRILOGY_CAPABILITIES_t flags.
523
+ * The TRILOGY_CAPABILITIES_PROTOCOL_41 and
524
+ * TRILOGY_CAPABILITIES_SECURE_CONNECTION flags will always be set
525
+ * internally.
526
+ * The TRILOGY_CAPABILITIES_SSL flag will also be set.
527
+ * client_encoding - The charset to use for the connection.
508
528
  *
509
529
  * Return values:
510
530
  * TRILOGY_OK - The packet was successfully built and written to the
511
531
  * builder's internal buffer.
512
532
  * TRILOGY_SYSERR - A system error occurred, check errno.
513
533
  */
514
- int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags);
534
+ int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags,
535
+ TRILOGY_CHARSET_t client_encoding);
515
536
 
516
537
  #define TRILOGY_SERVER_VERSION_SIZE 32
517
538
 
@@ -41,6 +41,7 @@ typedef struct {
41
41
  char *username;
42
42
  char *password;
43
43
  size_t password_len;
44
+ uint8_t encoding;
44
45
 
45
46
  trilogy_ssl_mode_t ssl_mode;
46
47
  trilogy_tls_version_t tls_min_version;
@@ -107,5 +108,6 @@ static inline int trilogy_sock_fd(trilogy_sock_t *sock) { return sock->fd_cb(soc
107
108
  trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts);
108
109
  int trilogy_sock_resolve(trilogy_sock_t *raw);
109
110
  int trilogy_sock_upgrade_ssl(trilogy_sock_t *raw);
111
+ int trilogy_sock_discard(trilogy_sock_t *sock);
110
112
 
111
113
  #endif
@@ -139,6 +139,29 @@ int trilogy_change_db(trilogy_conn_t *conn, const char *name, size_t name_len)
139
139
  }
140
140
  }
141
141
 
142
+ int trilogy_set_option(trilogy_conn_t *conn, const uint16_t option)
143
+ {
144
+ int rc = trilogy_set_option_send(conn, option);
145
+
146
+ if (rc == TRILOGY_AGAIN) {
147
+ rc = flush_full(conn);
148
+ }
149
+
150
+ if (rc < 0) {
151
+ return rc;
152
+ }
153
+
154
+ while (1) {
155
+ rc = trilogy_set_option_recv(conn);
156
+
157
+ if (rc != TRILOGY_AGAIN) {
158
+ return rc;
159
+ }
160
+
161
+ CHECKED(trilogy_sock_wait_read(conn->socket));
162
+ }
163
+ }
164
+
142
165
  int trilogy_ping(trilogy_conn_t *conn)
143
166
  {
144
167
  int rc = trilogy_ping_send(conn);
@@ -357,8 +357,9 @@ int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake
357
357
  }
358
358
 
359
359
  rc = trilogy_build_auth_packet(&builder, conn->socket->opts.username, conn->socket->opts.password,
360
- conn->socket->opts.password_len, conn->socket->opts.database, handshake->auth_plugin,
361
- handshake->scramble, conn->socket->opts.flags);
360
+ conn->socket->opts.password_len, conn->socket->opts.database,
361
+ conn->socket->opts.encoding, handshake->auth_plugin, handshake->scramble,
362
+ conn->socket->opts.flags);
362
363
 
363
364
  if (rc < 0) {
364
365
  return rc;
@@ -378,7 +379,7 @@ int trilogy_ssl_request_send(trilogy_conn_t *conn)
378
379
  }
379
380
 
380
381
  conn->socket->opts.flags |= TRILOGY_CAPABILITIES_SSL;
381
- rc = trilogy_build_ssl_request_packet(&builder, conn->socket->opts.flags);
382
+ rc = trilogy_build_ssl_request_packet(&builder, conn->socket->opts.flags, conn->socket->opts.encoding);
382
383
 
383
384
  if (rc < 0) {
384
385
  return rc;
@@ -466,6 +467,44 @@ int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_l
466
467
 
467
468
  int trilogy_change_db_recv(trilogy_conn_t *conn) { return read_generic_response(conn); }
468
469
 
470
+ int trilogy_set_option_send(trilogy_conn_t *conn, const uint16_t option)
471
+ {
472
+ trilogy_builder_t builder;
473
+ int err = begin_command_phase(&builder, conn, 0);
474
+ if (err < 0) {
475
+ return err;
476
+ }
477
+
478
+ err = trilogy_build_set_option_packet(&builder, option);
479
+
480
+ if (err < 0) {
481
+ return err;
482
+ }
483
+
484
+ return begin_write(conn);
485
+ }
486
+
487
+ int trilogy_set_option_recv(trilogy_conn_t *conn) {
488
+ int rc = read_packet(conn);
489
+
490
+ if (rc < 0) {
491
+ return rc;
492
+ }
493
+
494
+ switch (current_packet_type(conn)) {
495
+ case TRILOGY_PACKET_OK:
496
+ case TRILOGY_PACKET_EOF: // COM_SET_OPTION returns an EOF packet, but it should be treated as an OK packet.
497
+ return read_ok_packet(conn);
498
+
499
+ case TRILOGY_PACKET_ERR:
500
+ return read_err_packet(conn);
501
+
502
+ default:
503
+ return TRILOGY_UNEXPECTED_PACKET;
504
+ }
505
+ }
506
+
507
+
469
508
  int trilogy_ping_send(trilogy_conn_t *conn)
470
509
  {
471
510
  trilogy_builder_t builder;
@@ -725,4 +764,13 @@ void trilogy_free(trilogy_conn_t *conn)
725
764
  trilogy_buffer_free(&conn->packet_buffer);
726
765
  }
727
766
 
767
+ int trilogy_discard(trilogy_conn_t *conn)
768
+ {
769
+ int rc = trilogy_sock_discard(conn->socket);
770
+ if (rc == TRILOGY_OK) {
771
+ trilogy_free(conn);
772
+ }
773
+ return rc;
774
+ }
775
+
728
776
  #undef CHECKED
@@ -10,6 +10,7 @@
10
10
  #define TRILOGY_CMD_CHANGE_DB 0x02
11
11
  #define TRILOGY_CMD_QUERY 0x03
12
12
  #define TRILOGY_CMD_PING 0x0e
13
+ #define TRILOGY_CMD_SET_OPTION 0x1b
13
14
 
14
15
  #define SCRAMBLE_LEN 20
15
16
 
@@ -493,8 +494,8 @@ static void trilogy_pack_scramble_sha2_hash(const char *scramble, const char *pa
493
494
  }
494
495
 
495
496
  int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
496
- const char *database, const char *auth_plugin, const char *scramble,
497
- TRILOGY_CAPABILITIES_t flags)
497
+ const char *database, TRILOGY_CHARSET_t client_encoding, const char *auth_plugin,
498
+ const char *scramble, TRILOGY_CAPABILITIES_t flags)
498
499
  {
499
500
  int rc = TRILOGY_OK;
500
501
 
@@ -506,8 +507,6 @@ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, cons
506
507
 
507
508
  uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
508
509
 
509
- uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
510
-
511
510
  unsigned int auth_response_len = 0;
512
511
  uint8_t auth_response[EVP_MAX_MD_SIZE];
513
512
 
@@ -646,12 +645,28 @@ fail:
646
645
  return rc;
647
646
  }
648
647
 
649
- int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags)
648
+ int trilogy_build_set_option_packet(trilogy_builder_t *builder, const uint16_t option)
649
+ {
650
+ int rc = TRILOGY_OK;
651
+
652
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_SET_OPTION));
653
+ CHECKED(trilogy_builder_write_uint16(builder, option));
654
+
655
+ trilogy_builder_finalize(builder);
656
+
657
+ return TRILOGY_OK;
658
+
659
+ fail:
660
+ return rc;
661
+ }
662
+
663
+
664
+ int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags,
665
+ TRILOGY_CHARSET_t client_encoding)
650
666
  {
651
667
  static const char zeroes[23] = {0};
652
668
 
653
669
  const uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
654
- const uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
655
670
  const uint32_t capabilities = flags | TRILOGY_CAPABILITIES_CLIENT | TRILOGY_CAPABILITIES_SSL;
656
671
 
657
672
  int rc = TRILOGY_OK;
@@ -621,3 +621,28 @@ fail:
621
621
  sock->ssl = NULL;
622
622
  return TRILOGY_OPENSSL_ERR;
623
623
  }
624
+
625
+ int trilogy_sock_discard(trilogy_sock_t *_sock)
626
+ {
627
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
628
+
629
+ if (sock->fd < 0) {
630
+ return TRILOGY_OK;
631
+ }
632
+
633
+ int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
634
+ if (null_fd < 0) {
635
+ return TRILOGY_SYSERR;
636
+ }
637
+
638
+ if (dup2(null_fd, sock->fd) < 0) {
639
+ close(null_fd);
640
+ return TRILOGY_SYSERR;
641
+ }
642
+
643
+ if (close(null_fd) < 0) {
644
+ return TRILOGY_SYSERR;
645
+ }
646
+
647
+ return TRILOGY_OK;
648
+ }
@@ -9,6 +9,7 @@
9
9
  #define TRILOGY_FLAGS_CAST_BOOLEANS 2
10
10
  #define TRILOGY_FLAGS_LOCAL_TIMEZONE 4
11
11
  #define TRILOGY_FLAGS_FLATTEN_ROWS 8
12
+ #define TRILOGY_FLAGS_CAST_ALL_DECIMALS_TO_BIGDECIMALS 16
12
13
  #define TRILOGY_FLAGS_DEFAULT (TRILOGY_FLAGS_CAST)
13
14
 
14
15
  struct rb_trilogy_cast_options {
@@ -16,6 +17,7 @@ struct rb_trilogy_cast_options {
16
17
  bool cast_booleans;
17
18
  bool database_local_time;
18
19
  bool flatten_rows;
20
+ bool cast_decimals_to_bigdecimals;
19
21
  };
20
22
 
21
23
  struct column_info {
@@ -23,9 +25,10 @@ struct column_info {
23
25
  TRILOGY_CHARSET_t charset;
24
26
  uint32_t len;
25
27
  uint16_t flags;
28
+ uint8_t decimals;
26
29
  };
27
30
 
28
- extern VALUE rb_cTrilogyError;
31
+ extern VALUE Trilogy_CastError;
29
32
 
30
33
  VALUE
31
34
  rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *column,
@@ -1,3 +1,3 @@
1
1
  class Trilogy
2
- VERSION = "2.2.0"
2
+ VERSION = "2.4.0"
3
3
  end