trilogy 2.4.0 → 2.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9c5df97a7642030f5c79167a0ff54ab25f500e38555b0303b9755f4102b0b17
4
- data.tar.gz: a67ea6052ca5d2346a5b7cb72f976c6c6a445361365e7bc3f343a54cd43151dd
3
+ metadata.gz: 0730bbbdae7e8eab195c4ad745e223bcd55fe6299f98cb324c88beea15ebdc5e
4
+ data.tar.gz: 7779f268cbfae85bf5575f680ebff9fee6d22b78bb5d3d315ba664969ab9618a
5
5
  SHA512:
6
- metadata.gz: 8d356765239b247f1902582abfb7a724eee0b2b18a3e8e0eabe71db196555bf5749192f259dba8c65f8a0945106df4413f328abeef8241cb3517495725dedabc
7
- data.tar.gz: c77e07b1a5e423d1ed7065a613feee4cd038be3606f519f7dc2fbbe87b389cf9d1fd4cc41993023060b504c40f12f85f8e75c688e1b4c418535c8891c192f26f
6
+ metadata.gz: 42c81e496210cfc0538ef1dd9f4f7c34e2ce94de45e5bcfe4c5815839c463a6b3ae78af529b88c63a670b3cd2035a6b931ef76fdfe1ec508f6b7851858b664d2
7
+ data.tar.gz: ad05962a8a47cea68ab66188badf405fe96342587bd86d91faf43dd028dc641949ea58d9a6d25547e820c4700c6cd9548d70a2494f0a215b08bb8a61c9c920c8
data/README.md CHANGED
@@ -34,13 +34,22 @@ if client.ping
34
34
  result.each_hash do |user|
35
35
  p user
36
36
  end
37
+ end
38
+ ```
37
39
 
38
- # Multi-statement
40
+ ### Processing multiple result sets
39
41
 
40
- results = []
41
- results << client.query("SELECT name FROM users WHERE id = 1; SELECT name FROM users WHERE id = 2")
42
- results << client.next_result while client.more_results_exist?
43
- end
42
+ In order to send and receive multiple result sets, pass the `multi_statement` option when connecting.
43
+ `Trilogy#more_results_exist?` will return true if more results exist, false if no more results exist, or raise
44
+ an error if the respective query errored. `Trilogy#next_result` will retrieve the next result set, or return nil
45
+ if no more results exist.
46
+
47
+ ``` ruby
48
+ client = Trilogy.new(host: "127.0.0.1", port: 3306, username: "root", read_timeout: 2, multi_statement: true)
49
+
50
+ results = []
51
+ results << client.query("SELECT name FROM users WHERE id = 1; SELECT name FROM users WHERE id = 2")
52
+ results << client.next_result while client.more_results_exist?
44
53
  ```
45
54
 
46
55
  ## Building
data/Rakefile CHANGED
@@ -8,6 +8,12 @@ Rake::ExtensionTask.new do |ext|
8
8
  ext.lib_dir = "lib/trilogy"
9
9
  end
10
10
 
11
+ # When any of the parent library's files change, we need to re-run extconf
12
+ vendored_c_lib = FileList["ext/trilogy-ruby/src/**/*.c", "ext/trilogy-ruby/inc/**/*.h"]
13
+ if extconf_task = Rake.application.tasks.find { |t| t.name =~ /Makefile/ }
14
+ task extconf_task => vendored_c_lib
15
+ end
16
+
11
17
  Rake::TestTask.new do |t|
12
18
  t.libs << "test"
13
19
  t.test_files = FileList['test/*_test.rb']
@@ -233,10 +233,6 @@ rb_trilogy_cast_value(const trilogy_value_t *value, const struct column_info *co
233
233
  return Qnil;
234
234
  }
235
235
 
236
- if (hour == 0 && min == 0 && sec == 0) {
237
- return Qnil;
238
- }
239
-
240
236
  // pad out msec_char with zeroes at the end as it could be at any
241
237
  // level of precision
242
238
  for (size_t i = strlen(msec_char); i < sizeof(msec_char) - 1; i++) {
@@ -15,8 +15,6 @@
15
15
 
16
16
  #include "trilogy-ruby.h"
17
17
 
18
- #define TRILOGY_RB_TIMEOUT 1
19
-
20
18
  VALUE Trilogy_CastError;
21
19
  static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
22
20
  Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError,
@@ -27,7 +25,7 @@ static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows,
27
25
  id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
28
26
  id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
29
27
  id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
30
- id_from_code, id_from_errno, id_connection_options;
28
+ id_from_code, id_from_errno, id_connection_options, id_max_allowed_packet;
31
29
 
32
30
  struct trilogy_ctx {
33
31
  trilogy_conn_t conn;
@@ -96,12 +94,26 @@ static void trilogy_syserr_fail_str(int e, VALUE msg)
96
94
  rb_raise(Trilogy_ConnectionRefusedError, "%" PRIsVALUE, msg);
97
95
  } else if (e == ECONNRESET) {
98
96
  rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg);
97
+ } else if (e == EPIPE) {
98
+ // Backwards compatibility: This error class makes no sense, but matches legacy behavior
99
+ rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", msg);
99
100
  } else {
100
101
  VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg);
101
102
  rb_exc_raise(exc);
102
103
  }
103
104
  }
104
105
 
106
+ static int trilogy_error_recoverable_p(int rc)
107
+ {
108
+ // TRILOGY_OPENSSL_ERR and TRILOGY_SYSERR (which can result from an SSL error) must shut down the socket, as further
109
+ // SSL calls would be invalid.
110
+ // TRILOGY_ERR, which represents an error message sent to us from the server, is recoverable.
111
+ // TRILOGY_MAX_PACKET_EXCEEDED is also recoverable as we do not send data when it occurs.
112
+ // For other exceptions we will also close the socket to prevent further use, as the connection is probably in an
113
+ // invalid state.
114
+ return rc == TRILOGY_ERR || rc == TRILOGY_MAX_PACKET_EXCEEDED;
115
+ }
116
+
105
117
  NORETURN(static void handle_trilogy_error(struct trilogy_ctx *, int, const char *, ...));
106
118
  static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *msg, ...)
107
119
  {
@@ -110,10 +122,22 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
110
122
  VALUE rbmsg = rb_vsprintf(msg, args);
111
123
  va_end(args);
112
124
 
125
+ if (!trilogy_error_recoverable_p(rc)) {
126
+ if (ctx->conn.socket != NULL) {
127
+ // trilogy_sock_shutdown may affect errno
128
+ int errno_was = errno;
129
+ trilogy_sock_shutdown(ctx->conn.socket);
130
+ errno = errno_was;
131
+ }
132
+ }
133
+
113
134
  switch (rc) {
114
135
  case TRILOGY_SYSERR:
115
136
  trilogy_syserr_fail_str(errno, rbmsg);
116
137
 
138
+ case TRILOGY_TIMEOUT:
139
+ rb_raise(Trilogy_TimeoutError, "%" PRIsVALUE, rbmsg);
140
+
117
141
  case TRILOGY_ERR: {
118
142
  VALUE message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
119
143
  VALUE exc = rb_funcall(Trilogy_ProtocolError, id_from_code, 2, message, INT2NUM(ctx->conn.error_code));
@@ -127,11 +151,6 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
127
151
  int err_reason = ERR_GET_REASON(ossl_error);
128
152
  trilogy_syserr_fail_str(err_reason, rbmsg);
129
153
  }
130
- // We can't recover from OpenSSL level errors if there's
131
- // an active connection.
132
- if (ctx->conn.socket != NULL) {
133
- trilogy_sock_shutdown(ctx->conn.socket);
134
- }
135
154
  rb_raise(Trilogy_SSLError, "%" PRIsVALUE ": SSL Error: %s", rbmsg, ERR_reason_error_string(ossl_error));
136
155
  }
137
156
 
@@ -169,8 +188,9 @@ static int flush_writes(struct trilogy_ctx *ctx)
169
188
  return rc;
170
189
  }
171
190
 
172
- if (trilogy_sock_wait_write(ctx->conn.socket) < 0) {
173
- rb_raise(Trilogy_TimeoutError, "trilogy_flush_writes");
191
+ rc = trilogy_sock_wait_write(ctx->conn.socket);
192
+ if (rc != TRILOGY_OK) {
193
+ return rc;
174
194
  }
175
195
  }
176
196
  }
@@ -190,6 +210,21 @@ static double timeval_to_double(struct timeval tv)
190
210
  return (double)tv.tv_sec + ((double)tv.tv_usec) / 1000000.0;
191
211
  }
192
212
 
213
+ struct rb_trilogy_wait_args {
214
+ struct timeval *timeout;
215
+ int wait_flag;
216
+ int fd;
217
+ int rc;
218
+ };
219
+
220
+ static VALUE rb_trilogy_wait_protected(VALUE vargs) {
221
+ struct rb_trilogy_wait_args *args = (void *)vargs;
222
+
223
+ args->rc = rb_wait_for_single_fd(args->fd, args->wait_flag, args->timeout);
224
+
225
+ return Qnil;
226
+ }
227
+
193
228
  static int _cb_ruby_wait(trilogy_sock_t *sock, trilogy_wait_t wait)
194
229
  {
195
230
  struct timeval *timeout = NULL;
@@ -219,11 +254,27 @@ static int _cb_ruby_wait(trilogy_sock_t *sock, trilogy_wait_t wait)
219
254
  timeout = NULL;
220
255
  }
221
256
 
222
- int fd = trilogy_sock_fd(sock);
223
- if (rb_wait_for_single_fd(fd, wait_flag, timeout) <= 0)
257
+ struct rb_trilogy_wait_args args;
258
+ args.fd = trilogy_sock_fd(sock);
259
+ args.wait_flag = wait_flag;
260
+ args.timeout = timeout;
261
+ args.rc = 0;
262
+
263
+ int state = 0;
264
+ rb_protect(rb_trilogy_wait_protected, (VALUE)&args, &state);
265
+ if (state) {
266
+ trilogy_sock_shutdown(sock);
267
+ rb_jump_tag(state);
268
+ }
269
+
270
+ // rc here comes from rb_wait_for_single_fd which (similar to poll(3)) returns 0 to indicate that the call timed out
271
+ // or -1 to indicate a system error with errno set.
272
+ if (args.rc < 0)
224
273
  return TRILOGY_SYSERR;
274
+ if (args.rc == 0)
275
+ return TRILOGY_TIMEOUT;
225
276
 
226
- return 0;
277
+ return TRILOGY_OK;
227
278
  }
228
279
 
229
280
  struct nogvl_sock_args {
@@ -275,8 +326,10 @@ escape the GVL on each wait operation without going through call_without_gvl */
275
326
  return rc;
276
327
  }
277
328
 
278
- if (trilogy_sock_wait(ctx->conn.socket, TRILOGY_WAIT_HANDSHAKE) < 0)
279
- return TRILOGY_RB_TIMEOUT;
329
+ rc = trilogy_sock_wait(ctx->conn.socket, TRILOGY_WAIT_HANDSHAKE);
330
+ if (rc != TRILOGY_OK) {
331
+ return rc;
332
+ }
280
333
  }
281
334
  }
282
335
 
@@ -303,8 +356,9 @@ static void auth_switch(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake)
303
356
  handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
304
357
  }
305
358
 
306
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
307
- rb_raise(Trilogy_TimeoutError, "trilogy_auth_recv");
359
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
360
+ if (rc != TRILOGY_OK) {
361
+ handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
308
362
  }
309
363
  }
310
364
  }
@@ -356,8 +410,9 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
356
410
  handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
357
411
  }
358
412
 
359
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
360
- rb_raise(Trilogy_TimeoutError, "trilogy_auth_recv");
413
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
414
+ if (rc != TRILOGY_OK) {
415
+ handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
361
416
  }
362
417
  }
363
418
 
@@ -415,6 +470,11 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VA
415
470
  connopt.keepalive_interval = NUM2USHORT(val);
416
471
  }
417
472
 
473
+ if ((val = rb_hash_lookup(opts, ID2SYM(id_max_allowed_packet))) != Qnil) {
474
+ Check_Type(val, T_FIXNUM);
475
+ connopt.max_allowed_packet = NUM2SIZET(val);
476
+ }
477
+
418
478
  if ((val = rb_hash_lookup(opts, ID2SYM(id_host))) != Qnil) {
419
479
  Check_Type(val, T_STRING);
420
480
 
@@ -455,12 +515,12 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VA
455
515
  connopt.flags |= TRILOGY_CAPABILITIES_FOUND_ROWS;
456
516
  }
457
517
 
458
- if (RTEST(rb_hash_aref(opts, ID2SYM(id_multi_result)))) {
518
+ if (rb_hash_aref(opts, ID2SYM(id_multi_result)) != Qfalse) {
459
519
  connopt.flags |= TRILOGY_CAPABILITIES_MULTI_RESULTS;
460
520
  }
461
521
 
462
522
  if (RTEST(rb_hash_aref(opts, ID2SYM(id_multi_statement)))) {
463
- connopt.flags |= TRILOGY_CAPABILITIES_MULTI_STATEMENTS | TRILOGY_CAPABILITIES_MULTI_RESULTS;
523
+ connopt.flags |= TRILOGY_CAPABILITIES_MULTI_STATEMENTS;
464
524
  }
465
525
 
466
526
  if ((val = rb_hash_aref(opts, ID2SYM(id_ssl_ca))) != Qnil) {
@@ -514,7 +574,7 @@ static VALUE rb_trilogy_initialize(VALUE self, VALUE encoding, VALUE charset, VA
514
574
  }
515
575
 
516
576
  int rc = try_connect(ctx, &handshake, &connopt);
517
- if (rc == TRILOGY_RB_TIMEOUT) {
577
+ if (rc == TRILOGY_TIMEOUT) {
518
578
  rb_raise(Trilogy_TimeoutError, "trilogy_connect_recv");
519
579
  }
520
580
  if (rc != TRILOGY_OK) {
@@ -561,8 +621,9 @@ static VALUE rb_trilogy_change_db(VALUE self, VALUE database)
561
621
  handle_trilogy_error(ctx, rc, "trilogy_change_db_recv");
562
622
  }
563
623
 
564
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
565
- rb_raise(Trilogy_TimeoutError, "trilogy_change_db_recv");
624
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
625
+ if (rc != TRILOGY_OK) {
626
+ handle_trilogy_error(ctx, rc, "trilogy_change_db_recv");
566
627
  }
567
628
  }
568
629
 
@@ -594,8 +655,9 @@ static VALUE rb_trilogy_set_server_option(VALUE self, VALUE option)
594
655
  handle_trilogy_error(ctx, rc, "trilogy_set_option_recv");
595
656
  }
596
657
 
597
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
598
- rb_raise(Trilogy_TimeoutError, "trilogy_set_option_recv");
658
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
659
+ if (rc != TRILOGY_OK) {
660
+ handle_trilogy_error(ctx, rc, "trilogy_set_option_recv");
599
661
  }
600
662
  }
601
663
 
@@ -667,8 +729,9 @@ static VALUE read_query_response(VALUE vargs)
667
729
  return read_query_error(args, rc, "trilogy_query_recv");
668
730
  }
669
731
 
670
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
671
- rb_raise(Trilogy_TimeoutError, "trilogy_query_recv");
732
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
733
+ if (rc != TRILOGY_OK) {
734
+ handle_trilogy_error(ctx, rc, "trilogy_query_recv");
672
735
  }
673
736
  }
674
737
 
@@ -716,8 +779,9 @@ static VALUE read_query_response(VALUE vargs)
716
779
  return read_query_error(args, rc, "trilogy_read_column");
717
780
  }
718
781
 
719
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
720
- rb_raise(Trilogy_TimeoutError, "trilogy_read_column");
782
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
783
+ if (rc != TRILOGY_OK) {
784
+ return read_query_error(args, rc, "trilogy_read_column");
721
785
  }
722
786
  }
723
787
 
@@ -744,8 +808,9 @@ static VALUE read_query_response(VALUE vargs)
744
808
  int rc = trilogy_read_row(&ctx->conn, row_values);
745
809
 
746
810
  if (rc == TRILOGY_AGAIN) {
747
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
748
- rb_raise(Trilogy_TimeoutError, "trilogy_read_row");
811
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
812
+ if (rc != TRILOGY_OK) {
813
+ return read_query_error(args, rc, "trilogy_read_row");
749
814
  }
750
815
  continue;
751
816
  }
@@ -871,8 +936,9 @@ static VALUE rb_trilogy_ping(VALUE self)
871
936
  handle_trilogy_error(ctx, rc, "trilogy_ping_recv");
872
937
  }
873
938
 
874
- if (trilogy_sock_wait_read(ctx->conn.socket) < 0) {
875
- rb_raise(Trilogy_TimeoutError, "trilogy_ping_recv");
939
+ rc = trilogy_sock_wait_read(ctx->conn.socket);
940
+ if (rc != TRILOGY_OK) {
941
+ handle_trilogy_error(ctx, rc, "trilogy_ping_recv");
876
942
  }
877
943
  }
878
944
 
@@ -931,6 +997,10 @@ static VALUE rb_trilogy_close(VALUE self)
931
997
  }
932
998
  }
933
999
 
1000
+ // We aren't checking or raising errors here (we need close to always close the socket and free the connection), so
1001
+ // we must clear any SSL errors left in the queue from a read/write.
1002
+ ERR_clear_error();
1003
+
934
1004
  trilogy_free(&ctx->conn);
935
1005
 
936
1006
  return Qnil;
@@ -1032,6 +1102,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
1032
1102
 
1033
1103
  rb_define_private_method(Trilogy, "_initialize", rb_trilogy_initialize, 3);
1034
1104
  rb_define_method(Trilogy, "change_db", rb_trilogy_change_db, 1);
1105
+ rb_define_alias(Trilogy, "select_db", "change_db");
1035
1106
  rb_define_method(Trilogy, "query", rb_trilogy_query, 1);
1036
1107
  rb_define_method(Trilogy, "ping", rb_trilogy_ping, 0);
1037
1108
  rb_define_method(Trilogy, "escape", rb_trilogy_escape, 1);
@@ -1114,6 +1185,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
1114
1185
  id_connect_timeout = rb_intern("connect_timeout");
1115
1186
  id_read_timeout = rb_intern("read_timeout");
1116
1187
  id_write_timeout = rb_intern("write_timeout");
1188
+ id_max_allowed_packet = rb_intern("max_allowed_packet");
1117
1189
  id_keepalive_enabled = rb_intern("keepalive_enabled");
1118
1190
  id_keepalive_idle = rb_intern("keepalive_idle");
1119
1191
  id_keepalive_count = rb_intern("keepalive_count");
@@ -177,4 +177,122 @@ int trilogy_ping(trilogy_conn_t *conn);
177
177
  */
178
178
  int trilogy_close(trilogy_conn_t *conn);
179
179
 
180
+ /* trilogy_stmt_prepare - Send a prepared statement prepare command to the server.
181
+ *
182
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
183
+ * undefined.
184
+ * stmt - A pointer to the buffer containing the statement to prepare.
185
+ * stmt_len - The length of the data buffer.
186
+ * stmt_out - A pointer to a pre-allocated trilogy_stmt_t.
187
+ *
188
+ * Return values:
189
+ * TRILOGY_OK - The prepare command was successfully sent to the server.
190
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
191
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
192
+ * packet.
193
+ * TRILOGY_SYSERR - A system error occurred, check errno.
194
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
195
+ */
196
+ int trilogy_stmt_prepare(trilogy_conn_t *conn, const char *stmt, size_t stmt_len, trilogy_stmt_t *stmt_out);
197
+
198
+ /* trilogy_stmt_execute - Send a prepared statement execute command to the server.
199
+ *
200
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
201
+ * undefined.
202
+ * stmt - Pointer to a valid trilogy_stmt_t, representing the prepared statement you're
203
+ * requesting to execute.
204
+ * flags - The flags (TRILOGY_STMT_FLAGS_t) to be used with this execute command packet.
205
+ * binds - Pointer to an array of trilogy_binary_value_t's. The array size should
206
+ * match that of `trilogy_stmt_t.column_count`.
207
+ * column_count_out - Out parameter; A pointer to a pre-allocated uint64_t. Represents the
208
+ * number of columns in the response.
209
+ *
210
+ * Return values:
211
+ * TRILOGY_OK - The execute command was successfully sent to the server.
212
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
213
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
214
+ * packet.
215
+ * TRILOGY_SYSERR - A system error occurred, check errno.
216
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
217
+ */
218
+ int trilogy_stmt_execute(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint8_t flags, trilogy_binary_value_t *binds,
219
+ uint64_t *column_count_out);
220
+
221
+ /* trilogy_stmt_bind_data - Send a prepared statement bind long data command to the server.
222
+ *
223
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
224
+ * undefined.
225
+ * stmt - Pointer to a valid trilogy_stmt_t, representing the prepared statement for which
226
+ * to bind the supplied parameter data to.
227
+ * param_num - The parameter index for which the supplied data should be bound to.
228
+ * data - A pointer to the buffer containing the data to be bound.
229
+ * data_len - The length of the data buffer.
230
+ *
231
+ * Return values:
232
+ * TRILOGY_OK - The bind data command was successfully sent to the server.
233
+ * TRILOGY_SYSERR - A system error occurred, check errno.
234
+ */
235
+ int trilogy_stmt_bind_data(trilogy_conn_t *conn, trilogy_stmt_t *stmt, uint16_t param_num, uint8_t *data,
236
+ size_t data_len);
237
+
238
+ /* trilogy_stmt_read_full_row - Read a row from the prepared statement execute response.
239
+ *
240
+ * This should only be called after a sucessful call to trilogy_stmt_execute.
241
+ * You should continue calling this until TRILOGY_EOF is returned. Denoting the end
242
+ * of the result set.
243
+ *
244
+ * conn - A pre-initialized trilogy_conn_t pointer. It can also be connected but
245
+ * a disconnected trilogy_conn_t will also return TRILOGY_OK.
246
+ * stmt - Pointer to a valid trilogy_stmt_t, representing the prepared statement you're
247
+ * requesting to execute.
248
+ * columns - The list of columns from the prepared statement.
249
+ * column_count - The number of columns in prepared statement.
250
+ * values_out - Out parameter; A pointer to a pre-allocated array of
251
+ * trilogy_binary_value_t's. There must be enough space to fit all of the
252
+ * values. This can be computed with:
253
+ * `(sizeof(trilogy_binary_value_t) * column_count)`.
254
+ *
255
+ * Return values:
256
+ * TRILOGY_OK - The prepare command response successfully read from
257
+ * the server.
258
+ * TRILOGY_EOF - There are no more rows to read from the result set.
259
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
260
+ * TRILOGY_PROTOCOL_VIOLATION - Invalid length parsed for a TIME/DATETIME/TIMESTAMP value.
261
+ * TRILOGY_UNKNOWN_TYPE - An unsupported or unknown MySQL type was seen.
262
+ * TRILOGY_SYSERR - A system error occurred, check errno.
263
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
264
+ */
265
+ int trilogy_stmt_read_full_row(trilogy_conn_t *conn, trilogy_stmt_t *stmt, trilogy_column_packet_t *columns,
266
+ trilogy_binary_value_t *values_out);
267
+
268
+ /* trilogy_stmt_reset - Send a prepared statement reset command to the server.
269
+ *
270
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
271
+ * undefined.
272
+ * stmt - Pointer to a valid trilogy_stmt_t, representing the prepared statement you're
273
+ * requesting to reset.
274
+ *
275
+ * Return values:
276
+ * TRILOGY_OK - The reset command was successfully sent to the server.
277
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
278
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
279
+ * packet.
280
+ * TRILOGY_SYSERR - A system error occurred, check errno.
281
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
282
+ */
283
+ int trilogy_stmt_reset(trilogy_conn_t *conn, trilogy_stmt_t *stmt);
284
+
285
+ /* trilogy_stmt_close_send - Send a prepared statement close command to the server.
286
+ *
287
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
288
+ * undefined.
289
+ * stmt - Pointer to a valid trilogy_stmt_t, representing the prepared statement you're
290
+ * requesting to close.
291
+ *
292
+ * Return values:
293
+ * TRILOGY_OK - The close command was successfully sent to the server.
294
+ * TRILOGY_SYSERR - A system error occurred, check errno.
295
+ */
296
+ int trilogy_stmt_close(trilogy_conn_t *conn, trilogy_stmt_t *stmt);
297
+
180
298
  #endif
@@ -16,6 +16,8 @@
16
16
  typedef struct {
17
17
  trilogy_buffer_t *buffer;
18
18
  size_t header_offset;
19
+ size_t packet_length;
20
+ size_t packet_max_length;
19
21
  uint32_t fragment_length;
20
22
  uint8_t seq;
21
23
  } trilogy_builder_t;
@@ -54,6 +56,8 @@ void trilogy_builder_finalize(trilogy_builder_t *builder);
54
56
  * Return values:
55
57
  * TRILOGY_OK - The value was appended to the packet buffer.
56
58
  * TRILOGY_SYSERR - A system error occurred, check errno.
59
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
60
+ * packet size.
57
61
  */
58
62
  int trilogy_builder_write_uint8(trilogy_builder_t *builder, uint8_t val);
59
63
 
@@ -66,6 +70,8 @@ int trilogy_builder_write_uint8(trilogy_builder_t *builder, uint8_t val);
66
70
  * Return values:
67
71
  * TRILOGY_OK - The value was appended to the packet buffer.
68
72
  * TRILOGY_SYSERR - A system error occurred, check errno.
73
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
74
+ * packet size.
69
75
  */
70
76
  int trilogy_builder_write_uint16(trilogy_builder_t *builder, uint16_t val);
71
77
 
@@ -78,6 +84,8 @@ int trilogy_builder_write_uint16(trilogy_builder_t *builder, uint16_t val);
78
84
  * Return values:
79
85
  * TRILOGY_OK - The value was appended to the packet buffer.
80
86
  * TRILOGY_SYSERR - A system error occurred, check errno.
87
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
88
+ * packet size.
81
89
  */
82
90
  int trilogy_builder_write_uint24(trilogy_builder_t *builder, uint32_t val);
83
91
 
@@ -90,6 +98,8 @@ int trilogy_builder_write_uint24(trilogy_builder_t *builder, uint32_t val);
90
98
  * Return values:
91
99
  * TRILOGY_OK - The value was appended to the packet buffer.
92
100
  * TRILOGY_SYSERR - A system error occurred, check errno.
101
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
102
+ * packet size.
93
103
  */
94
104
  int trilogy_builder_write_uint32(trilogy_builder_t *builder, uint32_t val);
95
105
 
@@ -102,9 +112,37 @@ int trilogy_builder_write_uint32(trilogy_builder_t *builder, uint32_t val);
102
112
  * Return values:
103
113
  * TRILOGY_OK - The value was appended to the packet buffer.
104
114
  * TRILOGY_SYSERR - A system error occurred, check errno.
115
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
116
+ * packet size.
105
117
  */
106
118
  int trilogy_builder_write_uint64(trilogy_builder_t *builder, uint64_t val);
107
119
 
120
+ /* trilogy_builder_write_float - Append a float to the packet buffer.
121
+ *
122
+ * builder - A pre-initialized trilogy_builder_t pointer
123
+ * val - The value to append to the buffer
124
+ *
125
+ * Return values:
126
+ * TRILOGY_OK - The value was appended to the packet buffer.
127
+ * TRILOGY_SYSERR - A system error occurred, check errno.
128
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
129
+ * packet size.
130
+ */
131
+ int trilogy_builder_write_float(trilogy_builder_t *builder, float val);
132
+
133
+ /* trilogy_builder_write_double - Append a double to the packet buffer.
134
+ *
135
+ * builder - A pre-initialized trilogy_builder_t pointer
136
+ * val - The value to append to the buffer
137
+ *
138
+ * Return values:
139
+ * TRILOGY_OK - The value was appended to the packet buffer.
140
+ * TRILOGY_SYSERR - A system error occurred, check errno.
141
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
142
+ * packet size.
143
+ */
144
+ int trilogy_builder_write_double(trilogy_builder_t *builder, double val);
145
+
108
146
  /* trilogy_builder_write_lenenc - Append a length-encoded integer to the packet
109
147
  * buffer.
110
148
  *
@@ -117,6 +155,8 @@ int trilogy_builder_write_uint64(trilogy_builder_t *builder, uint64_t val);
117
155
  * Return values:
118
156
  * TRILOGY_OK - The value was appended to the packet buffer.
119
157
  * TRILOGY_SYSERR - A system error occurred, check errno.
158
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
159
+ * packet size.
120
160
  */
121
161
  int trilogy_builder_write_lenenc(trilogy_builder_t *builder, uint64_t val);
122
162
 
@@ -130,6 +170,8 @@ int trilogy_builder_write_lenenc(trilogy_builder_t *builder, uint64_t val);
130
170
  * Return values:
131
171
  * TRILOGY_OK - The value was appended to the packet buffer.
132
172
  * TRILOGY_SYSERR - A system error occurred, check errno.
173
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
174
+ * packet size.
133
175
  */
134
176
  int trilogy_builder_write_buffer(trilogy_builder_t *builder, const void *data, size_t len);
135
177
 
@@ -144,6 +186,8 @@ int trilogy_builder_write_buffer(trilogy_builder_t *builder, const void *data, s
144
186
  * Return values:
145
187
  * TRILOGY_OK - The value was appended to the packet buffer.
146
188
  * TRILOGY_SYSERR - A system error occurred, check errno.
189
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
190
+ * packet size.
147
191
  */
148
192
  int trilogy_builder_write_lenenc_buffer(trilogy_builder_t *builder, const void *data, size_t len);
149
193
 
@@ -155,7 +199,23 @@ int trilogy_builder_write_lenenc_buffer(trilogy_builder_t *builder, const void *
155
199
  * Return values:
156
200
  * TRILOGY_OK - The value was appended to the packet buffer.
157
201
  * TRILOGY_SYSERR - A system error occurred, check errno.
202
+ * TRILOGY_MAX_PACKET_EXCEEDED - Appending this value would exceed the maximum
203
+ * packet size.
158
204
  */
159
205
  int trilogy_builder_write_string(trilogy_builder_t *builder, const char *data);
160
206
 
207
+ /* trilogy_builder_set_max_packet_length - Set the maximum packet length for
208
+ * the builder. Writing data to the builder that would cause the packet length
209
+ * to exceed this value will cause the builder to error.
210
+ *
211
+ * builder - A pre-initialized trilogy_builder_t pointer
212
+ * max_length - The new maximum packet length to set
213
+ *
214
+ * Return values:
215
+ * TRILOGY_OK - The maximum packet length was set.
216
+ * TRILOGY_MAX_PACKET_EXCEEDED - The current packet length is already
217
+ * larger than the requested maximum.
218
+ */
219
+ int trilogy_builder_set_max_packet_length(trilogy_builder_t *builder, size_t max_length);
220
+
161
221
  #endif