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