From 1b8528952725a7d8d0044fdfca7302c94b733449 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Mon, 25 Apr 2016 15:16:56 +0900
Subject: [PATCH 2/2] Largely reduce overhead of localtime() in SQLFetch

localtime() is a very costly system call causing serious grief on
performance of the driver for OLTP-type applications using a lot
SQLFetch and this one is being called for all data types when performing
an in-line conversion, while it is being used only in the case where
some of the date and/or timestamp fields are not initialized. While
testing performance of an internal application, this patch has proved
to improve the overall performance of an application by 20%.
---
 convert.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/convert.c b/convert.c
index 830910a..0d2e07f 100644
--- a/convert.c
+++ b/convert.c
@@ -953,16 +953,6 @@ copy_and_convert_field(StatementClass *stmt,
 
 	memset(&std_time, 0, sizeof(SIMPLE_TIME));
 
-	/* Initialize current date */
-#ifdef	HAVE_LOCALTIME_R
-	tim = localtime_r(&stmt_t, &tm);
-#else
-	tim = localtime(&stmt_t);
-#endif /* HAVE_LOCALTIME_R */
-	std_time.m = tim->tm_mon + 1;
-	std_time.d = tim->tm_mday;
-	std_time.y = tim->tm_year + 1900;
-
 	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax);
 
 	if (!value)
@@ -1607,6 +1597,25 @@ inolog("2stime fr=%d\n", std_time.fr);
 						ds = (DATE_STRUCT *) rgbValueBindRow;
 					else
 						ds = (DATE_STRUCT *) rgbValue + bind_row;
+
+					/*
+					 * Initialize date in case conversion destination
+					 * expects date part from this source time data.
+					 * A value may be partially set here, so do some
+					 * sanity checks on the existing values before
+					 * setting them.
+					 */
+#ifdef HAVE_LOCALTIME_R
+					tim = localtime_r(&stmt_t, &tm);
+#else
+					tim = localtime(&stmt_t);
+#endif /* HAVE_LOCALTIME_R */
+					if (std_time.m == 0)
+						std_time.m = tim->tm_mon + 1;
+					if (std_time.d == 0)
+						std_time.d = tim->tm_mday;
+					if (std_time.y == 0)
+						std_time.y = tim->tm_year + 1900;
 					ds->year = std_time.y;
 					ds->month = std_time.m;
 					ds->day = std_time.d;
@@ -1639,6 +1648,26 @@ inolog("2stime fr=%d\n", std_time.fr);
 						ts = (TIMESTAMP_STRUCT *) rgbValueBindRow;
 					else
 						ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
+
+					/*
+					 * Initialize date in case conversion destination
+					 * expects date part from this source time data.
+					 * A value may be partially set here, so do some
+					 * sanity checks on the existing values before
+					 * setting them.
+					 */
+#ifdef HAVE_LOCALTIME_R
+					tim = localtime_r(&stmt_t, &tm);
+#else
+					tim = localtime(&stmt_t);
+#endif /* HAVE_LOCALTIME_R */
+					if (std_time.m == 0)
+						std_time.m = tim->tm_mon + 1;
+					if (std_time.d == 0)
+						std_time.d = tim->tm_mday;
+					if (std_time.y == 0)
+						std_time.y = tim->tm_year + 1900;
+
 					ts->year = std_time.y;
 					ts->month = std_time.m;
 					ts->day = std_time.d;
@@ -4173,14 +4202,6 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
 	cbuf[0] = '\0';
 	memset(&st, 0, sizeof(st));
 	t = SC_get_time(qb->stmt);
-#ifdef	HAVE_LOCALTIME_R
-	tim = localtime_r(&t, &tm);
-#else
-	tim = localtime(&t);
-#endif /* HAVE_LOCALTIME_R */
-	st.m = tim->tm_mon + 1;
-	st.d = tim->tm_mday;
-	st.y = tim->tm_year + 1900;
 
 	ivstruct = (SQL_INTERVAL_STRUCT *) buffer;
 	/* Convert input C type to a neutral format */
@@ -4326,7 +4347,19 @@ mylog("C_WCHAR=%s(%d)\n", buffer, used);
 				st.hh = ts->hour;
 				st.mm = ts->minute;
 				st.ss = ts->second;
-
+				/*
+				 * Initialize date in case conversion destination
+				 * expects date part from this source time data.
+				 */
+				t = SC_get_time(qb->stmt);
+#ifdef HAVE_LOCALTIME_R
+				tim = localtime_r(&t, &tm);
+#else
+				tim = localtime(&t);
+#endif /* HAVE_LOCALTIME_R */
+				st.m = tim->tm_mon + 1;
+				st.d = tim->tm_mday;
+				st.y = tim->tm_year + 1900;
 				break;
 			}
 
-- 
2.8.1

