From e2afdd0fa8742b2a0c2edd18fa18577ead0a71f1 Mon Sep 17 00:00:00 2001
From: gentlawk <gentlawk@gmail.com>
Date: Fri, 21 Jun 2019 17:42:47 +0900
Subject: [PATCH 1/3] Fix zero-datetime in statement result raises
 ArgumentError

---
 ext/mysql2/result.c           | 42 +++++++++++++++++++----------------
 spec/mysql2/result_spec.rb    |  5 +++++
 spec/mysql2/statement_spec.rb |  5 +++++
 3 files changed, 33 insertions(+), 19 deletions(-)
 mode change 100644 => 100755 ext/mysql2/result.c
 mode change 100644 => 100755 spec/mysql2/result_spec.rb
 mode change 100644 => 100755 spec/mysql2/statement_spec.rb

diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c
old mode 100644
new mode 100755
index fbff98137..94dc0d1a7
--- a/ext/mysql2/result.c
+++ b/ext/mysql2/result.c
@@ -419,27 +419,31 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
           ts = (MYSQL_TIME*)result_buffer->buffer;
           seconds = (ts->year*31557600ULL) + (ts->month*2592000ULL) + (ts->day*86400ULL) + (ts->hour*3600ULL) + (ts->minute*60ULL) + ts->second;
 
-          if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
-            VALUE offset = INT2NUM(0);
-            if (args->db_timezone == intern_local) {
-              offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
-            }
-            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);
-            if (!NIL_P(args->app_timezone)) {
-              if (args->app_timezone == intern_local) {
+          if (seconds == 0) {
+            val = Qnil;
+          } else {
+            if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
+              VALUE offset = INT2NUM(0);
+              if (args->db_timezone == intern_local) {
                 offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
-                val = rb_funcall(val, intern_new_offset, 1, offset);
-              } else { // utc
-                val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
               }
-            }
-          } else {
-            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));
-            if (!NIL_P(args->app_timezone)) {
-              if (args->app_timezone == intern_local) {
-                val = rb_funcall(val, intern_localtime, 0);
-              } else { // utc
-                val = rb_funcall(val, intern_utc, 0);
+              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);
+              if (!NIL_P(args->app_timezone)) {
+                if (args->app_timezone == intern_local) {
+                  offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
+                  val = rb_funcall(val, intern_new_offset, 1, offset);
+                } else { // utc
+                  val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
+                }
+              }
+            } else {
+              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));
+              if (!NIL_P(args->app_timezone)) {
+                if (args->app_timezone == intern_local) {
+                  val = rb_funcall(val, intern_localtime, 0);
+                } else { // utc
+                  val = rb_funcall(val, intern_utc, 0);
+                }
               }
             }
           }
diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb
old mode 100644
new mode 100755
index a70b38ef0..6654088e2
--- a/spec/mysql2/result_spec.rb
+++ b/spec/mysql2/result_spec.rb
@@ -297,6 +297,11 @@
       expect(r.first['test']).to be_an_instance_of(Time)
     end
 
+    it "should return nil when timestamp is 0000-00-00T00:00:00" do
+      r = @client.query("SELECT CAST('0000-00-00 00:00:00' AS DATETIME) as test")
+      expect(r.first['test']).to be_nil
+    end
+
     it "should return Time for a TIMESTAMP value when within the supported range" do
       expect(test_result['timestamp_test']).to be_an_instance_of(Time)
       expect(test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')
diff --git a/spec/mysql2/statement_spec.rb b/spec/mysql2/statement_spec.rb
old mode 100644
new mode 100755
index dbc185e6b..22f6853b3
--- a/spec/mysql2/statement_spec.rb
+++ b/spec/mysql2/statement_spec.rb
@@ -454,6 +454,11 @@ def stmt_count
       expect(r.first['test']).to be_an_instance_of(Time)
     end
 
+    it "should return nil when timestamp is 0000-00-00T00:00:00" do
+      r = @client.prepare("SELECT CAST('0000-00-00 00:00:00' AS DATETIME) as test").execute
+      expect(r.first['test']).to be_nil
+    end
+
     it "should return Time for a TIMESTAMP value when within the supported range" do
       expect(test_result['timestamp_test']).to be_an_instance_of(Time)
       expect(test_result['timestamp_test'].strftime("%Y-%m-%d %H:%M:%S")).to eql('2010-04-04 11:44:00')

From 7e45d3754725e3bed2b91a9084d4b15febe6304e Mon Sep 17 00:00:00 2001
From: gentlawk <gentlawk@gmail.com>
Date: Fri, 6 Dec 2019 11:33:32 +0900
Subject: [PATCH 2/3] Fix unnecessary indent of if block

---
 ext/mysql2/result.c | 40 +++++++++++++++++++---------------------
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c
index 94dc0d1a7..3e36070e7 100755
--- a/ext/mysql2/result.c
+++ b/ext/mysql2/result.c
@@ -421,29 +421,27 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
 
           if (seconds == 0) {
             val = Qnil;
-          } else {
-            if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
-              VALUE offset = INT2NUM(0);
-              if (args->db_timezone == intern_local) {
+          } else if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
+            VALUE offset = INT2NUM(0);
+            if (args->db_timezone == intern_local) {
+              offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
+            }
+            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);
+            if (!NIL_P(args->app_timezone)) {
+              if (args->app_timezone == intern_local) {
                 offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
+                val = rb_funcall(val, intern_new_offset, 1, offset);
+              } else { // utc
+                val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
               }
-              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);
-              if (!NIL_P(args->app_timezone)) {
-                if (args->app_timezone == intern_local) {
-                  offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
-                  val = rb_funcall(val, intern_new_offset, 1, offset);
-                } else { // utc
-                  val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
-                }
-              }
-            } else {
-              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));
-              if (!NIL_P(args->app_timezone)) {
-                if (args->app_timezone == intern_local) {
-                  val = rb_funcall(val, intern_localtime, 0);
-                } else { // utc
-                  val = rb_funcall(val, intern_utc, 0);
-                }
+            }
+          } else {
+            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));
+            if (!NIL_P(args->app_timezone)) {
+              if (args->app_timezone == intern_local) {
+                val = rb_funcall(val, intern_localtime, 0);
+              } else { // utc
+                val = rb_funcall(val, intern_utc, 0);
               }
             }
           }

From 946532d824353029aca0087a3b09bae55c3c574b Mon Sep 17 00:00:00 2001
From: gentlawk <gentlawk@gmail.com>
Date: Fri, 6 Dec 2019 12:32:02 +0900
Subject: [PATCH 3/3] Fix filemode

---
 ext/mysql2/result.c           | 0
 spec/mysql2/result_spec.rb    | 0
 spec/mysql2/statement_spec.rb | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100755 => 100644 ext/mysql2/result.c
 mode change 100755 => 100644 spec/mysql2/result_spec.rb
 mode change 100755 => 100644 spec/mysql2/statement_spec.rb

diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c
old mode 100755
new mode 100644
diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb
old mode 100755
new mode 100644
diff --git a/spec/mysql2/statement_spec.rb b/spec/mysql2/statement_spec.rb
old mode 100755
new mode 100644