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

Generated by: LCOV version 1.13