Skip to content

Commit ad49bb2

Browse files
committed
Fix: BigDecimal statement parameter is ignored.
Added code to treat a parameter of Ruby type BigDecimal.
1 parent 270ebf3 commit ad49bb2

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

ext/mysql2/statement.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
VALUE cMysql2Statement;
44
extern VALUE mMysql2, cMysql2Error, cBigDecimal, cDateTime, cDate;
55
static VALUE sym_stream, intern_new_with_args, intern_each;
6-
static VALUE intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year;
6+
static VALUE intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year, intern_to_s;
77

88
#define GET_STATEMENT(self) \
99
mysql_stmt_wrapper *stmt_wrapper; \
@@ -190,6 +190,19 @@ static void *nogvl_stmt_store_result(void *ptr) {
190190
}
191191
}
192192

193+
static void set_buffer_for_string(MYSQL_BIND* bind_buffer, unsigned long *length_buffer, VALUE string) {
194+
int length;
195+
196+
bind_buffer->buffer_type = MYSQL_TYPE_STRING;
197+
bind_buffer->buffer = RSTRING_PTR(string);
198+
199+
length = RSTRING_LEN(string);
200+
bind_buffer->buffer_length = length;
201+
*length_buffer = length;
202+
203+
bind_buffer->length = length_buffer;
204+
}
205+
193206
/* Free each bind_buffer[i].buffer except when params_enc is non-nil, this means
194207
* the buffer is a Ruby string pointer and not our memory to manage.
195208
*/
@@ -280,11 +293,7 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
280293
#ifdef HAVE_RUBY_ENCODING_H
281294
params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
282295
#endif
283-
bind_buffers[i].buffer_type = MYSQL_TYPE_STRING;
284-
bind_buffers[i].buffer = RSTRING_PTR(params_enc[i]);
285-
bind_buffers[i].buffer_length = RSTRING_LEN(params_enc[i]);
286-
length_buffers[i] = bind_buffers[i].buffer_length;
287-
bind_buffers[i].length = &length_buffers[i];
296+
set_buffer_for_string(&bind_buffers[i], &length_buffers[i], params_enc[i]);
288297
}
289298
break;
290299
default:
@@ -324,6 +333,19 @@ static VALUE execute(int argc, VALUE *argv, VALUE self) {
324333
*(MYSQL_TIME*)(bind_buffers[i].buffer) = t;
325334
} else if (CLASS_OF(argv[i]) == cBigDecimal) {
326335
bind_buffers[i].buffer_type = MYSQL_TYPE_NEWDECIMAL;
336+
337+
// DECIMAL are represented with the "string representation of the
338+
// original server-side value", see
339+
// https://dev.mysql.com/doc/refman/5.7/en/c-api-prepared-statement-type-conversions.html
340+
// This should be independent of the locale used both on the server
341+
// and the client side.
342+
VALUE rb_val_as_string = rb_funcall(argv[i], intern_to_s, 0);
343+
344+
params_enc[i] = rb_val_as_string;
345+
#ifdef HAVE_RUBY_ENCODING_H
346+
params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
347+
#endif
348+
set_buffer_for_string(&bind_buffers[i], &length_buffers[i], params_enc[i]);
327349
}
328350
break;
329351
}
@@ -491,4 +513,6 @@ void init_mysql2_statement() {
491513
intern_day = rb_intern("day");
492514
intern_month = rb_intern("month");
493515
intern_year = rb_intern("year");
516+
517+
intern_to_s = rb_intern("to_s");
494518
}

spec/mysql2/statement_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@
117117
expect(list[1]).to eq('2')
118118
end
119119

120+
it "should update a DECIMAL value passing a BigDecimal" do
121+
@client.query 'USE test'
122+
@client.query 'DROP TABLE IF EXISTS mysql2_stmt_decimal_test'
123+
@client.query 'CREATE TABLE mysql2_stmt_decimal_test (decimal_test DECIMAL(10,3))'
124+
125+
@client.prepare("INSERT INTO mysql2_stmt_decimal_test VALUES (?)").execute(BigDecimal.new("123.45"))
126+
127+
test_result = @client.query("SELECT * FROM mysql2_stmt_decimal_test").first
128+
expect(test_result['decimal_test']).to eql(123.45)
129+
end
130+
120131
context "utf8_db" do
121132
before(:each) do
122133
@client.query("DROP DATABASE IF EXISTS test_mysql2_stmt_utf8")

0 commit comments

Comments
 (0)