From 42c3633194a699ab1a4b5ab00a6853c0aaf0a4e5 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Thu, 12 May 2022 18:30:23 +0300
Subject: [PATCH] sql: introduce cast from STRING to DATETIME

This patch introduces explicit cast from STRING to DATETIME.

Follow-up #6773

NO_DOC=DATETIME has already been introduced.
NO_CHANGELOG=DATETIME has already been introduced.
---
 src/box/sql/mem.c                  | 14 +++++++++++++
 test/sql-luatest/datetime_test.lua | 33 ++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index b8a9d39ca4..3e0e659d6b 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -858,6 +858,18 @@ str_to_dec(struct Mem *mem)
 	return 0;
 }
 
+/** Convert MEM from STRING to DATETIME. */
+static inline int
+str_to_datetime(struct Mem *mem)
+{
+	assert(mem->type == MEM_TYPE_STR);
+	struct datetime dt;
+	if (datetime_parse_full(&dt, mem->z, mem->n, 0) <= 0)
+		return -1;
+	mem_set_datetime(mem, &dt);
+	return 0;
+}
+
 static inline int
 double_to_int(struct Mem *mem)
 {
@@ -1457,6 +1469,8 @@ mem_cast_explicit(struct Mem *mem, enum field_type type)
 			return bin_to_uuid(mem);
 		return -1;
 	case FIELD_TYPE_DATETIME:
+		if (mem->type == MEM_TYPE_STR)
+			return str_to_datetime(mem);
 		if (mem->type != MEM_TYPE_DATETIME)
 			return -1;
 		mem->flags = 0;
diff --git a/test/sql-luatest/datetime_test.lua b/test/sql-luatest/datetime_test.lua
index 29bdf68d41..78cd1d5ab2 100644
--- a/test/sql-luatest/datetime_test.lua
+++ b/test/sql-luatest/datetime_test.lua
@@ -931,11 +931,12 @@ end
 g.test_datetime_18_3 = function()
     g.server:exec(function()
         local t = require('luatest')
+        local dt = require('datetime')
+        local dt1 = dt.new({year = 2001, month = 1, day = 1, hour = 1})
         local sql = [[SELECT CAST('2001-01-01T01:00:00Z' AS DATETIME);]]
-        local res = [[Type mismatch: can not convert ]]..
-                    [[string('2001-01-01T01:00:00Z') to datetime]]
-        local _, err = box.execute(sql)
-        t.assert_equals(err.message, res)
+        local res = {{dt1}}
+        local rows = box.execute(sql).rows
+        t.assert_equals(rows, res)
     end)
 end
 
@@ -2362,3 +2363,27 @@ g.test_datetime_31_8 = function()
         t.assert_equals(rows, {{itv3}})
     end)
 end
+
+-- Make sure cast from STRING to DATETIME works as intended.
+g.test_datetime_32_1 = function()
+    g.server:exec(function()
+        local t = require('luatest')
+        local dt = require('datetime')
+        local dt1 = dt.new({year = 2000, month = 2, day = 29, hour = 1})
+        local sql = [[SELECT CAST('2000-02-29T01:00:00Z' AS DATETIME);]]
+        local res = {{dt1}}
+        local rows = box.execute(sql).rows
+        t.assert_equals(rows, res)
+    end)
+end
+
+g.test_datetime_32_2 = function()
+    g.server:exec(function()
+        local t = require('luatest')
+        local sql = [[SELECT CAST('2001-02-29T01:00:00Z' AS DATETIME);]]
+        local _, err = box.execute(sql)
+        local res = [[Type mismatch: can not convert ]]..
+                    [[string('2001-02-29T01:00:00Z') to datetime]]
+        t.assert_equals(err.message, res)
+    end)
+end
-- 
GitLab