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/tds/convert.h>
38 : #include <freetds/tds/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 13342 : eat_iconv_left(TDSCOLUMN * curcol, char **pbuf, size_t *plen)
50 : {
51 13342 : unsigned cp = (unsigned) TDS_MIN(*plen, curcol->column_iconv_left);
52 13342 : memcpy(*pbuf, curcol->column_iconv_buf, cp);
53 13342 : if (cp < curcol->column_iconv_left)
54 830 : memmove(curcol->column_iconv_buf, curcol->column_iconv_buf + cp, curcol->column_iconv_left - cp);
55 13342 : curcol->column_iconv_left -= cp;
56 13342 : *pbuf += cp;
57 13342 : *plen -= cp;
58 13342 : }
59 :
60 : /**
61 : * Handle conversions from TDS (N)CHAR to ODBC (W)CHAR
62 : */
63 : static SQLLEN
64 13032 : 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 13032 : TDSSOCKET *tds = stmt->dbc->tds_socket;
73 :
74 13032 : TDSICONV *conv = curcol->char_conv;
75 13032 : if (!conv)
76 180 : conv = tds->conn->char_convs[client2server_chardata];
77 13032 : 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 11646 : conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, conv->to.charset.canonic);
86 11646 : if (!conv)
87 0 : conv = tds_iconv_get_info(tds->conn, stmt->dbc->original_charset_num, TDS_CHARSET_ISO_8859_1);
88 11646 : 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 13032 : ib = src;
94 13032 : il = srclen;
95 13032 : ob = dest;
96 13032 : ol = 0;
97 13032 : char_size = desttype == SQL_C_CHAR ? 1 : SIZEOF_SQLWCHAR;
98 13032 : if (destlen >= char_size) {
99 12528 : ol = destlen - char_size;
100 : /* copy left and continue only if possible */
101 12528 : eat_iconv_left(curcol, &ob, &ol);
102 12528 : if (ol) {
103 12488 : memset(&conv->suppress, 0, sizeof(conv->suppress));
104 12488 : conv->suppress.eilseq = 1;
105 12488 : conv->suppress.e2big = 1;
106 : /* TODO check return value */
107 12488 : tds_iconv(tds, conv, to_client, &ib, &il, &ob, &ol);
108 : }
109 : /* if input left try to decode on future left */
110 12528 : if (il && ol < sizeof(curcol->column_iconv_buf) && curcol->column_iconv_left == 0) {
111 814 : char *left_ob = curcol->column_iconv_buf;
112 814 : size_t left_ol = sizeof(curcol->column_iconv_buf);
113 814 : conv->suppress.eilseq = 1;
114 814 : conv->suppress.einval = 1;
115 814 : conv->suppress.e2big = 1;
116 814 : tds_iconv(tds, conv, to_client, &ib, &il, &left_ob, &left_ol);
117 814 : curcol->column_iconv_left = sizeof(curcol->column_iconv_buf) - (unsigned char) left_ol;
118 : /* copy part to fill buffer */
119 814 : eat_iconv_left(curcol, &ob, &ol);
120 : }
121 12528 : ol = ob - dest; /* bytes written */
122 12528 : curcol->column_text_sqlgetdatapos += (TDS_INT) (ib - src);
123 : /* terminate string */
124 12528 : memset(ob, 0, char_size);
125 : }
126 :
127 : /* returned size have to take into account buffer left unconverted */
128 13032 : 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 12158 : 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 12454 : 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 52680 : 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 52680 : TDS_INT nRetVal = TDS_CONVERT_FAIL;
286 52680 : TDSCONTEXT *context = stmt->dbc->env->tds_ctx;
287 :
288 : CONV_RESULT ores;
289 :
290 52680 : SQLLEN ret = SQL_NULL_DATA;
291 : int i;
292 52680 : bool binary_conversion = false;
293 : SQLULEN cplen;
294 : TDS_CHAR conv_buf[256];
295 :
296 52680 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype);
297 :
298 52680 : assert(desttype != SQL_C_DEFAULT);
299 :
300 52680 : nDestSybType = odbc_c_to_server_type(desttype);
301 52680 : 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 52670 : 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 50348 : } 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 50408 : if (is_char_type(srctype)) {
333 15132 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR)
334 13032 : 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 37376 : if (desttype == SQL_C_WCHAR)
350 1510 : destlen /= sizeof(SQLWCHAR);
351 37376 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
352 3708 : if (is_binary_type(srctype)) {
353 768 : binary_conversion = true;
354 768 : if (destlen && !(destlen % 2))
355 368 : --destlen;
356 : }
357 :
358 3708 : nDestSybType = TDS_CONVERT_CHAR;
359 3708 : ores.cc.len = destlen;
360 3708 : ores.cc.c = dest;
361 : }
362 :
363 37376 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
364 : char buf[48];
365 : TDSDATEREC when;
366 : int prec;
367 3708 : const char *fmt = NULL;
368 3708 : const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src;
369 :
370 : /* This logic should match odbc_datetime_display_size() in odbc_data.c */
371 : /* TODO: so, instead of dta->time_prec this should be using curcol->column_prec? */
372 3708 : switch (srctype) {
373 120 : case SYBMSDATETIMEOFFSET:
374 : case SYBMSDATETIME2:
375 120 : prec = dta->time_prec;
376 120 : goto datetime;
377 : case SYB5BIGDATETIME:
378 : prec = 6;
379 : goto datetime;
380 216 : case SYBDATETIME:
381 216 : prec = 3;
382 216 : goto datetime;
383 140 : case SYBDATETIME4:
384 140 : prec = 0;
385 496 : datetime:
386 992 : fmt = tds_dstr_cstr(&stmt->dbc->datetime_fmt);
387 496 : break;
388 64 : case SYBMSTIME:
389 64 : prec = dta->time_prec;
390 64 : goto time;
391 : case SYB5BIGTIME:
392 : prec = 6;
393 : goto time;
394 64 : case SYBTIME:
395 64 : prec = 3;
396 148 : time:
397 296 : fmt = tds_dstr_cstr(&stmt->dbc->time_fmt);
398 148 : break;
399 114 : case SYBMSDATE:
400 : case SYBDATE:
401 114 : prec = 0;
402 228 : fmt = tds_dstr_cstr(&stmt->dbc->date_fmt);
403 114 : break;
404 : }
405 758 : if (!fmt) goto normal_conversion;
406 :
407 758 : tds_datecrack(srctype, src, &when);
408 758 : tds_strftime(buf, sizeof(buf), fmt, &when, prec);
409 :
410 758 : if (srctype == SYBMSDATETIMEOFFSET) {
411 48 : char sign = '+';
412 48 : int off = dta->offset;
413 48 : if (off < 0) {
414 4 : sign = '-';
415 4 : off = -off;
416 : }
417 48 : sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60);
418 : }
419 :
420 758 : nRetVal = (TDS_INT) strlen(buf);
421 758 : memcpy(dest, buf, TDS_MIN(destlen, (SQLULEN) nRetVal));
422 : } else {
423 70286 : normal_conversion:
424 36618 : nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores);
425 : }
426 37376 : if (nRetVal < 0) {
427 15360 : odbc_convert_err_set(&stmt->errs, nRetVal);
428 15360 : return SQL_NULL_DATA;
429 : }
430 :
431 22016 : switch (desttype) {
432 :
433 2098 : case SQL_C_CHAR:
434 2098 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
435 :
436 2098 : ret = nRetVal;
437 : /* TODO handle not terminated configuration */
438 2098 : if (destlen > 0) {
439 2018 : cplen = TDS_MIN(destlen - 1, (SQLULEN) nRetVal);
440 : assert(cplen >= 0);
441 : /*
442 : * odbc always terminate but do not overwrite
443 : * destination buffer more than needed
444 : */
445 : /* update datapos only for binary source (char already handled) */
446 2018 : if (curcol && binary_conversion)
447 228 : curcol->column_text_sqlgetdatapos += cplen / 2;
448 2018 : dest[cplen] = 0;
449 : } else {
450 : /* if destlen == 0 we return only length */
451 : }
452 : break;
453 :
454 1410 : case SQL_C_WCHAR:
455 1410 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
456 :
457 1410 : ret = nRetVal * sizeof(SQLWCHAR);
458 : /* TODO handle not terminated configuration */
459 1410 : if (destlen > 0) {
460 1250 : SQLWCHAR *wp = (SQLWCHAR *) dest;
461 1250 : SQLCHAR *p = (SQLCHAR *) dest;
462 :
463 1250 : cplen = TDS_MIN(destlen - 1, (SQLULEN) nRetVal);
464 : assert(cplen >= 0);
465 : /*
466 : * odbc always terminate but do not overwrite
467 : * destination buffer more than needed
468 : */
469 : /* update datapos only for binary source (char already handled) */
470 1250 : if (curcol && binary_conversion)
471 300 : curcol->column_text_sqlgetdatapos += cplen / 2;
472 : /* convert in place and terminate */
473 1250 : wp[cplen] = 0;
474 813170 : while (cplen > 0) {
475 810670 : --cplen;
476 810670 : wp[cplen] = p[cplen];
477 : }
478 : } else {
479 : /* if destlen == 0 we return only length */
480 : }
481 : break;
482 :
483 778 : case SQL_C_TYPE_DATE:
484 : case SQL_C_DATE:
485 : {
486 : TDSDATEREC dr;
487 778 : DATE_STRUCT *dsp = (DATE_STRUCT *) dest;
488 :
489 : /*
490 : * we've already converted the returned value to a SYBMSDATETIME2
491 : * now decompose date into constituent parts...
492 : */
493 778 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
494 :
495 778 : dsp->year = dr.year;
496 778 : dsp->month = dr.month + 1;
497 778 : dsp->day = dr.day;
498 :
499 778 : ret = sizeof(DATE_STRUCT);
500 : }
501 778 : break;
502 :
503 778 : case SQL_C_TYPE_TIME:
504 : case SQL_C_TIME:
505 : {
506 : TDSDATEREC dr;
507 778 : TIME_STRUCT *tsp = (TIME_STRUCT *) dest;
508 :
509 : /*
510 : * we've already converted the returned value to a SYBMSDATETIME2
511 : * now decompose date into constituent parts...
512 : */
513 778 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
514 :
515 778 : tsp->hour = dr.hour;
516 778 : tsp->minute = dr.minute;
517 778 : tsp->second = dr.second;
518 :
519 778 : ret = sizeof(TIME_STRUCT);
520 : }
521 778 : break;
522 :
523 1118 : case SQL_C_TYPE_TIMESTAMP:
524 : case SQL_C_TIMESTAMP:
525 : {
526 : TDSDATEREC dr;
527 1118 : TIMESTAMP_STRUCT *tssp = (TIMESTAMP_STRUCT *) dest;
528 :
529 : /*
530 : * we've already converted the returned value to a SYBMSDATETIME2
531 : * now decompose date into constituent parts...
532 : */
533 1118 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
534 :
535 1118 : tssp->year = dr.year;
536 1118 : tssp->month = dr.month + 1;
537 1118 : tssp->day = dr.day;
538 1118 : tssp->hour = dr.hour;
539 1118 : tssp->minute = dr.minute;
540 1118 : tssp->second = dr.second;
541 1118 : tssp->fraction = dr.decimicrosecond * 100u;
542 :
543 1118 : ret = sizeof(TIMESTAMP_STRUCT);
544 : }
545 1118 : break;
546 :
547 : #ifdef SQL_C_SBIGINT
548 1554 : case SQL_C_SBIGINT:
549 : case SQL_C_UBIGINT:
550 1554 : *((TDS_INT8 *) dest) = ores.bi;
551 1554 : ret = sizeof(TDS_INT8);
552 1554 : break;
553 : #endif
554 :
555 5542 : case SQL_C_LONG:
556 : case SQL_C_SLONG:
557 : case SQL_C_ULONG:
558 5542 : *((TDS_INT *) dest) = ores.i;
559 5542 : ret = sizeof(TDS_INT);
560 5542 : break;
561 :
562 3442 : case SQL_C_SHORT:
563 : case SQL_C_SSHORT:
564 : case SQL_C_USHORT:
565 3442 : *((TDS_SMALLINT *) dest) = ores.si;
566 3442 : ret = sizeof(TDS_SMALLINT);
567 3442 : break;
568 :
569 1936 : case SQL_C_TINYINT:
570 : case SQL_C_STINYINT:
571 : case SQL_C_UTINYINT:
572 : case SQL_C_BIT:
573 1936 : *((TDS_TINYINT *) dest) = ores.ti;
574 1936 : ret = sizeof(TDS_TINYINT);
575 1936 : break;
576 :
577 1100 : case SQL_C_DOUBLE:
578 1100 : *((TDS_FLOAT *) dest) = ores.f;
579 1100 : ret = sizeof(TDS_FLOAT);
580 1100 : break;
581 :
582 1046 : case SQL_C_FLOAT:
583 1046 : *((TDS_REAL *) dest) = ores.r;
584 1046 : ret = sizeof(TDS_REAL);
585 1046 : break;
586 :
587 1154 : case SQL_C_NUMERIC:
588 : {
589 : /* ODBC numeric is quite different from TDS one ... */
590 1154 : SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest;
591 : size_t len;
592 1154 : num->precision = ores.n.precision;
593 1154 : num->scale = ores.n.scale;
594 1154 : num->sign = ores.n.array[0] ^ 1;
595 : /*
596 : * TODO can be greater than SQL_MAX_NUMERIC_LEN ??
597 : * Seeing Sybase manual wire supports bigger numeric but current
598 : * DBs do not support such precisions.
599 : */
600 1154 : len = TDS_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN);
601 1154 : memset(num->val, 0, SQL_MAX_NUMERIC_LEN);
602 1154 : memcpy(num->val, ores.n.array + 1, len);
603 1154 : tds_swap_bytes(num->val, len);
604 1154 : ret = sizeof(SQL_NUMERIC_STRUCT);
605 : }
606 1154 : break;
607 :
608 : #ifdef SQL_C_GUID
609 60 : case SQL_C_GUID:
610 60 : memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE));
611 60 : ret = sizeof(TDS_UNIQUE);
612 60 : break;
613 : #endif
614 :
615 : default:
616 : break;
617 : }
618 :
619 : return ret;
620 : }
621 :
622 52486 : SQLLEN odbc_tds2sql_col(TDS_STMT * stmt, TDSCOLUMN *curcol, int desttype, TDS_CHAR * dest, SQLULEN destlen,
623 : const struct _drecord *drec_ixd)
624 : {
625 52486 : int srctype = tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size);
626 52486 : TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
627 52486 : TDS_UINT srclen = curcol->column_cur_size;
628 :
629 52486 : if (is_blob_col(curcol)) {
630 16228 : if (srctype == SYBLONGBINARY && (
631 286 : curcol->column_usertype == USER_UNICHAR_TYPE ||
632 : curcol->column_usertype == USER_UNIVARCHAR_TYPE))
633 : srctype = SYBNTEXT;
634 15906 : if (srctype == SYBVARIANT)
635 12342 : srctype = ((TDSVARIANT *) src)->type;
636 15942 : src = ((TDSBLOB *) src)->textvalue;
637 : }
638 52486 : if (is_variable_type(srctype)) {
639 19062 : src += curcol->column_text_sqlgetdatapos;
640 19062 : srclen -= curcol->column_text_sqlgetdatapos;
641 : }
642 52486 : return odbc_tds2sql(stmt, curcol, srctype, src, srclen, desttype, dest, destlen, drec_ixd);
643 : }
644 :
645 194 : SQLLEN odbc_tds2sql_int4(TDS_STMT * stmt, TDS_INT *src, int desttype, TDS_CHAR * dest, SQLULEN destlen)
646 : {
647 194 : return odbc_tds2sql(stmt, NULL, SYBINT4, (TDS_CHAR *) src, sizeof(*src),
648 : desttype, dest, destlen, NULL);
649 : }
|