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 = ODBC_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) - 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 += 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 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 : size_t 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 = ODBC_MIN(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 = ODBC_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, cplen;
292 52538 : int binary_conversion = 0;
293 : TDS_CHAR conv_buf[256];
294 :
295 52538 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype);
296 :
297 52538 : assert(desttype != SQL_C_DEFAULT);
298 :
299 52538 : nDestSybType = odbc_c_to_server_type(desttype);
300 52538 : if (!nDestSybType) {
301 10 : odbc_errs_add(&stmt->errs, "HY003", NULL);
302 10 : return SQL_NULL_DATA;
303 : }
304 :
305 : /* special case for binary type */
306 52528 : if (desttype == SQL_C_BINARY) {
307 2322 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen);
308 :
309 2322 : if (is_numeric_type(srctype)) {
310 60 : desttype = SQL_C_NUMERIC;
311 60 : nDestSybType = SYBNUMERIC;
312 : /* prevent buffer overflow */
313 60 : if (destlen < sizeof(SQL_NUMERIC_STRUCT)) {
314 0 : odbc_errs_add(&stmt->errs, "07006", NULL);
315 0 : return SQL_NULL_DATA;
316 : }
317 60 : ores.n.precision = ((TDS_NUMERIC *) src)->precision;
318 60 : ores.n.scale = ((TDS_NUMERIC *) src)->scale;
319 : } else {
320 2262 : return odbc_convert_to_binary(curcol, srctype, src, srclen, dest, destlen);
321 : }
322 50206 : } else if (is_numeric_type(nDestSybType)) {
323 : /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */
324 1574 : if (drec_ixd)
325 364 : ores.n.precision = drec_ixd->sql_desc_precision;
326 : else
327 1210 : ores.n.precision = 38;
328 1574 : ores.n.scale = 0;
329 : }
330 :
331 50266 : if (is_char_type(srctype)) {
332 15052 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR)
333 12952 : return odbc_convert_char(stmt, curcol, src, srclen, desttype, dest, destlen);
334 2100 : 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 10 : i = odbc_tds_convert_wide_iso(src, srclen, conv_buf, sizeof(conv_buf));
340 10 : if (i < 0)
341 : return SQL_NULL_DATA;
342 10 : src = conv_buf;
343 10 : srclen = i;
344 10 : srctype = SYBVARCHAR;
345 : }
346 : }
347 :
348 37314 : if (desttype == SQL_C_WCHAR)
349 1510 : destlen /= sizeof(SQLWCHAR);
350 37314 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
351 3736 : if (is_binary_type(srctype)) {
352 768 : binary_conversion = 1;
353 768 : if (destlen && !(destlen % 2))
354 368 : --destlen;
355 : }
356 :
357 3736 : nDestSybType = TDS_CONVERT_CHAR;
358 3736 : ores.cc.len = destlen;
359 3736 : ores.cc.c = dest;
360 : }
361 :
362 37314 : if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) {
363 : char buf[48];
364 : TDSDATEREC when;
365 : int prec;
366 3736 : const char *fmt = NULL;
367 3736 : const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src;
368 :
369 3736 : switch (srctype) {
370 112 : case SYBMSDATETIMEOFFSET:
371 : case SYBMSDATETIME2:
372 112 : prec = dta->time_prec;
373 112 : goto datetime;
374 : case SYB5BIGDATETIME:
375 : prec = 6;
376 : goto datetime;
377 260 : case SYBDATETIME:
378 260 : prec = 3;
379 260 : goto datetime;
380 140 : case SYBDATETIME4:
381 140 : prec = 0;
382 : datetime:
383 : fmt = "%Y-%m-%d %H:%M:%S.%z";
384 : break;
385 60 : case SYBMSTIME:
386 60 : prec = dta->time_prec;
387 60 : goto time;
388 : case SYB5BIGTIME:
389 : prec = 6;
390 : goto time;
391 64 : case SYBTIME:
392 64 : 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 786 : tds_datecrack(srctype, src, &when);
405 786 : tds_strftime(buf, sizeof(buf), fmt, &when, prec);
406 :
407 786 : if (srctype == SYBMSDATETIMEOFFSET) {
408 48 : char sign = '+';
409 48 : int off = dta->offset;
410 48 : if (off < 0) {
411 4 : sign = '-';
412 4 : off = -off;
413 : }
414 48 : sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60);
415 : }
416 :
417 786 : nRetVal = strlen(buf);
418 786 : memcpy(dest, buf, ODBC_MIN(destlen, nRetVal));
419 : } else {
420 70106 : normal_conversion:
421 36528 : nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores);
422 : }
423 37314 : if (nRetVal < 0) {
424 15360 : odbc_convert_err_set(&stmt->errs, nRetVal);
425 15360 : return SQL_NULL_DATA;
426 : }
427 :
428 21954 : switch (desttype) {
429 :
430 2126 : case SQL_C_CHAR:
431 2126 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
432 :
433 2126 : ret = nRetVal;
434 : /* TODO handle not terminated configuration */
435 2126 : if (destlen > 0) {
436 2046 : 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 2046 : if (curcol && binary_conversion)
444 228 : curcol->column_text_sqlgetdatapos += cplen / 2;
445 2046 : dest[cplen] = 0;
446 : } else {
447 : /* if destlen == 0 we return only length */
448 : }
449 : break;
450 :
451 1410 : case SQL_C_WCHAR:
452 1410 : tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen);
453 :
454 1410 : ret = nRetVal * sizeof(SQLWCHAR);
455 : /* TODO handle not terminated configuration */
456 1410 : if (destlen > 0) {
457 1250 : SQLWCHAR *wp = (SQLWCHAR *) dest;
458 1250 : SQLCHAR *p = (SQLCHAR *) dest;
459 :
460 1250 : 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 1250 : if (curcol && binary_conversion)
468 300 : curcol->column_text_sqlgetdatapos += cplen / 2;
469 : /* convert in place and terminate */
470 1250 : wp[cplen] = 0;
471 813170 : while (cplen > 0) {
472 810670 : --cplen;
473 810670 : wp[cplen] = p[cplen];
474 : }
475 : } else {
476 : /* if destlen == 0 we return only length */
477 : }
478 : break;
479 :
480 778 : case SQL_C_TYPE_DATE:
481 : case SQL_C_DATE:
482 : {
483 : TDSDATEREC dr;
484 778 : 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 778 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
491 :
492 778 : dsp->year = dr.year;
493 778 : dsp->month = dr.month + 1;
494 778 : dsp->day = dr.day;
495 :
496 778 : ret = sizeof(DATE_STRUCT);
497 : }
498 778 : break;
499 :
500 778 : case SQL_C_TYPE_TIME:
501 : case SQL_C_TIME:
502 : {
503 : TDSDATEREC dr;
504 778 : 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 778 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
511 :
512 778 : tsp->hour = dr.hour;
513 778 : tsp->minute = dr.minute;
514 778 : tsp->second = dr.second;
515 :
516 778 : ret = sizeof(TIME_STRUCT);
517 : }
518 778 : break;
519 :
520 1118 : case SQL_C_TYPE_TIMESTAMP:
521 : case SQL_C_TIMESTAMP:
522 : {
523 : TDSDATEREC dr;
524 1118 : 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 1118 : tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr);
531 :
532 1118 : tssp->year = dr.year;
533 1118 : tssp->month = dr.month + 1;
534 1118 : tssp->day = dr.day;
535 1118 : tssp->hour = dr.hour;
536 1118 : tssp->minute = dr.minute;
537 1118 : tssp->second = dr.second;
538 1118 : tssp->fraction = dr.decimicrosecond * 100u;
539 :
540 1118 : ret = sizeof(TIMESTAMP_STRUCT);
541 : }
542 1118 : break;
543 :
544 : #ifdef SQL_C_SBIGINT
545 1554 : case SQL_C_SBIGINT:
546 : case SQL_C_UBIGINT:
547 1554 : *((TDS_INT8 *) dest) = ores.bi;
548 1554 : ret = sizeof(TDS_INT8);
549 1554 : break;
550 : #endif
551 :
552 5452 : case SQL_C_LONG:
553 : case SQL_C_SLONG:
554 : case SQL_C_ULONG:
555 5452 : *((TDS_INT *) dest) = ores.i;
556 5452 : ret = sizeof(TDS_INT);
557 5452 : break;
558 :
559 3442 : case SQL_C_SHORT:
560 : case SQL_C_SSHORT:
561 : case SQL_C_USHORT:
562 3442 : *((TDS_SMALLINT *) dest) = ores.si;
563 3442 : ret = sizeof(TDS_SMALLINT);
564 3442 : break;
565 :
566 1936 : case SQL_C_TINYINT:
567 : case SQL_C_STINYINT:
568 : case SQL_C_UTINYINT:
569 : case SQL_C_BIT:
570 1936 : *((TDS_TINYINT *) dest) = ores.ti;
571 1936 : ret = sizeof(TDS_TINYINT);
572 1936 : break;
573 :
574 1100 : case SQL_C_DOUBLE:
575 1100 : *((TDS_FLOAT *) dest) = ores.f;
576 1100 : ret = sizeof(TDS_FLOAT);
577 1100 : break;
578 :
579 1046 : case SQL_C_FLOAT:
580 1046 : *((TDS_REAL *) dest) = ores.r;
581 1046 : ret = sizeof(TDS_REAL);
582 1046 : break;
583 :
584 1154 : case SQL_C_NUMERIC:
585 : {
586 : /* ODBC numeric is quite different from TDS one ... */
587 1154 : SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest;
588 1154 : num->precision = ores.n.precision;
589 1154 : num->scale = ores.n.scale;
590 1154 : 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 1154 : i = ODBC_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN);
597 1154 : memcpy(num->val, ores.n.array + 1, i);
598 1154 : tds_swap_bytes(num->val, i);
599 1154 : if (i < SQL_MAX_NUMERIC_LEN)
600 168 : 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 60 : case SQL_C_GUID:
607 60 : memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE));
608 60 : ret = sizeof(TDS_UNIQUE);
609 60 : break;
610 : #endif
611 :
612 : default:
613 : break;
614 : }
615 :
616 : return ret;
617 : }
618 :
619 52344 : SQLLEN odbc_tds2sql_col(TDS_STMT * stmt, TDSCOLUMN *curcol, int desttype, TDS_CHAR * dest, SQLULEN destlen,
620 : const struct _drecord *drec_ixd)
621 : {
622 52344 : int srctype = tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size);
623 52344 : TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
624 52344 : TDS_UINT srclen = curcol->column_cur_size;
625 :
626 52344 : if (is_blob_col(curcol)) {
627 16228 : if (srctype == SYBLONGBINARY && (
628 286 : curcol->column_usertype == USER_UNICHAR_TYPE ||
629 : curcol->column_usertype == USER_UNIVARCHAR_TYPE))
630 : srctype = SYBNTEXT;
631 15906 : if (srctype == SYBVARIANT)
632 12342 : srctype = ((TDSVARIANT *) src)->type;
633 15942 : src = ((TDSBLOB *) src)->textvalue;
634 : }
635 52344 : if (is_variable_type(srctype)) {
636 18982 : src += curcol->column_text_sqlgetdatapos;
637 18982 : srclen -= curcol->column_text_sqlgetdatapos;
638 : }
639 52344 : return odbc_tds2sql(stmt, curcol, srctype, src, srclen, desttype, dest, destlen, drec_ixd);
640 : }
641 :
642 194 : SQLLEN odbc_tds2sql_int4(TDS_STMT * stmt, TDS_INT *src, int desttype, TDS_CHAR * dest, SQLULEN destlen)
643 : {
644 194 : return odbc_tds2sql(stmt, NULL, SYBINT4, (TDS_CHAR *) src, sizeof(*src),
645 : desttype, dest, destlen, NULL);
646 : }
|