trilogy 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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