LCOV - code coverage report
Current view: top level - src/odbc - convert_tds2sql.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 281 291 96.6 %
Date: 2024-03-23 09:12:27 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-1999  Brian Bruns
       3             :  * Copyright (C) 2003-2010  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <assert.h>
      24             : 
      25             : #if HAVE_STDLIB_H
      26             : #include <stdlib.h>
      27             : #endif /* HAVE_STDLIB_H */
      28             : 
      29             : #if HAVE_STRING_H
      30             : #include <string.h>
      31             : #endif /* HAVE_STRING_H */
      32             : 
      33             : #include <ctype.h>
      34             : 
      35             : #include <freetds/utils.h>
      36             : #include <freetds/odbc.h>
      37             : #include <freetds/convert.h>
      38             : #include <freetds/iconv.h>
      39             : #include <freetds/utils/string.h>
      40             : #include <freetds/encodings.h>
      41             : #include <odbcss.h>
      42             : 
      43             : #define TDS_ISSPACE(c) isspace((unsigned char) (c))
      44             : 
      45             : /**
      46             :  * Copy beginning of column_iconv_buf
      47             :  */
      48             : static void
      49        8744 : eat_iconv_left(TDSCOLUMN * curcol, char **pbuf, size_t *plen)
      50             : {
      51        8744 :         unsigned cp = ODBC_MIN(*plen, curcol->column_iconv_left);
      52        8744 :         memcpy(*pbuf, curcol->column_iconv_buf, cp);
      53        8744 :         if (cp < curcol->column_iconv_left)
      54         642 :                 memmove(curcol->column_iconv_buf, curcol->column_iconv_buf + cp, curcol->column_iconv_left - cp);
      55        8744 :         curcol->column_iconv_left -= cp;
      56        8744 :         *pbuf += cp;
      57        8744 :         *plen -= cp;
      58        8744 : }
      59             : 
      60             : /**
      61             :  * Handle conversions from TDS (N)CHAR to ODBC (W)CHAR
      62             :  */
      63             : static SQLLEN
      64        8506 : odbc_convert_char(TDS_STMT * stmt, TDSCOLUMN * curcol, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen)
      65             : {
      66             :         const char *ib;
      67             :         char *ob;
      68             :         size_t il, ol, char_size;
      69             : 
      70             :         /* FIXME MARS not correct cause is the global tds but stmt->tds can be NULL on SQLGetData */
      71        8506 :         TDSSOCKET *tds = stmt->dbc->tds_socket;
      72             : 
      73        8506 :         TDSICONV *conv = curcol->char_conv;
      74        8506 :         if (!conv)
      75         144 :                 conv = tds->conn->char_convs[client2server_chardata];
      76        8506 :         if (desttype == SQL_C_WCHAR) {
      77        1074 :                 int charset = odbc_get_wide_canonic(tds->conn);
      78             :                 /* SQL_C_WCHAR, convert to wide encode */
      79        1074 :                 conv = tds_iconv_get_info(tds->conn, charset, conv->to.charset.canonic);
      80        1074 :                 if (!conv)
      81           0 :                         conv = tds_iconv_get_info(tds->conn, charset, TDS_CHARSET_ISO_8859_1);
      82             : #ifdef ENABLE_ODBC_WIDE
      83             :         } else {
      84        7432 :                 conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, conv->to.charset.canonic);
      85        7432 :                 if (!conv)
      86           0 :                         conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, TDS_CHARSET_ISO_8859_1);
      87        7432 :                 if (!conv)
      88           0 :                         conv = tds_iconv_get_info(tds->conn, TDS_CHARSET_ISO_8859_1, TDS_CHARSET_ISO_8859_1);
      89             : #endif
      90             :         }
      91             : 
      92        8506 :         ib = src;
      93        8506 :         il = srclen;
      94        8506 :         ob = dest;
      95        8506 :         ol = 0;
      96        8506 :         char_size = desttype == SQL_C_CHAR ? 1 : SIZEOF_SQLWCHAR;
      97        8506 :         if (destlen >= char_size) {
      98        8114 :                 ol = destlen - char_size;
      99             :                 /* copy left and continue only if possible */
     100        8114 :                 eat_iconv_left(curcol, &ob, &ol);
     101        8114 :                 if (ol) {
     102        8084 :                         memset(&conv->suppress, 0, sizeof(conv->suppress));
     103        8084 :                         conv->suppress.eilseq = 1;
     104        8084 :                         conv->suppress.e2big = 1;
     105             :                         /* TODO check return value */
     106        8084 :                         tds_iconv(tds, conv, to_client, &ib, &il, &ob, &ol);
     107             :                 }
     108             :                 /* if input left try to decode on future left */
     109        8114 :                 if (il && ol < sizeof(curcol->column_iconv_buf) && curcol->column_iconv_left == 0) {
     110         630 :                         char *left_ob = curcol->column_iconv_buf;
     111         630 :                         size_t left_ol = sizeof(curcol->column_iconv_buf);
     112         630 :                         conv->suppress.eilseq = 1;
     113         630 :                         conv->suppress.einval = 1;
     114         630 :                         conv->suppress.e2big = 1;
     115         630 :                         tds_iconv(tds, conv, to_client, &ib, &il, &left_ob, &left_ol);
     116         630 :                         curcol->column_iconv_left = sizeof(curcol->column_iconv_buf) - left_ol;
     117             :                         /* copy part to fill buffer */
     118         630 :                         eat_iconv_left(curcol, &ob, &ol);
     119             :                 }
     120        8114 :                 ol = ob - dest; /* bytes written */
     121        8114 :                 curcol->column_text_sqlgetdatapos += ib - src;
     122             :                 /* terminate string */
     123        8114 :                 memset(ob, 0, char_size);
     124             :         }
     125             : 
     126             :         /* returned size have to take into account buffer left unconverted */
     127        8506 :         if (il == 0 || (conv->from.charset.min_bytes_per_char == conv->from.charset.max_bytes_per_char
     128         440 :             && conv->to.charset.min_bytes_per_char == conv->to.charset.max_bytes_per_char)) {
     129        7832 :                 ol += il * conv->from.charset.min_bytes_per_char / conv->to.charset.min_bytes_per_char + curcol->column_iconv_left;
     130         674 :         } else if ((conv->flags & TDS_ENCODING_MEMCPY) != 0) {
     131         222 :                 ol += il + curcol->column_iconv_left;
     132             :         } else {
     133             :                 /* TODO convert and discard ?? or return proper SQL_NO_TOTAL values ?? */
     134             :                 return SQL_NO_TOTAL;
     135             :         }
     136        8054 :         return ol;
     137             : }
     138             : 
     139             : /**
     140             :  * Handle conversions from TDS NCHAR to ISO8859-1 stripping spaces (for fixed types)
     141             :  */
     142             : static int
     143           8 : odbc_tds_convert_wide_iso(TDSCOLUMN *curcol, TDS_CHAR *src, TDS_UINT srclen, TDS_CHAR *buf, TDS_UINT buf_len)
     144             : {
     145             :         TDS_CHAR *p;
     146             :         /*
     147             :          * TODO check for endian
     148             :          * This affect for instance Sybase under little endian system
     149             :          */
     150             :         
     151             :         /* skip white spaces */
     152           8 :         while (srclen > 1 && src[1] == 0 && TDS_ISSPACE(src[0])) {
     153           0 :                 srclen -= 2;
     154           0 :                 src += 2;
     155             :         }
     156             : 
     157             :         /* convert */
     158             :         p = buf;
     159          72 :         while (buf_len > 1 && srclen > 1 && src[1] == 0) {
     160          64 :                 *p++ = src[0];
     161          64 :                 --buf_len;
     162          64 :                 srclen -= 2;
     163          64 :                 src += 2;
     164             :         }
     165             : 
     166             :         /* skip white spaces */
     167           8 :         while (srclen > 1 && src[1] == 0 && TDS_ISSPACE(src[0])) {
     168           0 :                 srclen -= 2;
     169           0 :                 src += 2;
     170             :         }
     171             : 
     172             :         /* still characters, wrong format */
     173           8 :         if (srclen)
     174             :                 return -1;
     175             : 
     176           8 :         *p = 0;
     177           8 :         return p - buf;
     178             : }
     179             : 
     180             : /* The following function is going to write in these structure not using them
     181             :  * but just knowing the ABI. Check these ABI. Mainly make sure the alignment
     182             :  * is still correct.
     183             :  */
     184             : TDS_COMPILE_CHECK(ss_time2, sizeof(SQL_SS_TIME2_STRUCT) == 12
     185             :         && TDS_OFFSET(SQL_SS_TIME2_STRUCT, fraction) == 8);
     186             : TDS_COMPILE_CHECK(ss_timestampoffset, sizeof(SQL_SS_TIMESTAMPOFFSET_STRUCT) == 20
     187             :         && TDS_OFFSET(SQL_SS_TIMESTAMPOFFSET_STRUCT, fraction) == 12);
     188             : TDS_COMPILE_CHECK(date_struct, sizeof(DATE_STRUCT) == 6
     189             :         && TDS_OFFSET(DATE_STRUCT, year) == 0
     190             :         && TDS_OFFSET(DATE_STRUCT, month) == 2
     191             :         && TDS_OFFSET(DATE_STRUCT, day) == 4);
     192             : TDS_COMPILE_CHECK(timestamp_struct, sizeof(TIMESTAMP_STRUCT) == 16
     193             :         && TDS_OFFSET(TIMESTAMP_STRUCT, year) == 0
     194             :         && TDS_OFFSET(TIMESTAMP_STRUCT, month) == 2
     195             :         && TDS_OFFSET(TIMESTAMP_STRUCT, day) == 4
     196             :         && TDS_OFFSET(TIMESTAMP_STRUCT, hour) == 6
     197             :         && TDS_OFFSET(TIMESTAMP_STRUCT, minute) == 8
     198             :         && TDS_OFFSET(TIMESTAMP_STRUCT, second) == 10
     199             :         && TDS_OFFSET(TIMESTAMP_STRUCT, fraction) == 12);
     200             : 
     201             : /**
     202             :  * Handle conversions from MSSQL 2008 DATE/TIME types to binary.
     203             :  * These types have a different binary representation in libTDS.
     204             :  */
     205             : static SQLLEN
     206         154 : odbc_convert_datetime_to_binary(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_DATETIMEALL * dta, TDS_CHAR * dest, SQLULEN destlen)
     207             : {
     208             :         size_t len, cplen;
     209             :         TDS_USMALLINT buf[10];
     210             :         TDSDATEREC when;
     211             : 
     212         154 :         tds_datecrack(srctype, dta, &when);
     213             : 
     214         154 :         len = 0;
     215         154 :         if (srctype != SYBMSTIME && srctype != SYBTIME && srctype != SYB5BIGTIME) {
     216         106 :                 buf[0] = when.year;
     217         106 :                 buf[1] = when.month + 1;
     218         106 :                 buf[2] = when.day;
     219         106 :                 len = 3;
     220             :         }
     221         154 :         if (srctype != SYBMSDATE && srctype != SYBDATE) {
     222         112 :                 buf[len++] = when.hour;
     223         112 :                 buf[len++] = when.minute;
     224         112 :                 buf[len++] = when.second;
     225         112 :                 if ((len % 2) != 0)
     226          48 :                         buf[len++] = 0;
     227         112 :                 *((TDS_UINT*) (buf+len)) = when.decimicrosecond * 100u;
     228         112 :                 len += 2;
     229             :         }
     230         154 :         if (srctype == SYBMSDATETIMEOFFSET) {
     231             :                 /* TODO check for negative hour/minutes */
     232          16 :                 buf[8] = dta->offset / 60;
     233          16 :                 buf[9] = dta->offset % 60;
     234          16 :                 len = 10;
     235             :         }
     236         154 :         len *= 2;
     237             : 
     238             :         /* just return length */
     239         154 :         if (destlen == 0)
     240           0 :                 return len;
     241             : 
     242         154 :         cplen = ODBC_MIN(destlen, len);
     243         154 :         memcpy(dest, buf, cplen);
     244         154 :         if (curcol)
     245         154 :                 curcol->column_text_sqlgetdatapos += cplen;
     246         154 :         return len;
     247             : }
     248             : 
     249             : static SQLLEN
     250        1788 : odbc_convert_to_binary(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_CHAR * src, TDS_UINT srclen, TDS_CHAR * dest, SQLULEN destlen)
     251             : {
     252        1788 :         SQLLEN ret = srclen;
     253             : 
     254             :         /* special case for date/time */
     255        1788 :         switch (srctype) {
     256         154 :         case SYBMSTIME:
     257             :         case SYBMSDATE:
     258             :         case SYBMSDATETIME2:
     259             :         case SYBMSDATETIMEOFFSET:
     260             :         case SYBDATE:
     261             :         case SYBTIME:
     262             :         case SYB5BIGTIME:
     263             :         case SYB5BIGDATETIME:
     264         154 :                 return odbc_convert_datetime_to_binary(stmt, curcol, srctype, (TDS_DATETIMEALL *) src, dest, destlen);
     265             :         }
     266             : 
     267             :         /* if destlen == 0 we return only length */
     268        1634 :         if (destlen > 0) {
     269        1634 :                 size_t cplen = ODBC_MIN(destlen, srclen);
     270             :                 /* do not NUL terminate binary buffer */
     271        1634 :                 memcpy(dest, src, cplen);
     272        1634 :                 if (curcol)
     273        1634 :                         curcol->column_text_sqlgetdatapos += cplen;
     274             :         }
     275             :         return ret;
     276             : }
     277             : 
     278             : static SQLLEN
     279       39888 : odbc_tds2sql(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen,
     280             :              const struct _drecord *drec_ixd)
     281             : {
     282             :         TDS_INT nDestSybType;
     283       39888 :         TDS_INT nRetVal = TDS_CONVERT_FAIL;
     284       39888 :         TDSCONTEXT *context = stmt->dbc->env->tds_ctx;
     285             : 
     286             :         CONV_RESULT ores;
     287             : 
     288       39888 :         SQLLEN ret = SQL_NULL_DATA;
     289             :         int i, cplen;
     290       39888 :         int binary_conversion = 0;
     291             :         TDS_CHAR conv_buf[256];
     292             : 
     293       39888 :         tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype);
     294             : 
     295       39888 :         assert(desttype != SQL_C_DEFAULT);
     296             : 
     297       39888 :         nDestSybType = odbc_c_to_server_type(desttype);
     298       39888 :         if (!nDestSybType) {
     299           8 :                 odbc_errs_add(&stmt->errs, "HY003", NULL);
     300           8 :                 return SQL_NULL_DATA;
     301             :         }
     302             : 
     303             :         /* special case for binary type */
     304       39880 :         if (desttype == SQL_C_BINARY) {
     305        1836 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen);
     306             : 
     307        1836 :                 if (is_numeric_type(srctype)) {
     308          48 :                         desttype = SQL_C_NUMERIC;
     309          48 :                         nDestSybType = SYBNUMERIC;
     310             :                         /* prevent buffer overflow */
     311          48 :                         if (destlen < sizeof(SQL_NUMERIC_STRUCT)) {
     312           0 :                                 odbc_errs_add(&stmt->errs, "07006", NULL);
     313           0 :                                 return SQL_NULL_DATA;
     314             :                         }
     315          48 :                         ores.n.precision = ((TDS_NUMERIC *) src)->precision;
     316          48 :                         ores.n.scale = ((TDS_NUMERIC *) src)->scale;
     317             :                 } else {
     318        1788 :                         return odbc_convert_to_binary(stmt, curcol, srctype, src, srclen, dest, destlen);
     319             :                 }
     320       38044 :         } else if (is_numeric_type(nDestSybType)) {
     321             :                 /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */
     322        1252 :                 if (drec_ixd)
     323         284 :                         ores.n.precision = drec_ixd->sql_desc_precision;
     324             :                 else
     325         968 :                         ores.n.precision = 38;
     326        1252 :                 ores.n.scale = 0;
     327             :         }
     328             : 
     329       38092 :         if (is_char_type(srctype)) {
     330       10186 :                 if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR)
     331        8506 :                         return odbc_convert_char(stmt, curcol, src, srclen, desttype, dest, destlen);
     332        1680 :                 if (is_unicode_type(srctype)) {
     333             :                         /*
     334             :                          * convert to single and then process normally.
     335             :                          * Here we processed SQL_C_BINARY and SQL_C_*CHAR so only fixed types are left
     336             :                          */
     337           8 :                         i = odbc_tds_convert_wide_iso(curcol, src, srclen, conv_buf, sizeof(conv_buf));
     338           8 :                         if (i < 0)
     339             :                                 return SQL_NULL_DATA;
     340           8 :                         src = conv_buf;
     341           8 :                         srclen = i;
     342           8 :                         srctype = SYBVARCHAR;
     343             :                 }
     344             :         }
     345             : 
     346       29586 :         if (desttype == SQL_C_WCHAR)
     347        1208 :                 destlen /= sizeof(SQLWCHAR);
     348       29586 :         if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
     349        2970 :                 if (is_binary_type(srctype)) {
     350         614 :                         binary_conversion = 1;
     351         614 :                         if (destlen && !(destlen % 2))
     352         294 :                                 --destlen;
     353             :                 }
     354             : 
     355        2970 :                 nDestSybType = TDS_CONVERT_CHAR;
     356        2970 :                 ores.cc.len = destlen;
     357        2970 :                 ores.cc.c = dest;
     358             :         }
     359             : 
     360       29586 :         if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
     361             :                 char buf[48];
     362             :                 TDSDATEREC when;
     363             :                 int prec;
     364        2970 :                 const char *fmt = NULL;
     365        2970 :                 const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src;
     366             : 
     367        2970 :                 switch (srctype) {
     368          80 :                 case SYBMSDATETIMEOFFSET:
     369             :                 case SYBMSDATETIME2:
     370          80 :                         prec = dta->time_prec;
     371          80 :                         goto datetime;
     372             :                 case SYB5BIGDATETIME:
     373             :                         prec = 6;
     374             :                         goto datetime;
     375         204 :                 case SYBDATETIME:
     376         204 :                         prec = 3;
     377         204 :                         goto datetime;
     378         112 :                 case SYBDATETIME4:
     379         112 :                         prec = 0;
     380             :                 datetime:
     381             :                         fmt = "%Y-%m-%d %H:%M:%S.%z";
     382             :                         break;
     383          42 :                 case SYBMSTIME:
     384          42 :                         prec = dta->time_prec;
     385          42 :                         goto time;
     386             :                 case SYB5BIGTIME:
     387             :                         prec = 6;
     388             :                         goto time;
     389          52 :                 case SYBTIME:
     390          52 :                         prec = 3;
     391             :                 time:
     392             :                         fmt = "%H:%M:%S.%z";
     393             :                         break;
     394             :                 case SYBMSDATE:
     395             :                 case SYBDATE:
     396             :                         prec = 0;
     397             :                         fmt = "%Y-%m-%d";
     398             :                         break;
     399             :                 }
     400             :                 if (!fmt) goto normal_conversion;
     401             : 
     402         608 :                 tds_datecrack(srctype, src, &when);
     403         608 :                 tds_strftime(buf, sizeof(buf), fmt, &when, prec);
     404             : 
     405         608 :                 if (srctype == SYBMSDATETIMEOFFSET) {
     406          36 :                         char sign = '+';
     407          36 :                         int off = dta->offset;
     408          36 :                         if (off < 0) {
     409           2 :                                 sign = '-';
     410           2 :                                 off = -off;
     411             :                         }
     412          36 :                         sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60);
     413             :                 }
     414             : 
     415         608 :                 nRetVal = strlen(buf);
     416         608 :                 memcpy(dest, buf, ODBC_MIN(destlen, nRetVal));
     417             :         } else {
     418       55594 : normal_conversion:
     419       28978 :                 nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores);
     420             :         }
     421       29586 :         if (nRetVal < 0) {
     422       12096 :                 odbc_convert_err_set(&stmt->errs, nRetVal);
     423       12096 :                 return SQL_NULL_DATA;
     424             :         }
     425             : 
     426       17490 :         switch (desttype) {
     427             : 
     428        1682 :         case SQL_C_CHAR:
     429        1682 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
     430             : 
     431        1682 :                 ret = nRetVal;
     432             :                 /* TODO handle not terminated configuration */
     433        1682 :                 if (destlen > 0) {
     434        1618 :                         cplen = ODBC_MIN(destlen - 1, nRetVal);
     435             :                         assert(cplen >= 0);
     436             :                         /*
     437             :                          * odbc always terminate but do not overwrite 
     438             :                          * destination buffer more than needed
     439             :                          */
     440             :                         /* update datapos only for binary source (char already handled) */
     441        1618 :                         if (curcol && binary_conversion)
     442         182 :                                 curcol->column_text_sqlgetdatapos += cplen / 2;
     443        1618 :                         dest[cplen] = 0;
     444             :                 } else {
     445             :                         /* if destlen == 0 we return only length */
     446             :                 }
     447             :                 break;
     448             : 
     449        1128 :         case SQL_C_WCHAR:
     450        1128 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
     451             : 
     452        1128 :                 ret = nRetVal * sizeof(SQLWCHAR);
     453             :                 /* TODO handle not terminated configuration */
     454        1128 :                 if (destlen > 0) {
     455        1000 :                         SQLWCHAR *wp = (SQLWCHAR *) dest;
     456        1000 :                         SQLCHAR  *p  = (SQLCHAR *)  dest;
     457             : 
     458        1000 :                         cplen = ODBC_MIN(destlen - 1, nRetVal);
     459             :                         assert(cplen >= 0);
     460             :                         /*
     461             :                          * odbc always terminate but do not overwrite 
     462             :                          * destination buffer more than needed
     463             :                          */
     464             :                         /* update datapos only for binary source (char already handled) */
     465        1000 :                         if (curcol && binary_conversion)
     466         240 :                                 curcol->column_text_sqlgetdatapos += cplen / 2;
     467             :                         /* convert in place and terminate */
     468        1000 :                         wp[cplen] = 0;
     469      650536 :                         while (cplen > 0) {
     470      648536 :                                 --cplen;
     471      648536 :                                 wp[cplen] = p[cplen];
     472             :                         }
     473             :                 } else {
     474             :                         /* if destlen == 0 we return only length */
     475             :                 }
     476             :                 break;
     477             : 
     478         614 :         case SQL_C_TYPE_DATE:
     479             :         case SQL_C_DATE:
     480             :                 {
     481             :                         TDSDATEREC dr;
     482         614 :                         DATE_STRUCT *dsp = (DATE_STRUCT *) dest;
     483             : 
     484             :                         /*
     485             :                          * we've already converted the returned value to a SYBMSDATETIME2
     486             :                          * now decompose date into constituent parts...
     487             :                          */
     488         614 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     489             : 
     490         614 :                         dsp->year = dr.year;
     491         614 :                         dsp->month = dr.month + 1;
     492         614 :                         dsp->day = dr.day;
     493             : 
     494         614 :                         ret = sizeof(DATE_STRUCT);
     495             :                 }
     496         614 :                 break;
     497             : 
     498         614 :         case SQL_C_TYPE_TIME:
     499             :         case SQL_C_TIME:
     500             :                 {
     501             :                         TDSDATEREC dr;
     502         614 :                         TIME_STRUCT *tsp = (TIME_STRUCT *) dest;
     503             : 
     504             :                         /*
     505             :                          * we've already converted the returned value to a SYBMSDATETIME2
     506             :                          * now decompose date into constituent parts...
     507             :                          */
     508         614 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     509             : 
     510         614 :                         tsp->hour = dr.hour;
     511         614 :                         tsp->minute = dr.minute;
     512         614 :                         tsp->second = dr.second;
     513             : 
     514         614 :                         ret = sizeof(TIME_STRUCT);
     515             :                 }
     516         614 :                 break;
     517             : 
     518         886 :         case SQL_C_TYPE_TIMESTAMP:
     519             :         case SQL_C_TIMESTAMP: 
     520             :                 {
     521             :                         TDSDATEREC dr;
     522         886 :                         TIMESTAMP_STRUCT *tssp = (TIMESTAMP_STRUCT *) dest;
     523             : 
     524             :                         /*
     525             :                          * we've already converted the returned value to a SYBMSDATETIME2
     526             :                          * now decompose date into constituent parts...
     527             :                          */
     528         886 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     529             : 
     530         886 :                         tssp->year = dr.year;
     531         886 :                         tssp->month = dr.month + 1;
     532         886 :                         tssp->day = dr.day;
     533         886 :                         tssp->hour = dr.hour;
     534         886 :                         tssp->minute = dr.minute;
     535         886 :                         tssp->second = dr.second;
     536         886 :                         tssp->fraction = dr.decimicrosecond * 100u;
     537             : 
     538         886 :                         ret = sizeof(TIMESTAMP_STRUCT);
     539             :                 }
     540         886 :                 break;
     541             : 
     542             : #ifdef SQL_C_SBIGINT
     543        1242 :         case SQL_C_SBIGINT:
     544             :         case SQL_C_UBIGINT:
     545        1242 :                 *((TDS_INT8 *) dest) = ores.bi;
     546        1242 :                 ret = sizeof(TDS_INT8);
     547        1242 :                 break;
     548             : #endif
     549             : 
     550        4250 :         case SQL_C_LONG:
     551             :         case SQL_C_SLONG:
     552             :         case SQL_C_ULONG:
     553        4250 :                 *((TDS_INT *) dest) = ores.i;
     554        4250 :                 ret = sizeof(TDS_INT);
     555        4250 :                 break;
     556             : 
     557        2712 :         case SQL_C_SHORT:
     558             :         case SQL_C_SSHORT:
     559             :         case SQL_C_USHORT:
     560        2712 :                 *((TDS_SMALLINT *) dest) = ores.si;
     561        2712 :                 ret = sizeof(TDS_SMALLINT);
     562        2712 :                 break;
     563             : 
     564        1694 :         case SQL_C_TINYINT:
     565             :         case SQL_C_STINYINT:
     566             :         case SQL_C_UTINYINT:
     567             :         case SQL_C_BIT:
     568        1694 :                 *((TDS_TINYINT *) dest) = ores.ti;
     569        1694 :                 ret = sizeof(TDS_TINYINT);
     570        1694 :                 break;
     571             : 
     572         874 :         case SQL_C_DOUBLE:
     573         874 :                 *((TDS_FLOAT *) dest) = ores.f;
     574         874 :                 ret = sizeof(TDS_FLOAT);
     575         874 :                 break;
     576             : 
     577         832 :         case SQL_C_FLOAT:
     578         832 :                 *((TDS_REAL *) dest) = ores.r;
     579         832 :                 ret = sizeof(TDS_REAL);
     580         832 :                 break;
     581             : 
     582         916 :         case SQL_C_NUMERIC:
     583             :                 {
     584             :                         /* ODBC numeric is quite different from TDS one ... */
     585         916 :                         SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest;
     586         916 :                         num->precision = ores.n.precision;
     587         916 :                         num->scale = ores.n.scale;
     588         916 :                         num->sign = ores.n.array[0] ^ 1;
     589             :                         /*
     590             :                          * TODO can be greater than SQL_MAX_NUMERIC_LEN ?? 
     591             :                          * seeing Sybase manual wire support bigger numeric but currently
     592             :                          * DBs so not support such precision
     593             :                          */
     594         916 :                         i = ODBC_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN);
     595         916 :                         memcpy(num->val, ores.n.array + 1, i);
     596         916 :                         tds_swap_bytes(num->val, i);
     597         916 :                         if (i < SQL_MAX_NUMERIC_LEN)
     598         132 :                                 memset(num->val + i, 0, SQL_MAX_NUMERIC_LEN - i);
     599             :                         ret = sizeof(SQL_NUMERIC_STRUCT);
     600             :                 }
     601             :                 break;
     602             : 
     603             : #ifdef SQL_C_GUID
     604          46 :         case SQL_C_GUID:
     605          46 :                 memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE));
     606          46 :                 ret = sizeof(TDS_UNIQUE);
     607          46 :                 break;
     608             : #endif
     609             : 
     610             :         default:
     611             :                 break;
     612             :         }
     613             : 
     614             :         return ret;
     615             : }
     616             : 
     617       39738 : SQLLEN odbc_tds2sql_col(TDS_STMT * stmt, TDSCOLUMN *curcol, int desttype, TDS_CHAR * dest, SQLULEN destlen,
     618             :                         const struct _drecord *drec_ixd)
     619             : {
     620       39738 :         int srctype = tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size);
     621       39738 :         TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
     622       39738 :         TDS_UINT srclen = curcol->column_cur_size;
     623             : 
     624       39738 :         if (is_blob_col(curcol)) {
     625       12938 :                 if (srctype == SYBLONGBINARY && (
     626         236 :                     curcol->column_usertype == USER_UNICHAR_TYPE ||
     627             :                     curcol->column_usertype == USER_UNIVARCHAR_TYPE))
     628             :                         srctype = SYBNTEXT;
     629       12666 :                 if (srctype == SYBVARIANT)
     630        9864 :                         srctype = ((TDSVARIANT *) src)->type;
     631       12702 :                 src = ((TDSBLOB *) src)->textvalue;
     632             :         }
     633       39738 :         if (is_variable_type(srctype)) {
     634       13306 :                 src += curcol->column_text_sqlgetdatapos;
     635       13306 :                 srclen -= curcol->column_text_sqlgetdatapos;
     636             :         }
     637       39738 :         return odbc_tds2sql(stmt, curcol, srctype, src, srclen, desttype, dest, destlen, drec_ixd);
     638             : }
     639             : 
     640         150 : SQLLEN odbc_tds2sql_int4(TDS_STMT * stmt, TDS_INT *src, int desttype, TDS_CHAR * dest, SQLULEN destlen)
     641             : {
     642         150 :         return odbc_tds2sql(stmt, NULL, SYBINT4, (TDS_CHAR *) src, sizeof(*src),
     643             :                             desttype, dest, destlen, NULL);
     644             : }

Generated by: LCOV version 1.13