@@ -935,26 +935,110 @@ odbc_internal::StatusRecord ConvertFromTimeDSValue(DSValue const& src_dsval,
935935 return status_record;
936936}
937937
938+ odbc_internal::StatusRecord ConvertTimestampStringToChar (
939+ const std::string& timestamp_src_str,
940+ void * dest_buf,
941+ SQLLEN buffer_length,
942+ SQLLEN * res_len) {
943+
944+ SQLLEN timestamp_src_len =
945+ static_cast <SQLLEN >(timestamp_src_str.size ());
946+ auto * dest = reinterpret_cast <char *>(dest_buf);
947+ StatusRecord status_record;
948+
949+ if (buffer_length > timestamp_src_len) {
950+ if (res_len) *res_len = timestamp_src_len;
951+ std::strncpy (dest, timestamp_src_str.c_str (), timestamp_src_len);
952+ dest[timestamp_src_len] = ' \0 ' ;
953+ } else if (20 <= buffer_length && buffer_length <= timestamp_src_len) {
954+ if (res_len) *res_len = buffer_length;
955+ std::strncpy (dest, timestamp_src_str.c_str (), buffer_length - 1 );
956+ dest[buffer_length - 1 ] = ' \0 ' ;
957+ status_record = StatusRecord{SQLStates::k_01004 (), " Data truncated" };
958+ } else {
959+ status_record =
960+ StatusRecord{SQLStates::k_22003 (), " Buffer length is insufficient" };
961+ }
962+ return status_record;
963+ }
964+
965+ odbc_internal::StatusRecord ConvertTimestampStringToWChar (
966+ const std::string& timestamp_src_str,
967+ void * dest_buf,
968+ SQLLEN buffer_length,
969+ SQLLEN * res_len) {
970+
971+ auto wstr_or = Utf8ToUtf16 (timestamp_src_str);
972+ if (!wstr_or) {
973+ return StatusRecord{
974+ SQLStates::k_HY000 (),
975+ " DSValueToWchar Conversion Failed" };
976+ }
977+
978+ std::vector<SQLWCHAR > wstr_data (
979+ wstr_or->begin (), wstr_or->end ());
980+ wstr_data.emplace_back (L' \0 ' );
981+
982+ auto * dest = reinterpret_cast <SQLWCHAR *>(dest_buf);
983+
984+ SQLLEN timestamp_src_len =
985+ static_cast <SQLLEN >(wstr_or->size ());
986+
987+ SQLLEN wchar_capacity =
988+ buffer_length / sizeof (SQLWCHAR );
989+
990+ StatusRecord status_record = StatusRecord::Ok ();
991+
992+ if (wchar_capacity > timestamp_src_len) {
993+ if (res_len) {
994+ *res_len = timestamp_src_len * sizeof (SQLWCHAR );
995+ }
996+
997+ std::memcpy (dest, wstr_data.data (),
998+ timestamp_src_len * sizeof (SQLWCHAR ));
999+
1000+ dest[timestamp_src_len] = L' \0 ' ;
1001+
1002+ } else if (20 <= wchar_capacity &&
1003+ wchar_capacity <= timestamp_src_len) {
1004+
1005+ if (res_len) {
1006+ *res_len = wchar_capacity * sizeof (SQLWCHAR );
1007+ }
1008+
1009+ std::memcpy (dest, wstr_data.data (),
1010+ wchar_capacity * sizeof (SQLWCHAR ));
1011+
1012+ dest[wchar_capacity - 1 ] = L' \0 ' ;
1013+
1014+ status_record =
1015+ StatusRecord{SQLStates::k_01004 (),
1016+ " Data truncated" };
1017+
1018+ } else {
1019+
1020+ status_record =
1021+ StatusRecord{SQLStates::k_22003 (),
1022+ " Buffer length is insufficient" };
1023+ }
1024+
1025+ return status_record;
1026+ }
1027+
9381028odbc_internal::StatusRecord ConvertFromTimestampDSValue (
9391029 DSValue const & src_dsval, DataBuffer& dest_data) {
940- using odbc_internal::SQLStates;
941- using odbc_internal::StatusRecord;
942- using odbc_internal::StatusRecordOr;
9431030
944- SQL_TIMESTAMP_STRUCT timestamp_src_struct ;
945- DSValueToTimestamp (src_dsval, timestamp_src_struct) ;
1031+ using odbc_internal::SQLStates ;
1032+ using odbc_internal::StatusRecord ;
9461033
947- std::string timestamp_src_str;
948- timestamp_src_str = FormatTimestampToString (timestamp_src_struct);
949-
950- SQLSMALLINT dest_type = dest_data.type ;
951- SQLPOINTER dest_buf = dest_data.buf ;
952- SQLLEN buffer_length = dest_data.buflen ;
953- SQLLEN * res_len = dest_data.result_len ;
1034+ std::string str_val;
1035+ DSValueToString (src_dsval, str_val);
1036+ std::string timestamp_src_str;
9541037
955- // Define length variables
956- int k_timestamp_src_len = timestamp_src_str.length ();
957- constexpr int kTimestampBinaryLength = sizeof (SQL_TIMESTAMP_STRUCT );
1038+ SQLSMALLINT dest_type = dest_data.type ;
1039+ SQLPOINTER dest_buf = dest_data.buf ;
1040+ SQLLEN buffer_length = dest_data.buflen ;
1041+ SQLLEN * res_len = dest_data.result_len ;
9581042
9591043 if (!dest_buf) {
9601044 return StatusRecord::Ok ();
@@ -965,82 +1049,76 @@ odbc_internal::StatusRecord ConvertFromTimestampDSValue(
9651049 return StatusRecord{SQLStates::k_HY090 (), " Invalid Buffer length" };
9661050 }
9671051
968- StatusRecord status_record = StatusRecord::Ok ();
1052+ StatusRecord status_record = StatusRecord::Ok ();
9691053
970- switch (dest_type) {
971- case SQL_C_CHAR : {
972- auto * dest = reinterpret_cast <char *>(dest_buf);
973- if (buffer_length > k_timestamp_src_len) {
974- if (res_len) {
975- *res_len = k_timestamp_src_len;
1054+ // --- Check for ISO string with 'T' and long fraction ---
1055+ auto t_pos = str_val.find (' T' );
1056+ if (t_pos != std::string::npos) {
1057+ auto dot_pos = str_val.find (' .' , t_pos);
1058+ bool long_fraction = false ;
1059+
1060+ if (dot_pos != std::string::npos) {
1061+ std::size_t fraction_length = str_val.size () - dot_pos - 1 ;
1062+ if (!str_val.empty () && str_val.back () == ' Z' ) --fraction_length;
1063+ if (fraction_length > 9 ) long_fraction = true ;
9761064 }
977- std::strncpy (dest, timestamp_src_str.c_str (), k_timestamp_src_len);
978- dest[k_timestamp_src_len] = ' \0 ' ;
979- } else if (20 <= buffer_length && buffer_length <= k_timestamp_src_len) {
980- if (res_len) {
981- *res_len = buffer_length;
1065+
1066+ if (long_fraction) {
1067+ // Trim 'Z' and replace 'T' with space
1068+ if (!str_val.empty () && str_val.back () == ' Z' ) str_val.pop_back ();
1069+ str_val[t_pos] = ' ' ;
1070+ timestamp_src_str = str_val;
1071+
1072+ switch (dest_type) {
1073+ case SQL_C_CHAR :
1074+ return ConvertTimestampStringToChar (timestamp_src_str, dest_buf, buffer_length, res_len);
1075+ case SQL_C_WCHAR :
1076+ return ConvertTimestampStringToWChar (timestamp_src_str, dest_buf, buffer_length, res_len);
1077+ default :
1078+ LOG (ERROR ) << " ConvertFromTimestampDSValue:: Conversion unsupported for picosecond for C-type: " << dest_type;
1079+ return StatusRecord{SQLStates::k_HY000 (), " Conversion unsupported for picosecond" };
1080+ }
9821081 }
983- std::strncpy (dest, timestamp_src_str.c_str (), buffer_length - 1 );
984- dest[buffer_length - 1 ] = ' \0 ' ;
985- LOG (WARNING )
986- << " ConvertFromTimestampDSValue:: Data truncated for SQL_C_CHAR." ;
987- status_record = StatusRecord{SQLStates::k_01004 (), " Data truncated" };
988- } else {
989- LOG (ERROR ) << " ConvertFromTimestampDSValue:: Buffer length is "
990- " insufficient for SQL_C_CHAR." ;
991- status_record =
992- StatusRecord{SQLStates::k_22003 (), " Buffer length is insufficient" };
993- }
994- break ;
9951082 }
1083+ // Conversion for unix epoch time
1084+ bool looks_like_float_epoch = false ;
9961085
997- case SQL_C_WCHAR : {
998- StatusRecordOr<std::wstring> wstr = Utf8ToUtf16 (timestamp_src_str);
999- if (!wstr) {
1000- LOG (ERROR )
1001- << " ConvertFromTimestampDSValue:: DSValueToWchar Conversion Failed" ;
1002- status_record = StatusRecord{SQLStates::k_HY000 (),
1003- " DSValueToWchar Conversion Failed" };
1004- break ;
1005- }
1006- std::vector<SQLWCHAR > wstr_data (wstr->begin (), wstr->end ());
1007- wstr_data.emplace_back (L' \0 ' );
1086+ try {
1087+ size_t idx = 0 ;
1088+ std::stod (str_val, &idx);
1089+ if (idx == str_val.length ()) {
1090+ looks_like_float_epoch = true ;
1091+ }
1092+ } catch (...) {
1093+ looks_like_float_epoch = false ;
1094+ }
1095+ SQL_TIMESTAMP_STRUCT timestamp_src_struct ;
1096+ if (looks_like_float_epoch) {
1097+ timestamp_src_str = FloatTimestampToString (str_val);
1098+ timestamp_src_struct= ConvertStrToTimestampStruct (timestamp_src_str);
1099+ } else {
1100+ DSValueToTimestamp (src_dsval, timestamp_src_struct);
1101+ timestamp_src_str =
1102+ FormatTimestampToString (timestamp_src_struct);
1103+ }
1104+ int k_timestamp_src_len = static_cast <int >(timestamp_src_str.length ());
1105+ constexpr int kTimestampBinaryLength = sizeof (SQL_TIMESTAMP_STRUCT );
10081106
1009- auto * dest = reinterpret_cast <SQLWCHAR *>(dest_buf);
1010- SQLLEN wchar_capacity = buffer_length / sizeof (SQLWCHAR );
1011- if (wchar_capacity > k_timestamp_src_len) {
1012- if (res_len) {
1013- *res_len = k_timestamp_src_len * sizeof (SQLWCHAR );
1014- }
1015- std::memcpy (dest, wstr_data.data (),
1016- (k_timestamp_src_len) * sizeof (SQLWCHAR ));
1017- dest[k_timestamp_src_len] = L' \0 ' ;
1018- } else if (20 <= wchar_capacity &&
1019- wchar_capacity <= k_timestamp_src_len) {
1020- if (res_len) {
1021- *res_len = wchar_capacity * sizeof (SQLWCHAR );
1022- }
1023- std::memcpy (dest, wstr_data.data (),
1024- (wchar_capacity) * sizeof (SQLWCHAR ));
1025- dest[wchar_capacity - 1 ] = L' \0 ' ;
1026- LOG (WARNING )
1027- << " ConvertFromTimestampDSValue:: Data truncated for SQL_C_WCHAR." ;
1028- status_record = StatusRecord{SQLStates::k_01004 (), " Data truncated" };
1029- } else {
1030- LOG (ERROR ) << " ConvertFromTimestampDSValue:: Buffer length is "
1031- " insufficient for SQL_C_WCHAR." ;
1032- status_record =
1033- StatusRecord{SQLStates::k_22003 (), " Buffer length is insufficient" };
1034- }
1107+ switch (dest_type) {
1108+ case SQL_C_CHAR :
1109+ status_record = ConvertTimestampStringToChar (timestamp_src_str, dest_buf, buffer_length, res_len);
1110+ break ;
1111+
1112+ case SQL_C_WCHAR :
1113+ status_record = ConvertTimestampStringToWChar (timestamp_src_str, dest_buf, buffer_length, res_len);
10351114 break ;
1036- }
10371115
10381116 case SQL_C_BINARY : {
10391117 if (kTimestampBinaryLength <= buffer_length) {
10401118 if (res_len) {
10411119 *res_len = kTimestampBinaryLength ;
10421120 }
1043- timestamp_src_struct.fraction = timestamp_src_struct.fraction * 1000 ;
1121+ timestamp_src_struct.fraction = timestamp_src_struct.fraction ;
10441122 std::memcpy (dest_buf, ×tamp_src_struct, kTimestampBinaryLength );
10451123
10461124 } else {
@@ -1214,7 +1292,7 @@ odbc_internal::StatusRecord ConvertFromDatetimeDSValue(DSValue const& src_dsval,
12141292 if (res_len) {
12151293 *res_len = kDatetimeBinaryLength ;
12161294 }
1217- datetime_src_struct.fraction = datetime_src_struct.fraction * 1000 ;
1295+ datetime_src_struct.fraction = datetime_src_struct.fraction ;
12181296 std::memcpy (dest_buf, &datetime_src_struct, kDatetimeBinaryLength );
12191297
12201298 } else {
0 commit comments