Skip to content

Commit e2afdd0

Browse files
committed
Fix zero-datetime in statement result raises ArgumentError
1 parent 9804551 commit e2afdd0

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

ext/mysql2/result.c

100644100755
Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -419,27 +419,31 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
419419
ts = (MYSQL_TIME*)result_buffer->buffer;
420420
seconds = (ts->year*31557600ULL) + (ts->month*2592000ULL) + (ts->day*86400ULL) + (ts->hour*3600ULL) + (ts->minute*60ULL) + ts->second;
421421

422-
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
423-
VALUE offset = INT2NUM(0);
424-
if (args->db_timezone == intern_local) {
425-
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
426-
}
427-
val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), offset);
428-
if (!NIL_P(args->app_timezone)) {
429-
if (args->app_timezone == intern_local) {
422+
if (seconds == 0) {
423+
val = Qnil;
424+
} else {
425+
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
426+
VALUE offset = INT2NUM(0);
427+
if (args->db_timezone == intern_local) {
430428
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
431-
val = rb_funcall(val, intern_new_offset, 1, offset);
432-
} else { // utc
433-
val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
434429
}
435-
}
436-
} else {
437-
val = rb_funcall(rb_cTime, args->db_timezone, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), ULONG2NUM(ts->second_part));
438-
if (!NIL_P(args->app_timezone)) {
439-
if (args->app_timezone == intern_local) {
440-
val = rb_funcall(val, intern_localtime, 0);
441-
} else { // utc
442-
val = rb_funcall(val, intern_utc, 0);
430+
val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), offset);
431+
if (!NIL_P(args->app_timezone)) {
432+
if (args->app_timezone == intern_local) {
433+
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
434+
val = rb_funcall(val, intern_new_offset, 1, offset);
435+
} else { // utc
436+
val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
437+
}
438+
}
439+
} else {
440+
val = rb_funcall(rb_cTime, args->db_timezone, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), ULONG2NUM(ts->second_part));
441+
if (!NIL_P(args->app_timezone)) {
442+
if (args->app_timezone == intern_local) {
443+
val = rb_funcall(val, intern_localtime, 0);
444+
} else { // utc
445+
val = rb_funcall(val, intern_utc, 0);
446+
}
443447
}
444448
}
445449
}

spec/mysql2/result_spec.rb

100644100755
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,11 @@
297297
expect(r.first['test']).to be_an_instance_of(Time)
298298
end
299299

300+
it "should return nil when timestamp is 0000-00-00T00:00:00" do
301+
r = @client.query("SELECT CAST('0000-00-00 00:00:00' AS DATETIME) as test")
302+
expect(r.first['test']).to be_nil
303+
end
304+
300305
it "should return Time for a TIMESTAMP value when within the supported range" do
301306
expect(test_result['timestamp_test']).to be_an_instance_of(Time)
302307
expect(test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')

spec/mysql2/statement_spec.rb

100644100755
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,11 @@ def stmt_count
454454
expect(r.first['test']).to be_an_instance_of(Time)
455455
end
456456

457+
it "should return nil when timestamp is 0000-00-00T00:00:00" do
458+
r = @client.prepare("SELECT CAST('0000-00-00 00:00:00' AS DATETIME) as test").execute
459+
expect(r.first['test']).to be_nil
460+
end
461+
457462
it "should return Time for a TIMESTAMP value when within the supported range" do
458463
expect(test_result['timestamp_test']).to be_an_instance_of(Time)
459464
expect(test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')

0 commit comments

Comments
 (0)