CS_RETCODE cs_dt_crack(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec) { TDS_DATETIME *dt; TDS_DATETIME4 *dt4; TDSDATEREC dr; tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec); if (datetype == CS_DATETIME_TYPE) { dt = (TDS_DATETIME *) dateval; tds_datecrack(SYBDATETIME, dt, &dr); } else if (datetype == CS_DATETIME4_TYPE) { dt4 = (TDS_DATETIME4 *) dateval; tds_datecrack(SYBDATETIME4, dt4, &dr); } else { return CS_FAIL; } daterec->dateyear = dr.year; daterec->datemonth = dr.month; daterec->datedmonth = dr.day; daterec->datedyear = dr.dayofyear; daterec->datedweek = dr.weekday; daterec->datehour = dr.hour; daterec->dateminute = dr.minute; daterec->datesecond = dr.second; daterec->datemsecond = dr.millisecond; daterec->datetzone = 0; return CS_SUCCEED; }
static SQLLEN odbc_convert_msdatetime_to_binary(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_DATETIMEALL * dta, TDS_CHAR * dest, SQLULEN destlen) { size_t len, cplen; TDS_USMALLINT buf[10]; TDSDATEREC when; tds_datecrack(srctype, dta, &when); len = 0; if (srctype != SYBMSTIME) { buf[0] = when.year; buf[1] = when.month + 1; buf[2] = when.day; len = 3; } if (srctype != SYBMSDATE) { buf[len++] = when.hour; buf[len++] = when.minute; buf[len++] = when.second; if ((len % 2) != 0) buf[len++] = 0; *((TDS_UINT*) (buf+len)) = when.decimicrosecond * 100u; len += 2; } if (srctype == SYBMSDATETIMEOFFSET) { /* TODO check for negative hour/minutes */ buf[8] = dta->offset / 60; buf[9] = dta->offset % 60; len = 10; } len *= 2; /* just return length */ if (destlen == 0) return len; cplen = (destlen > len) ? len : destlen; memcpy(dest, buf, cplen); if (curcol) curcol->column_text_sqlgetdatapos += cplen; return len; }
wxDateTime TdsResultSet::GetResultDate(int nField) { // Don't use nField-1 here since GetResultString will take care of that TDSCOLUMN* curcol = m_pDatabase->current_results->columns[nField-1]; TDS_DATETIME* dateTime = (TDS_DATETIME*) curcol->column_data; //fprintf(stderr, "Retrieved dtdays = %d, dttime = %d\n", dateTime->dtdays, dateTime->dttime); if (curcol->column_cur_size < 0) return wxInvalidDateTime; TDSDATEREC dateRec; TDS_INT nReturn = tds_datecrack(/*curcol->on_server.column_type*/SYBDATETIME, dateTime, &dateRec); if (nReturn == TDS_FAIL) return wxInvalidDateTime; //fprintf(stderr, "Second retrieved as %d\n", dateRec.second); wxDateTime date; date.Set(dateRec.day, wxDateTime::Month(dateRec.month), dateRec.year, dateRec.hour, dateRec.minute, dateRec.second, dateRec.millisecond); return date; }
SQLLEN odbc_tds2sql(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen, const struct _drecord *drec_ixd) { TDS_INT nDestSybType; TDS_INT nRetVal = TDS_CONVERT_FAIL; TDSCONTEXT *context = stmt->dbc->env->tds_ctx; CONV_RESULT ores; SQLLEN ret = SQL_NULL_DATA; int i, cplen; int binary_conversion = 0; TDS_CHAR conv_buf[256]; tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype); assert(desttype != SQL_C_DEFAULT); if (curcol) { if (is_blob_col(curcol)) { if (srctype == SYBLONGBINARY && ( curcol->column_usertype == USER_UNICHAR_TYPE || curcol->column_usertype == USER_UNIVARCHAR_TYPE)) srctype = SYBTEXT; if (curcol->column_type == SYBVARIANT) srctype = ((TDSVARIANT *) src)->type; src = ((TDSBLOB *) src)->textvalue; } if (is_variable_type(curcol->column_type)) { src += curcol->column_text_sqlgetdatapos; srclen -= curcol->column_text_sqlgetdatapos; } } nDestSybType = odbc_c_to_server_type(desttype); if (!nDestSybType) { odbc_errs_add(&stmt->errs, "HY003", NULL); return SQL_NULL_DATA; } /* special case for binary type */ if (desttype == SQL_C_BINARY) { tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen); if (is_numeric_type(srctype)) { desttype = SQL_C_NUMERIC; nDestSybType = SYBNUMERIC; /* prevent buffer overflow */ if (destlen < sizeof(SQL_NUMERIC_STRUCT)) { odbc_errs_add(&stmt->errs, "07006", NULL); return SQL_NULL_DATA; } ores.n.precision = ((TDS_NUMERIC *) src)->precision; ores.n.scale = ((TDS_NUMERIC *) src)->scale; } else { return odbc_convert_to_binary(stmt, curcol, srctype, src, srclen, dest, destlen); } } else if (is_numeric_type(nDestSybType)) { /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */ if (drec_ixd) ores.n.precision = drec_ixd->sql_desc_precision; else ores.n.precision = 38; ores.n.scale = 0; } if (is_char_type(srctype)) { if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) return odbc_convert_char(stmt, curcol, src, srclen, desttype, dest, destlen); if (is_unicode_type(srctype)) { /* * convert to single and then process normally. * Here we processed SQL_C_BINARY and SQL_C_*CHAR so only fixed types are left */ i = odbc_tds_convert_wide_iso(curcol, src, srclen, conv_buf, sizeof(conv_buf)); if (i < 0) return SQL_NULL_DATA; src = conv_buf; srclen = i; srctype = SYBVARCHAR; } } if (desttype == SQL_C_WCHAR) destlen /= sizeof(SQLWCHAR); if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) { switch (srctype) { case SYBLONGBINARY: case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY: binary_conversion = 1; if (destlen && !(destlen % 2)) --destlen; } nDestSybType = TDS_CONVERT_CHAR; ores.cc.len = destlen; ores.cc.c = dest; } if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) { char buf[48]; TDSDATEREC when; int prec = 3; const char *fmt = NULL; const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src; switch (srctype) { case SYBMSDATETIMEOFFSET: case SYBMSDATETIME2: prec = dta->time_prec; case SYBDATETIME: fmt = "%Y-%m-%d %H:%M:%S.%z"; if (prec) break; case SYBDATETIME4: fmt = "%Y-%m-%d %H:%M:%S"; break; case SYBMSTIME: prec = dta->time_prec; fmt = prec ? "%H:%M:%S.%z" : "%H:%M:%S"; break; case SYBMSDATE: fmt = "%Y-%m-%d"; break; } if (!fmt) goto normal_conversion; tds_datecrack(srctype, src, &when); tds_strftime(buf, sizeof(buf), fmt, &when, prec); if (srctype == SYBMSDATETIMEOFFSET) { char sign = '+'; int off = dta->offset; if (off < 0) { sign = '-'; off = -off; } sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60); } nRetVal = strlen(buf); memcpy(dest, buf, destlen < nRetVal ? destlen : nRetVal); } else { normal_conversion: nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores); } if (nRetVal < 0) { odbc_convert_err_set(&stmt->errs, nRetVal); return SQL_NULL_DATA; } switch (desttype) { case SQL_C_CHAR: tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen); ret = nRetVal; /* TODO handle not terminated configuration */ if (destlen > 0) { cplen = (destlen - 1) > nRetVal ? nRetVal : (destlen - 1); assert(cplen >= 0); /* * odbc always terminate but do not overwrite * destination buffer more than needed */ /* update datapos only for binary source (char already handled) */ if (curcol && binary_conversion) curcol->column_text_sqlgetdatapos += cplen / 2; dest[cplen] = 0; } else { /* if destlen == 0 we return only length */ } break; case SQL_C_WCHAR: tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen); ret = nRetVal * sizeof(SQLWCHAR); /* TODO handle not terminated configuration */ if (destlen > 0) { SQLWCHAR *wp = (SQLWCHAR *) dest; SQLCHAR *p = (SQLCHAR *) dest; cplen = (destlen - 1) > nRetVal ? nRetVal : (destlen - 1); assert(cplen >= 0); /* * odbc always terminate but do not overwrite * destination buffer more than needed */ /* update datapos only for binary source (char already handled) */ if (curcol && binary_conversion) curcol->column_text_sqlgetdatapos += cplen / 2; /* convert in place and terminate */ wp[cplen] = 0; while (cplen > 0) { --cplen; wp[cplen] = p[cplen]; } } else { /* if destlen == 0 we return only length */ } break; case SQL_C_TYPE_DATE: case SQL_C_DATE: { TDSDATEREC dr; DATE_STRUCT *dsp = (DATE_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); dsp->year = dr.year; dsp->month = dr.month + 1; dsp->day = dr.day; ret = sizeof(DATE_STRUCT); } break; case SQL_C_TYPE_TIME: case SQL_C_TIME: { TDSDATEREC dr; TIME_STRUCT *tsp = (TIME_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); tsp->hour = dr.hour; tsp->minute = dr.minute; tsp->second = dr.second; ret = sizeof(TIME_STRUCT); } break; case SQL_C_TYPE_TIMESTAMP: case SQL_C_TIMESTAMP: { TDSDATEREC dr; TIMESTAMP_STRUCT *tssp = (TIMESTAMP_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); tssp->year = dr.year; tssp->month = dr.month + 1; tssp->day = dr.day; tssp->hour = dr.hour; tssp->minute = dr.minute; tssp->second = dr.second; tssp->fraction = dr.decimicrosecond * 100u; ret = sizeof(TIMESTAMP_STRUCT); } break; #ifdef SQL_C_SBIGINT case SQL_C_SBIGINT: case SQL_C_UBIGINT: *((TDS_INT8 *) dest) = ores.bi; ret = sizeof(TDS_INT8); break; #endif case SQL_C_LONG: case SQL_C_SLONG: case SQL_C_ULONG: *((TDS_INT *) dest) = ores.i; ret = sizeof(TDS_INT); break; case SQL_C_SHORT: case SQL_C_SSHORT: case SQL_C_USHORT: *((TDS_SMALLINT *) dest) = ores.si; ret = sizeof(TDS_SMALLINT); break; case SQL_C_TINYINT: case SQL_C_STINYINT: case SQL_C_UTINYINT: case SQL_C_BIT: *((TDS_TINYINT *) dest) = ores.ti; ret = sizeof(TDS_TINYINT); break; case SQL_C_DOUBLE: *((TDS_FLOAT *) dest) = ores.f; ret = sizeof(TDS_FLOAT); break; case SQL_C_FLOAT: *((TDS_REAL *) dest) = ores.r; ret = sizeof(TDS_REAL); break; case SQL_C_NUMERIC: { /* ODBC numeric is quite different from TDS one ... */ SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest; num->precision = ores.n.precision; num->scale = ores.n.scale; num->sign = ores.n.array[0] ^ 1; /* * TODO can be greater than SQL_MAX_NUMERIC_LEN ?? * seeing Sybase manual wire support bigger numeric but currently * DBs so not support such precision */ i = ODBC_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN); memcpy(num->val, ores.n.array + 1, i); tds_swap_bytes(num->val, i); if (i < SQL_MAX_NUMERIC_LEN) memset(num->val + i, 0, SQL_MAX_NUMERIC_LEN - i); ret = sizeof(SQL_NUMERIC_STRUCT); } break; #ifdef SQL_C_GUID case SQL_C_GUID: memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE)); ret = sizeof(TDS_UNIQUE); break; #endif case SQL_C_BINARY: /* type already handled */ assert(desttype != SQL_C_BINARY); default: break; } return ret; }