From bcbf48259f46a47e7d2b47fab1470a9553c950a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Wed, 18 Feb 2015 14:17:33 +0100
Subject: [PATCH] Odbc: big_typed_query() now knows about time values.

---
 lib/modules/Sql.pmod/odbc.pike | 38 ++++++++++++++++++++++++++++++++++
 src/modules/Odbc/odbc_result.c | 33 +++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/lib/modules/Sql.pmod/odbc.pike b/lib/modules/Sql.pmod/odbc.pike
index 2fbc1d5ad9..2442fa3cb5 100644
--- a/lib/modules/Sql.pmod/odbc.pike
+++ b/lib/modules/Sql.pmod/odbc.pike
@@ -51,6 +51,44 @@ class typed_result
     return Gmp.mpq(mantissa, 10->pow(-scale));
   }
 
+  //! Time of day.
+  class TOD(int hour, int minute, int second,
+	    int|void nanos)
+  {
+    protected string _sprintf(int c)
+    {
+      if (nanos) {
+	return sprintf("%02d:%02d:%02d.%09d",
+		       hour, minute, second, nanos);
+      }
+      return sprintf("%02d:%02d:%02d", hour, minute, second);
+    }
+
+    protected mixed cast(string t)
+    {
+      switch(t) {
+      case "string":
+	return _sprintf('s');
+      case "int":
+	// Number of seconds since the start of the day.
+	return (hour*60 + minute)*60 + second;
+      case "float":
+	int seconds = cast("int");
+	return seconds + nanos/1000000000.0;
+      }
+      return UNDEFINED;
+    }
+  }
+
+  //! Function called to create time of day objects.
+  //!
+  //! The default implementation just passes along its
+  //! arguments to @[TOD].
+  TOD time_factory(int hour, int minute, int second, int|void nanos)
+  {
+    return TOD(hour, minute, second, nanos);
+  }
+
   //! Function called to create timestamp and date objects.
   //!
   //! @note
diff --git a/src/modules/Odbc/odbc_result.c b/src/modules/Odbc/odbc_result.c
index 95ee1188f4..8f1fdb18bd 100644
--- a/src/modules/Odbc/odbc_result.c
+++ b/src/modules/Odbc/odbc_result.c
@@ -71,6 +71,7 @@ int odbc_result_fun_num = -1;
 int odbc_typed_result_fun_num = -1;
 
 static int scale_numeric_fun_num = -1;
+static int time_factory_fun_num = -1;
 static int timestamp_factory_fun_num = -1;
 
 /*
@@ -211,6 +212,25 @@ static void push_numeric(int i)
   free_string(data);
 }
 
+static void push_time(int i)
+{
+  struct pike_string *data = Pike_sp[-1].u.string;
+  struct tagTIME_STRUCT *time = (struct tagTIME_STRUCT *)(data->str);
+  if (data->len < sizeof(struct tagTIME_STRUCT)) {
+    return;
+  }
+  Pike_sp--;
+  push_int(time->hour);
+  push_int(time->minute);
+  push_int(time->second);
+#if 0
+  /* New in struct tagSS_TIME2_STRUCT. */
+  push_int(time->fraction);	/* ns */
+#endif
+  free_string(data);
+  apply_current(time_factory_fun_num, 3);
+}
+
 static void push_date(int i)
 {
   struct pike_string *data = Pike_sp[-1].u.string;
@@ -427,6 +447,12 @@ static void odbc_fix_fields(void)
       field_info[i].factory = push_date;
       break;
     case SQL_SS_TIME2:
+      /* This corresponds to MSSQL time, and is time of day
+       * with nanosecond precision.
+       *
+       * FIXME: We just convert it to SQL_C_TYPE_TIME for now.
+       */
+      /* FALL_THROUGH */
     case SQL_TIME:
       push_text("time");
       field_info[i].type = SQL_C_WCHAR;
@@ -434,6 +460,9 @@ static void odbc_fix_fields(void)
        *       wants bytes.
        */
       field_info[i].size = 32 * (ptrdiff_t)sizeof(SQLWCHAR);
+      field_info[i].bin_type = SQL_C_TYPE_TIME;
+      field_info[i].bin_size = sizeof(struct tagTIME_STRUCT);
+      field_info[i].factory = push_time;
       break;
     case SQL_SS_TIMESTAMPOFFSET:
       /* This corresponds to MSSQL datetimeoffset, and is
@@ -1336,6 +1365,10 @@ void init_odbc_res_programs(void)
     ADD_FUNCTION("scale_numeric", NULL,
 		 tFunc(tInt tInt, tOr(tInt, tObj)),
 		 ID_PUBLIC);
+  time_factory_fun_num =
+    ADD_FUNCTION("time_factory", NULL,
+		 tFunc(tInt tInt tInt tOr(tInt, tVoid), tMix),
+		 ID_PUBLIC);
   timestamp_factory_fun_num =
     ADD_FUNCTION("timestamp_factory", NULL,
 		 tFunc(tInt tInt tInt
-- 
GitLab