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-04-15 09:57:00 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       13260 : eat_iconv_left(TDSCOLUMN * curcol, char **pbuf, size_t *plen)
      50             : {
      51       13260 :         unsigned cp = (unsigned) TDS_MIN(*plen, curcol->column_iconv_left);
      52       13260 :         memcpy(*pbuf, curcol->column_iconv_buf, cp);
      53       13260 :         if (cp < curcol->column_iconv_left)
      54         828 :                 memmove(curcol->column_iconv_buf, curcol->column_iconv_buf + cp, curcol->column_iconv_left - cp);
      55       13260 :         curcol->column_iconv_left -= cp;
      56       13260 :         *pbuf += cp;
      57       13260 :         *plen -= cp;
      58       13260 : }
      59             : 
      60             : /**
      61             :  * Handle conversions from TDS (N)CHAR to ODBC (W)CHAR
      62             :  */
      63             : static SQLLEN
      64       12952 : 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       12952 :         TDSSOCKET *tds = stmt->dbc->tds_socket;
      73             : 
      74       12952 :         TDSICONV *conv = curcol->char_conv;
      75       12952 :         if (!conv)
      76         180 :                 conv = tds->conn->char_convs[client2server_chardata];
      77       12952 :         if (desttype == SQL_C_WCHAR) {
      78        1386 :                 int charset = odbc_get_wide_canonic(tds->conn);
      79             :                 /* SQL_C_WCHAR, convert to wide encode */
      80        1386 :                 conv = tds_iconv_get_info(tds->conn, charset, conv->to.charset.canonic);
      81        1386 :                 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       11566 :                 conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, conv->to.charset.canonic);
      86       11566 :                 if (!conv)
      87           0 :                         conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, TDS_CHARSET_ISO_8859_1);
      88       11566 :                 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       12952 :         ib = src;
      94       12952 :         il = srclen;
      95       12952 :         ob = dest;
      96       12952 :         ol = 0;
      97       12952 :         char_size = desttype == SQL_C_CHAR ? 1 : SIZEOF_SQLWCHAR;
      98       12952 :         if (destlen >= char_size) {
      99       12448 :                 ol = destlen - char_size;
     100             :                 /* copy left and continue only if possible */
     101       12448 :                 eat_iconv_left(curcol, &ob, &ol);
     102       12448 :                 if (ol) {
     103       12408 :                         memset(&conv->suppress, 0, sizeof(conv->suppress));
     104       12408 :                         conv->suppress.eilseq = 1;
     105       12408 :                         conv->suppress.e2big = 1;
     106             :                         /* TODO check return value */
     107       12408 :                         tds_iconv(tds, conv, to_client, &ib, &il, &ob, &ol);
     108             :                 }
     109             :                 /* if input left try to decode on future left */
     110       12448 :                 if (il && ol < sizeof(curcol->column_iconv_buf) && curcol->column_iconv_left == 0) {
     111         812 :                         char *left_ob = curcol->column_iconv_buf;
     112         812 :                         size_t left_ol = sizeof(curcol->column_iconv_buf);
     113         812 :                         conv->suppress.eilseq = 1;
     114         812 :                         conv->suppress.einval = 1;
     115         812 :                         conv->suppress.e2big = 1;
     116         812 :                         tds_iconv(tds, conv, to_client, &ib, &il, &left_ob, &left_ol);
     117         812 :                         curcol->column_iconv_left = sizeof(curcol->column_iconv_buf) - (unsigned char) left_ol;
     118             :                         /* copy part to fill buffer */
     119         812 :                         eat_iconv_left(curcol, &ob, &ol);
     120             :                 }
     121       12448 :                 ol = ob - dest; /* bytes written */
     122       12448 :                 curcol->column_text_sqlgetdatapos += (TDS_INT) (ib - src);
     123             :                 /* terminate string */
     124       12448 :                 memset(ob, 0, char_size);
     125             :         }
     126             : 
     127             :         /* returned size have to take into account buffer left unconverted */
     128       12952 :         if (il == 0 || (conv->from.charset.min_bytes_per_char == conv->from.charset.max_bytes_per_char
     129         566 :             && conv->to.charset.min_bytes_per_char == conv->to.charset.max_bytes_per_char)) {
     130       12078 :                 ol += il * conv->from.charset.min_bytes_per_char / conv->to.charset.min_bytes_per_char + curcol->column_iconv_left;
     131         874 :         } else if ((conv->flags & TDS_ENCODING_MEMCPY) != 0) {
     132         296 :                 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       12374 :         return ol;
     138             : }
     139             : 
     140             : /**
     141             :  * Handle conversions from TDS NCHAR to ISO8859-1 stripping spaces (for fixed types)
     142             :  */
     143             : static int
     144          10 : 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          20 :         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          90 :         while (buf_len > 1 && srclen > 1 && src[1] == 0) {
     161          80 :                 *p++ = src[0];
     162          80 :                 --buf_len;
     163          80 :                 srclen -= 2;
     164          80 :                 src += 2;
     165             :         }
     166             : 
     167             :         /* skip white spaces */
     168          10 :         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          10 :         if (srclen)
     175             :                 return -1;
     176             : 
     177          10 :         *p = 0;
     178          10 :         return (int) (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         212 : odbc_convert_datetime_to_binary(TDSCOLUMN *curcol, int srctype, TDS_DATETIMEALL * dta, TDS_CHAR * dest, SQLULEN destlen)
     208             : {
     209             :         TDS_INT len, cplen;
     210             :         TDS_USMALLINT buf[10];
     211             :         TDSDATEREC when;
     212             : 
     213         212 :         tds_datecrack(srctype, dta, &when);
     214             : 
     215         212 :         len = 0;
     216         212 :         if (srctype != SYBMSTIME && srctype != SYBTIME && srctype != SYB5BIGTIME) {
     217         152 :                 buf[0] = when.year;
     218         152 :                 buf[1] = when.month + 1;
     219         152 :                 buf[2] = when.day;
     220         152 :                 len = 3;
     221             :         }
     222         212 :         if (srctype != SYBMSDATE && srctype != SYBDATE) {
     223         158 :                 buf[len++] = when.hour;
     224         158 :                 buf[len++] = when.minute;
     225         158 :                 buf[len++] = when.second;
     226         158 :                 if ((len % 2) != 0)
     227          60 :                         buf[len++] = 0;
     228         158 :                 *((TDS_UINT*) (buf+len)) = when.decimicrosecond * 100u;
     229         158 :                 len += 2;
     230             :         }
     231         212 :         if (srctype == SYBMSDATETIMEOFFSET) {
     232             :                 /* TODO check for negative hour/minutes */
     233          20 :                 buf[8] = dta->offset / 60;
     234          20 :                 buf[9] = dta->offset % 60;
     235          20 :                 len = 10;
     236             :         }
     237         212 :         len *= 2;
     238             : 
     239             :         /* just return length */
     240         212 :         if (destlen == 0)
     241           0 :                 return len;
     242             : 
     243         212 :         cplen = TDS_MIN((TDS_INT) destlen, len);
     244         212 :         memcpy(dest, buf, cplen);
     245         212 :         if (curcol)
     246         212 :                 curcol->column_text_sqlgetdatapos += cplen;
     247         212 :         return len;
     248             : }
     249             : 
     250             : static SQLLEN
     251        2262 : odbc_convert_to_binary(TDSCOLUMN *curcol, int srctype, TDS_CHAR * src, TDS_UINT srclen, TDS_CHAR * dest, SQLULEN destlen)
     252             : {
     253        2262 :         SQLLEN ret = srclen;
     254             : 
     255             :         /* special case for date/time */
     256        2262 :         switch (srctype) {
     257         212 :         case SYBMSTIME:
     258             :         case SYBMSDATE:
     259             :         case SYBMSDATETIME2:
     260             :         case SYBMSDATETIMEOFFSET:
     261             :         case SYBDATE:
     262             :         case SYBTIME:
     263             :         case SYB5BIGTIME:
     264             :         case SYB5BIGDATETIME:
     265         212 :                 return odbc_convert_datetime_to_binary(curcol, srctype, (TDS_DATETIMEALL *) src, dest, destlen);
     266             :         }
     267             : 
     268             :         /* if destlen == 0 we return only length */
     269        2050 :         if (destlen > 0) {
     270        2050 :                 size_t cplen = TDS_MIN(destlen, srclen);
     271             :                 /* do not NUL terminate binary buffer */
     272        2050 :                 memcpy(dest, src, cplen);
     273        2050 :                 if (curcol)
     274        2050 :                         curcol->column_text_sqlgetdatapos += cplen;
     275             :         }
     276             :         return ret;
     277             : }
     278             : 
     279             : static SQLLEN
     280       52538 : 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       52538 :         TDS_INT nRetVal = TDS_CONVERT_FAIL;
     286       52538 :         TDSCONTEXT *context = stmt->dbc->env->tds_ctx;
     287             : 
     288             :         CONV_RESULT ores;
     289             : 
     290       52538 :         SQLLEN ret = SQL_NULL_DATA;
     291             :         int i;
     292             :         SQLULEN cplen;
     293       52538 :         int binary_conversion = 0;
     294             :         TDS_CHAR conv_buf[256];
     295             : 
     296       52538 :         tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype);
     297             : 
     298       52538 :         assert(desttype != SQL_C_DEFAULT);
     299             : 
     300       52538 :         nDestSybType = odbc_c_to_server_type(desttype);
     301       52538 :         if (!nDestSybType) {
     302          10 :                 odbc_errs_add(&stmt->errs, "HY003", NULL);
     303          10 :                 return SQL_NULL_DATA;
     304             :         }
     305             : 
     306             :         /* special case for binary type */
     307       52528 :         if (desttype == SQL_C_BINARY) {
     308        2322 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen);
     309             : 
     310        2322 :                 if (is_numeric_type(srctype)) {
     311          60 :                         desttype = SQL_C_NUMERIC;
     312          60 :                         nDestSybType = SYBNUMERIC;
     313             :                         /* prevent buffer overflow */
     314          60 :                         if (destlen < sizeof(SQL_NUMERIC_STRUCT)) {
     315           0 :                                 odbc_errs_add(&stmt->errs, "07006", NULL);
     316           0 :                                 return SQL_NULL_DATA;
     317             :                         }
     318          60 :                         ores.n.precision = ((TDS_NUMERIC *) src)->precision;
     319          60 :                         ores.n.scale = ((TDS_NUMERIC *) src)->scale;
     320             :                 } else {
     321        2262 :                         return odbc_convert_to_binary(curcol, srctype, src, srclen, dest, destlen);
     322             :                 }
     323       50206 :         } else if (is_numeric_type(nDestSybType)) {
     324             :                 /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */
     325        1574 :                 if (drec_ixd)
     326         364 :                         ores.n.precision = (unsigned char) drec_ixd->sql_desc_precision;
     327             :                 else
     328        1210 :                         ores.n.precision = 38;
     329        1574 :                 ores.n.scale = 0;
     330             :         }
     331             : 
     332       50266 :         if (is_char_type(srctype)) {
     333       15052 :                 if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR)
     334       12952 :                         return odbc_convert_char(stmt, curcol, src, srclen, desttype, dest, destlen);
     335        2100 :                 if (is_unicode_type(srctype)) {
     336             :                         /*
     337             :                          * convert to single and then process normally.
     338             :                          * Here we processed SQL_C_BINARY and SQL_C_*CHAR so only fixed types are left
     339             :                          */
     340          10 :                         i = odbc_tds_convert_wide_iso(src, srclen, conv_buf, sizeof(conv_buf));
     341          10 :                         if (i < 0)
     342             :                                 return SQL_NULL_DATA;
     343          10 :                         src = conv_buf;
     344          10 :                         srclen = i;
     345          10 :                         srctype = SYBVARCHAR;
     346             :                 }
     347             :         }
     348             : 
     349       37314 :         if (desttype == SQL_C_WCHAR)
     350        1510 :                 destlen /= sizeof(SQLWCHAR);
     351       37314 :         if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
     352        3736 :                 if (is_binary_type(srctype)) {
     353         768 :                         binary_conversion = 1;
     354         768 :                         if (destlen && !(destlen % 2))
     355         368 :                                 --destlen;
     356             :                 }
     357             : 
     358        3736 :                 nDestSybType = TDS_CONVERT_CHAR;
     359        3736 :                 ores.cc.len = destlen;
     360        3736 :                 ores.cc.c = dest;
     361             :         }
     362             : 
     363       37314 :         if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
     364             :                 char buf[48];
     365             :                 TDSDATEREC when;
     366             :                 int prec;
     367        3736 :                 const char *fmt = NULL;
     368        3736 :                 const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src;
     369             : 
     370        3736 :                 switch (srctype) {
     371         112 :                 case SYBMSDATETIMEOFFSET:
     372             :                 case SYBMSDATETIME2:
     373         112 :                         prec = dta->time_prec;
     374         112 :                         goto datetime;
     375             :                 case SYB5BIGDATETIME:
     376             :                         prec = 6;
     377             :                         goto datetime;
     378         260 :                 case SYBDATETIME:
     379         260 :                         prec = 3;
     380         260 :                         goto datetime;
     381         140 :                 case SYBDATETIME4:
     382         140 :                         prec = 0;
     383             :                 datetime:
     384             :                         fmt = "%Y-%m-%d %H:%M:%S.%z";
     385             :                         break;
     386          60 :                 case SYBMSTIME:
     387          60 :                         prec = dta->time_prec;
     388          60 :                         goto time;
     389             :                 case SYB5BIGTIME:
     390             :                         prec = 6;
     391             :                         goto time;
     392          64 :                 case SYBTIME:
     393          64 :                         prec = 3;
     394             :                 time:
     395             :                         fmt = "%H:%M:%S.%z";
     396             :                         break;
     397             :                 case SYBMSDATE:
     398             :                 case SYBDATE:
     399             :                         prec = 0;
     400             :                         fmt = "%Y-%m-%d";
     401             :                         break;
     402             :                 }
     403             :                 if (!fmt) goto normal_conversion;
     404             : 
     405         786 :                 tds_datecrack(srctype, src, &when);
     406         786 :                 tds_strftime(buf, sizeof(buf), fmt, &when, prec);
     407             : 
     408         786 :                 if (srctype == SYBMSDATETIMEOFFSET) {
     409          48 :                         char sign = '+';
     410          48 :                         int off = dta->offset;
     411          48 :                         if (off < 0) {
     412           4 :                                 sign = '-';
     413           4 :                                 off = -off;
     414             :                         }
     415          48 :                         sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60);
     416             :                 }
     417             : 
     418         786 :                 nRetVal = (TDS_INT) strlen(buf);
     419         786 :                 memcpy(dest, buf, TDS_MIN(destlen, (SQLULEN) nRetVal));
     420             :         } else {
     421       70106 : normal_conversion:
     422       36528 :                 nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores);
     423             :         }
     424       37314 :         if (nRetVal < 0) {
     425       15360 :                 odbc_convert_err_set(&stmt->errs, nRetVal);
     426       15360 :                 return SQL_NULL_DATA;
     427             :         }
     428             : 
     429       21954 :         switch (desttype) {
     430             : 
     431        2126 :         case SQL_C_CHAR:
     432        2126 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
     433             : 
     434        2126 :                 ret = nRetVal;
     435             :                 /* TODO handle not terminated configuration */
     436        2126 :                 if (destlen > 0) {
     437        2046 :                         cplen = TDS_MIN(destlen - 1, (SQLULEN) nRetVal);
     438             :                         assert(cplen >= 0);
     439             :                         /*
     440             :                          * odbc always terminate but do not overwrite 
     441             :                          * destination buffer more than needed
     442             :                          */
     443             :                         /* update datapos only for binary source (char already handled) */
     444        2046 :                         if (curcol && binary_conversion)
     445         228 :                                 curcol->column_text_sqlgetdatapos += cplen / 2;
     446        2046 :                         dest[cplen] = 0;
     447             :                 } else {
     448             :                         /* if destlen == 0 we return only length */
     449             :                 }
     450             :                 break;
     451             : 
     452        1410 :         case SQL_C_WCHAR:
     453        1410 :                 tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
     454             : 
     455        1410 :                 ret = nRetVal * sizeof(SQLWCHAR);
     456             :                 /* TODO handle not terminated configuration */
     457        1410 :                 if (destlen > 0) {
     458        1250 :                         SQLWCHAR *wp = (SQLWCHAR *) dest;
     459        1250 :                         SQLCHAR  *p  = (SQLCHAR *)  dest;
     460             : 
     461        1250 :                         cplen = TDS_MIN(destlen - 1, (SQLULEN) nRetVal);
     462             :                         assert(cplen >= 0);
     463             :                         /*
     464             :                          * odbc always terminate but do not overwrite 
     465             :                          * destination buffer more than needed
     466             :                          */
     467             :                         /* update datapos only for binary source (char already handled) */
     468        1250 :                         if (curcol && binary_conversion)
     469         300 :                                 curcol->column_text_sqlgetdatapos += cplen / 2;
     470             :                         /* convert in place and terminate */
     471        1250 :                         wp[cplen] = 0;
     472      813170 :                         while (cplen > 0) {
     473      810670 :                                 --cplen;
     474      810670 :                                 wp[cplen] = p[cplen];
     475             :                         }
     476             :                 } else {
     477             :                         /* if destlen == 0 we return only length */
     478             :                 }
     479             :                 break;
     480             : 
     481         778 :         case SQL_C_TYPE_DATE:
     482             :         case SQL_C_DATE:
     483             :                 {
     484             :                         TDSDATEREC dr;
     485         778 :                         DATE_STRUCT *dsp = (DATE_STRUCT *) dest;
     486             : 
     487             :                         /*
     488             :                          * we've already converted the returned value to a SYBMSDATETIME2
     489             :                          * now decompose date into constituent parts...
     490             :                          */
     491         778 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     492             : 
     493         778 :                         dsp->year = dr.year;
     494         778 :                         dsp->month = dr.month + 1;
     495         778 :                         dsp->day = dr.day;
     496             : 
     497         778 :                         ret = sizeof(DATE_STRUCT);
     498             :                 }
     499         778 :                 break;
     500             : 
     501         778 :         case SQL_C_TYPE_TIME:
     502             :         case SQL_C_TIME:
     503             :                 {
     504             :                         TDSDATEREC dr;
     505         778 :                         TIME_STRUCT *tsp = (TIME_STRUCT *) dest;
     506             : 
     507             :                         /*
     508             :                          * we've already converted the returned value to a SYBMSDATETIME2
     509             :                          * now decompose date into constituent parts...
     510             :                          */
     511         778 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     512             : 
     513         778 :                         tsp->hour = dr.hour;
     514         778 :                         tsp->minute = dr.minute;
     515         778 :                         tsp->second = dr.second;
     516             : 
     517         778 :                         ret = sizeof(TIME_STRUCT);
     518             :                 }
     519         778 :                 break;
     520             : 
     521        1118 :         case SQL_C_TYPE_TIMESTAMP:
     522             :         case SQL_C_TIMESTAMP: 
     523             :                 {
     524             :                         TDSDATEREC dr;
     525        1118 :                         TIMESTAMP_STRUCT *tssp = (TIMESTAMP_STRUCT *) dest;
     526             : 
     527             :                         /*
     528             :                          * we've already converted the returned value to a SYBMSDATETIME2
     529             :                          * now decompose date into constituent parts...
     530             :                          */
     531        1118 :                         tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
     532             : 
     533        1118 :                         tssp->year = dr.year;
     534        1118 :                         tssp->month = dr.month + 1;
     535        1118 :                         tssp->day = dr.day;
     536        1118 :                         tssp->hour = dr.hour;
     537        1118 :                         tssp->minute = dr.minute;
     538        1118 :                         tssp->second = dr.second;
     539        1118 :                         tssp->fraction = dr.decimicrosecond * 100u;
     540             : 
     541        1118 :                         ret = sizeof(TIMESTAMP_STRUCT);
     542             :                 }
     543        1118 :                 break;
     544             : 
     545             : #ifdef SQL_C_SBIGINT
     546        1554 :         case SQL_C_SBIGINT:
     547             :         case SQL_C_UBIGINT:
     548        1554 :                 *((TDS_INT8 *) dest) = ores.bi;
     549        1554 :                 ret = sizeof(TDS_INT8);
     550        1554 :                 break;
     551             : #endif
     552             : 
     553        5452 :         case SQL_C_LONG:
     554             :         case SQL_C_SLONG:
     555             :         case SQL_C_ULONG:
     556        5452 :                 *((TDS_INT *) dest) = ores.i;
     557        5452 :                 ret = sizeof(TDS_INT);
     558        5452 :                 break;
     559             : 
     560        3442 :         case SQL_C_SHORT:
     561             :         case SQL_C_SSHORT:
     562             :         case SQL_C_USHORT:
     563        3442 :                 *((TDS_SMALLINT *) dest) = ores.si;
     564        3442 :                 ret = sizeof(TDS_SMALLINT);
     565        3442 :                 break;
     566             : 
     567        1936 :         case SQL_C_TINYINT:
     568             :         case SQL_C_STINYINT:
     569             :         case SQL_C_UTINYINT:
     570             :         case SQL_C_BIT:
     571        1936 :                 *((TDS_TINYINT *) dest) = ores.ti;
     572        1936 :                 ret = sizeof(TDS_TINYINT);
     573        1936 :                 break;
     574             : 
     575        1100 :         case SQL_C_DOUBLE:
     576        1100 :                 *((TDS_FLOAT *) dest) = ores.f;
     577        1100 :                 ret = sizeof(TDS_FLOAT);
     578        1100 :                 break;
     579             : 
     580        1046 :         case SQL_C_FLOAT:
     581        1046 :                 *((TDS_REAL *) dest) = ores.r;
     582        1046 :                 ret = sizeof(TDS_REAL);
     583        1046 :                 break;
     584             : 
     585        1154 :         case SQL_C_NUMERIC:
     586             :                 {
     587             :                         /* ODBC numeric is quite different from TDS one ... */
     588        1154 :                         SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest;
     589        1154 :                         num->precision = ores.n.precision;
     590        1154 :                         num->scale = ores.n.scale;
     591        1154 :                         num->sign = ores.n.array[0] ^ 1;
     592             :                         /*
     593             :                          * TODO can be greater than SQL_MAX_NUMERIC_LEN ?? 
     594             :                          * seeing Sybase manual wire support bigger numeric but currently
     595             :                          * DBs so not support such precision
     596             :                          */
     597        1154 :                         i = TDS_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN);
     598        1154 :                         memcpy(num->val, ores.n.array + 1, i);
     599        1154 :                         tds_swap_bytes(num->val, i);
     600        1154 :                         if (i < SQL_MAX_NUMERIC_LEN)
     601         168 :                                 memset(num->val + i, 0, SQL_MAX_NUMERIC_LEN - i);
     602             :                         ret = sizeof(SQL_NUMERIC_STRUCT);
     603             :                 }
     604             :                 break;
     605             : 
     606             : #ifdef SQL_C_GUID
     607          60 :         case SQL_C_GUID:
     608          60 :                 memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE));
     609          60 :                 ret = sizeof(TDS_UNIQUE);
     610          60 :                 break;
     611             : #endif
     612             : 
     613             :         default:
     614             :                 break;
     615             :         }
     616             : 
     617             :         return ret;
     618             : }
     619             : 
     620       52344 : SQLLEN odbc_tds2sql_col(TDS_STMT * stmt, TDSCOLUMN *curcol, int desttype, TDS_CHAR * dest, SQLULEN destlen,
     621             :                         const struct _drecord *drec_ixd)
     622             : {
     623       52344 :         int srctype = tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size);
     624       52344 :         TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
     625       52344 :         TDS_UINT srclen = curcol->column_cur_size;
     626             : 
     627       52344 :         if (is_blob_col(curcol)) {
     628       16228 :                 if (srctype == SYBLONGBINARY && (
     629         286 :                     curcol->column_usertype == USER_UNICHAR_TYPE ||
     630             :                     curcol->column_usertype == USER_UNIVARCHAR_TYPE))
     631             :                         srctype = SYBNTEXT;
     632       15906 :                 if (srctype == SYBVARIANT)
     633       12342 :                         srctype = ((TDSVARIANT *) src)->type;
     634       15942 :                 src = ((TDSBLOB *) src)->textvalue;
     635             :         }
     636       52344 :         if (is_variable_type(srctype)) {
     637       18982 :                 src += curcol->column_text_sqlgetdatapos;
     638       18982 :                 srclen -= curcol->column_text_sqlgetdatapos;
     639             :         }
     640       52344 :         return odbc_tds2sql(stmt, curcol, srctype, src, srclen, desttype, dest, destlen, drec_ixd);
     641             : }
     642             : 
     643         194 : SQLLEN odbc_tds2sql_int4(TDS_STMT * stmt, TDS_INT *src, int desttype, TDS_CHAR * dest, SQLULEN destlen)
     644             : {
     645         194 :         return odbc_tds2sql(stmt, NULL, SYBINT4, (TDS_CHAR *) src, sizeof(*src),
     646             :                             desttype, dest, destlen, NULL);
     647             : }

Generated by: LCOV version 1.13