Skip to content

Commit e771aa0

Browse files
nyaxtjustincase
authored andcommitted
reuse result bind buffers
1 parent 28a7d66 commit e771aa0

File tree

2 files changed

+105
-85
lines changed

2 files changed

+105
-85
lines changed

ext/mysql2/result.c

Lines changed: 100 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,24 @@ static void rb_mysql_result_mark(void * wrapper) {
7171

7272
/* this may be called manually or during GC */
7373
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
74+
unsigned int i;
7475
if (!wrapper) return;
7576

7677
if (wrapper->resultFreed != 1) {
7778
if (wrapper->stmt) {
7879
mysql_stmt_free_result(wrapper->stmt);
80+
81+
if(wrapper->result_buffers) {
82+
for(i = 0; i < wrapper->numberOfFields; i++) {
83+
if (wrapper->result_buffers[i].buffer) {
84+
free(wrapper->result_buffers[i].buffer);
85+
}
86+
}
87+
free(wrapper->result_buffers);
88+
free(wrapper->is_null);
89+
free(wrapper->error);
90+
free(wrapper->length);
91+
}
7992
}
8093
/* FIXME: this may call flush_use_result, which can hit the socket */
8194
mysql_free_result(wrapper->result);
@@ -196,78 +209,56 @@ static unsigned int msec_char_to_uint(char *msec_char, size_t len)
196209
return (unsigned int)strtoul(msec_char, NULL, 10);
197210
}
198211

199-
static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
212+
static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields) {
213+
unsigned int i;
200214
VALUE rowVal;
201215
mysql2_result_wrapper * wrapper;
202-
unsigned int i = 0;
203-
MYSQL_BIND *result_buffers; // FIXME: don't do this every time
204-
my_bool *is_null;
205-
my_bool *error;
206-
unsigned long *length;
207-
208-
#ifdef HAVE_RUBY_ENCODING_H
209-
rb_encoding *default_internal_enc;
210-
rb_encoding *conn_enc;
211-
#endif
212216
GetMysql2Result(self, wrapper);
213217

214-
#ifdef HAVE_RUBY_ENCODING_H
215-
default_internal_enc = rb_default_internal_encoding();
216-
conn_enc = rb_to_encoding(wrapper->encoding);
217-
#endif
218-
219-
if (asArray) {
220-
rowVal = rb_ary_new2(wrapper->numberOfFields);
221-
} else {
222-
rowVal = rb_hash_new();
223-
}
224-
if (wrapper->fields == Qnil) {
225-
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
226-
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
227-
}
218+
if (wrapper->result_buffers != NULL) return;
228219

229-
result_buffers = xcalloc(wrapper->numberOfFields, sizeof(MYSQL_BIND));
230-
is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
231-
error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
232-
length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
220+
wrapper->result_buffers = xcalloc(wrapper->numberOfFields, sizeof(MYSQL_BIND));
221+
wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
222+
wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
223+
wrapper->length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
233224

234225
for (i = 0; i < wrapper->numberOfFields; i++) {
235-
result_buffers[i].buffer_type = fields[i].type;
226+
wrapper->result_buffers[i].buffer_type = fields[i].type;
236227

237228
// mysql type | C type
238229
switch(fields[i].type) {
239230
case MYSQL_TYPE_NULL: // NULL
240231
break;
241232
case MYSQL_TYPE_TINY: // signed char
242-
result_buffers[i].buffer = xcalloc(1, sizeof(signed char));
243-
result_buffers[i].buffer_length = sizeof(signed char);
233+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(signed char));
234+
wrapper->result_buffers[i].buffer_length = sizeof(signed char);
244235
break;
245236
case MYSQL_TYPE_SHORT: // short int
246-
result_buffers[i].buffer = xcalloc(1, sizeof(short int));
247-
result_buffers[i].buffer_length = sizeof(short int);
237+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(short int));
238+
wrapper->result_buffers[i].buffer_length = sizeof(short int);
248239
break;
249240
case MYSQL_TYPE_INT24: // int
250241
case MYSQL_TYPE_LONG: // int
251242
case MYSQL_TYPE_YEAR: // int
252-
result_buffers[i].buffer = xcalloc(1, sizeof(int));
253-
result_buffers[i].buffer_length = sizeof(int);
243+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(int));
244+
wrapper->result_buffers[i].buffer_length = sizeof(int);
254245
break;
255246
case MYSQL_TYPE_LONGLONG: // long long int
256-
result_buffers[i].buffer = xcalloc(1, sizeof(long long int));
257-
result_buffers[i].buffer_length = sizeof(long long int);
247+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(long long int));
248+
wrapper->result_buffers[i].buffer_length = sizeof(long long int);
258249
break;
259250
case MYSQL_TYPE_FLOAT: // float
260251
case MYSQL_TYPE_DOUBLE: // double
261-
result_buffers[i].buffer = xcalloc(1, sizeof(double));
262-
result_buffers[i].buffer_length = sizeof(double);
252+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(double));
253+
wrapper->result_buffers[i].buffer_length = sizeof(double);
263254
break;
264255
case MYSQL_TYPE_TIME: // MYSQL_TIME
265256
case MYSQL_TYPE_DATE: // MYSQL_TIME
266257
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
267258
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
268259
case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
269-
result_buffers[i].buffer = xcalloc(1, sizeof(MYSQL_TIME));
270-
result_buffers[i].buffer_length = sizeof(MYSQL_TIME);
260+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(MYSQL_TIME));
261+
wrapper->result_buffers[i].buffer_length = sizeof(MYSQL_TIME);
271262
break;
272263
case MYSQL_TYPE_DECIMAL: // char[]
273264
case MYSQL_TYPE_NEWDECIMAL: // char[]
@@ -282,30 +273,52 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
282273
case MYSQL_TYPE_SET: // char[]
283274
case MYSQL_TYPE_ENUM: // char[]
284275
case MYSQL_TYPE_GEOMETRY: // char[]
285-
result_buffers[i].buffer = malloc(fields[i].max_length);
286-
result_buffers[i].buffer_length = fields[i].max_length;
276+
wrapper->result_buffers[i].buffer = malloc(fields[i].max_length);
277+
wrapper->result_buffers[i].buffer_length = fields[i].max_length;
287278
break;
288279
default:
289280
rb_raise(cMysql2Error, "unhandled mysql type: %d", fields[i].type);
290281
}
291282

292-
result_buffers[i].is_null = &is_null[i];
293-
result_buffers[i].length = &length[i];
294-
result_buffers[i].error = &error[i];
295-
result_buffers[i].is_unsigned = ((fields[i].flags & UNSIGNED_FLAG) != 0);
283+
wrapper->result_buffers[i].is_null = &wrapper->is_null[i];
284+
wrapper->result_buffers[i].length = &wrapper->length[i];
285+
wrapper->result_buffers[i].error = &wrapper->error[i];
286+
wrapper->result_buffers[i].is_unsigned = ((fields[i].flags & UNSIGNED_FLAG) != 0);
296287
}
288+
}
289+
290+
static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD *fields) {
291+
VALUE rowVal;
292+
mysql2_result_wrapper *wrapper;
293+
unsigned int i = 0;
294+
295+
#ifdef HAVE_RUBY_ENCODING_H
296+
rb_encoding *default_internal_enc;
297+
rb_encoding *conn_enc;
298+
#endif
299+
GetMysql2Result(self, wrapper);
300+
301+
#ifdef HAVE_RUBY_ENCODING_H
302+
default_internal_enc = rb_default_internal_encoding();
303+
conn_enc = rb_to_encoding(wrapper->encoding);
304+
#endif
305+
306+
if (asArray) {
307+
rowVal = rb_ary_new2(wrapper->numberOfFields);
308+
} else {
309+
rowVal = rb_hash_new();
310+
}
311+
if (wrapper->fields == Qnil) {
312+
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
313+
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
314+
}
315+
316+
if (wrapper->result_buffers == NULL) {
317+
rb_mysql_result_alloc_result_buffers(self, fields);
318+
}
319+
320+
if(mysql_stmt_bind_result(wrapper->stmt, wrapper->result_buffers)) {
297321

298-
if(mysql_stmt_bind_result(wrapper->stmt, result_buffers)) {
299-
// FIXME: goto this
300-
for(i = 0; i < wrapper->numberOfFields; i++) {
301-
if (result_buffers[i].buffer) {
302-
free(result_buffers[i].buffer);
303-
}
304-
}
305-
free(result_buffers);
306-
free(is_null);
307-
free(error);
308-
free(length);
309322
rb_raise(cMysql2Error, "%s", mysql_stmt_error(wrapper->stmt));
310323
}
311324

@@ -318,52 +331,54 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
318331
VALUE val = Qnil;
319332
MYSQL_TIME *ts;
320333

321-
if (is_null[i]) {
334+
if (wrapper->is_null[i]) {
322335
val = Qnil;
323336
} else {
324-
switch(result_buffers[i].buffer_type) {
337+
const MYSQL_BIND* const result_buffer = &wrapper->result_buffers[i];
338+
339+
switch(result_buffer->buffer_type) {
325340
case MYSQL_TYPE_TINY: // signed char
326-
if (result_buffers[i].is_unsigned) {
327-
val = UINT2NUM(*((unsigned char*)result_buffers[i].buffer));
341+
if (result_buffer->is_unsigned) {
342+
val = UINT2NUM(*((unsigned char*)result_buffer->buffer));
328343
} else {
329-
val = INT2NUM(*((signed char*)result_buffers[i].buffer));
344+
val = INT2NUM(*((signed char*)result_buffer->buffer));
330345
}
331346
break;
332347
case MYSQL_TYPE_SHORT: // short int
333-
if (result_buffers[i].is_unsigned) {
334-
val = UINT2NUM(*((unsigned short int*)result_buffers[i].buffer));
348+
if (result_buffer->is_unsigned) {
349+
val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
335350
} else {
336-
val = INT2NUM(*((short int*)result_buffers[i].buffer));
351+
val = INT2NUM(*((short int*)result_buffer->buffer));
337352
}
338353
break;
339354
case MYSQL_TYPE_INT24: // int
340355
case MYSQL_TYPE_LONG: // int
341356
case MYSQL_TYPE_YEAR: // int
342-
if (result_buffers[i].is_unsigned) {
343-
val = UINT2NUM(*((unsigned int*)result_buffers[i].buffer));
357+
if (result_buffer->is_unsigned) {
358+
val = UINT2NUM(*((unsigned int*)result_buffer->buffer));
344359
} else {
345-
val = INT2NUM(*((int*)result_buffers[i].buffer));
360+
val = INT2NUM(*((int*)result_buffer->buffer));
346361
}
347362
break;
348363
case MYSQL_TYPE_LONGLONG: // long long int
349-
if (result_buffers[i].is_unsigned) {
350-
val = ULL2NUM(*((unsigned long long int*)result_buffers[i].buffer));
364+
if (result_buffer->is_unsigned) {
365+
val = ULL2NUM(*((unsigned long long int*)result_buffer->buffer));
351366
} else {
352-
val = LL2NUM(*((long long int*)result_buffers[i].buffer));
367+
val = LL2NUM(*((long long int*)result_buffer->buffer));
353368
}
354369
break;
355370
case MYSQL_TYPE_FLOAT: // float
356-
val = rb_float_new((double)(*((float*)result_buffers[i].buffer)));
371+
val = rb_float_new((double)(*((float*)result_buffer->buffer)));
357372
break;
358373
case MYSQL_TYPE_DOUBLE: // double
359-
val = rb_float_new((double)(*((double*)result_buffers[i].buffer)));
374+
val = rb_float_new((double)(*((double*)result_buffer->buffer)));
360375
break;
361376
case MYSQL_TYPE_DATE: // MYSQL_TIME
362-
ts = (MYSQL_TIME*)result_buffers[i].buffer;
377+
ts = (MYSQL_TIME*)result_buffer->buffer;
363378
val = rb_funcall(cDate, rb_intern("new"), 3, INT2NUM(ts->year), INT2NUM(ts->month), INT2NUM(ts->day));
364379
break;
365380
case MYSQL_TYPE_TIME: // MYSQL_TIME
366-
ts = (MYSQL_TIME*)result_buffers[i].buffer;
381+
ts = (MYSQL_TIME*)result_buffer->buffer;
367382
val = rb_funcall(rb_cTime,
368383
rb_intern("mktime"), 6,
369384
UINT2NUM(Qnil),
@@ -376,7 +391,7 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
376391
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
377392
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
378393
case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
379-
ts = (MYSQL_TIME*)result_buffers[i].buffer;
394+
ts = (MYSQL_TIME*)result_buffer->buffer;
380395
val = rb_funcall(rb_cTime,
381396
rb_intern("mktime"), 6,
382397
UINT2NUM(ts->year),
@@ -388,7 +403,7 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
388403
break;
389404
case MYSQL_TYPE_DECIMAL: // char[]
390405
case MYSQL_TYPE_NEWDECIMAL: // char[]
391-
val = rb_funcall(cBigDecimal, rb_intern("new"), 1, rb_str_new(result_buffers[i].buffer, *(result_buffers[i].length)));
406+
val = rb_funcall(cBigDecimal, rb_intern("new"), 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
392407
break;
393408
case MYSQL_TYPE_STRING: // char[]
394409
case MYSQL_TYPE_VAR_STRING: // char[]
@@ -401,14 +416,14 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
401416
case MYSQL_TYPE_SET: // char[]
402417
case MYSQL_TYPE_ENUM: // char[]
403418
case MYSQL_TYPE_GEOMETRY: // char[]
404-
val = rb_str_new(result_buffers[i].buffer, *(result_buffers[i].length));
419+
val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
405420
#ifdef HAVE_RUBY_ENCODING_H
406421
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
407422
#endif
408423
break;
409424
default:
410425
rb_raise(cMysql2Error, "unhandled buffer type: %d",
411-
result_buffers[i].buffer_type);
426+
result_buffer->buffer_type);
412427
break;
413428
}
414429
}
@@ -420,10 +435,6 @@ static VALUE rb_mysql_result_stmt_fetch_row(VALUE self, ID db_timezone, ID app_t
420435
}
421436
}
422437

423-
free(result_buffers);
424-
free(is_null);
425-
free(error);
426-
free(length);
427438
return rowVal;
428439
}
429440

@@ -996,6 +1007,10 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
9961007
wrapper->client_wrapper = DATA_PTR(client);
9971008
wrapper->client_wrapper->refcount++;
9981009
wrapper->stmt = s;
1010+
wrapper->result_buffers = NULL;
1011+
wrapper->is_null = NULL;
1012+
wrapper->error = NULL;
1013+
wrapper->length = NULL;
9991014

10001015
rb_obj_call_init(obj, 0, NULL);
10011016
rb_iv_set(obj, "@query_options", options);

ext/mysql2/result.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ typedef struct {
1818
MYSQL_RES *result;
1919
MYSQL_STMT *stmt;
2020
mysql_client_wrapper *client_wrapper;
21+
/* statement result bind buffers */
22+
MYSQL_BIND *result_buffers;
23+
my_bool *is_null;
24+
my_bool *error;
25+
unsigned long *length;
2126
} mysql2_result_wrapper;
2227

2328
#define GetMysql2Result(obj, sval) (sval = (mysql2_result_wrapper*)DATA_PTR(obj));

0 commit comments

Comments
 (0)