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 : }
|