Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3 : * Copyright (C) 2015 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 <stdarg.h>
24 :
25 : #include <freetds/time.h>
26 :
27 : #include <stdio.h>
28 : #include <assert.h>
29 :
30 : #if HAVE_STDLIB_H
31 : #include <stdlib.h>
32 : #endif /* HAVE_STDLIB_H */
33 :
34 : #if HAVE_STRING_H
35 : #include <string.h>
36 : #endif /* HAVE_STRING_H */
37 :
38 : #include <freetds/replacements.h>
39 : #include <freetds/utils.h>
40 :
41 : #include "cspublic.h"
42 : #include "ctlib.h"
43 :
44 : #undef cs_dt_crack
45 :
46 : static CS_INT cs_diag_storemsg(CS_CONTEXT *context, CS_CLIENTMSG *message);
47 : static CS_INT cs_diag_clearmsg(CS_CONTEXT *context, CS_INT type);
48 : static CS_INT cs_diag_getmsg(CS_CONTEXT *context, CS_INT idx, CS_CLIENTMSG *message);
49 : static CS_INT cs_diag_countmsg(CS_CONTEXT *context, CS_INT *count);
50 :
51 : const char *
52 0 : cs_prretcode(int retcode)
53 : {
54 : static char unknown[24];
55 :
56 0 : tdsdump_log(TDS_DBG_FUNC, "cs_prretcode(%d)\n", retcode);
57 :
58 0 : switch(retcode) {
59 : case CS_SUCCEED: return "CS_SUCCEED";
60 0 : case CS_FAIL: return "CS_FAIL";
61 0 : case CS_MEM_ERROR: return "CS_MEM_ERROR";
62 0 : case CS_PENDING: return "CS_PENDING";
63 0 : case CS_QUIET: return "CS_QUIET";
64 0 : case CS_BUSY: return "CS_BUSY";
65 0 : case CS_INTERRUPT: return "CS_INTERRUPT";
66 0 : case CS_BLK_HAS_TEXT: return "CS_BLK_HAS_TEXT";
67 0 : case CS_CONTINUE: return "CS_CONTINUE";
68 0 : case CS_FATAL: return "CS_FATAL";
69 0 : case CS_RET_HAFAILOVER: return "CS_RET_HAFAILOVER";
70 0 : case CS_UNSUPPORTED: return "CS_UNSUPPORTED";
71 :
72 0 : case CS_CANCELED: return "CS_CANCELED";
73 0 : case CS_ROW_FAIL: return "CS_ROW_FAIL";
74 0 : case CS_END_DATA: return "CS_END_DATA";
75 0 : case CS_END_RESULTS: return "CS_END_RESULTS";
76 0 : case CS_END_ITEM: return "CS_END_ITEM";
77 0 : case CS_NOMSG: return "CS_NOMSG";
78 0 : case CS_TIMED_OUT: return "CS_TIMED_OUT";
79 :
80 0 : default:
81 0 : sprintf(unknown, "oops: %u ??", retcode);
82 : }
83 0 : return unknown;
84 : }
85 :
86 : static const char *
87 300 : _cs_get_layer(int layer)
88 : {
89 300 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_layer(%d)\n", layer);
90 :
91 300 : switch (layer) {
92 : case 2:
93 : return "cslib user api layer";
94 : break;
95 : default:
96 : break;
97 : }
98 0 : return "unrecognized layer";
99 : }
100 :
101 : static const char *
102 300 : _cs_get_origin(int origin)
103 : {
104 300 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_origin(%d)\n", origin);
105 :
106 300 : switch (origin) {
107 : case 1:
108 : return "external error";
109 : break;
110 0 : case 2:
111 0 : return "internal CS-Library error";
112 : break;
113 10 : case 4:
114 10 : return "common library error";
115 : break;
116 0 : case 5:
117 0 : return "intl library error";
118 : break;
119 : default:
120 : break;
121 : }
122 0 : return "unrecognized origin";
123 : }
124 :
125 : static const char *
126 300 : _cs_get_user_api_layer_error(int error)
127 : {
128 300 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_user_api_layer_error(%d)\n", error);
129 :
130 300 : switch (error) {
131 : case 2:
132 : return "The information being retrieved will not fit in a buffer of %1! bytes.";
133 : break;
134 0 : case 3:
135 0 : return "Memory allocation failure.";
136 : break;
137 60 : case 4:
138 60 : return "The parameter %1! cannot be NULL.";
139 : break;
140 170 : case 6:
141 170 : return "An illegal value of %1! was given for parameter %2!.";
142 : break;
143 40 : case 16:
144 40 : return "Conversion between %1! and %2! datatypes is not supported.";
145 : break;
146 10 : case 18:
147 10 : return "An illegal value of %1! was placed in the %2! field of the CS_DATAFMT structure.";
148 : break;
149 10 : case 20:
150 10 : return "The conversion/operation resulted in overflow.";
151 : break;
152 0 : case 24:
153 0 : return "The conversion/operation was stopped due to a syntax error in the source field.";
154 : break;
155 0 : case 36:
156 0 : return "The result is truncated because the conversion/operation resulted in overflow.";
157 : break;
158 : default:
159 : break;
160 : }
161 0 : return "unrecognized error";
162 : }
163 :
164 : static char *
165 300 : _cs_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
166 : {
167 : char *m;
168 :
169 300 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_msgstr(%s, %d, %d, %d, %d)\n", funcname, layer, origin, severity, number);
170 :
171 300 : if (asprintf(&m, "%s: %s: %s: %s", funcname, _cs_get_layer(layer), _cs_get_origin(origin), (layer == 2)
172 : ? _cs_get_user_api_layer_error(number)
173 : : "unrecognized error") < 0) {
174 : return NULL;
175 : }
176 300 : return m;
177 : }
178 :
179 : static void
180 470 : _csclient_msg(CS_CONTEXT * ctx, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...)
181 : {
182 : va_list ap;
183 : CS_CLIENTMSG cm;
184 : char *msgstr;
185 :
186 470 : tdsdump_log(TDS_DBG_FUNC, "_csclient_msg(%p, %s, %d, %d, %d, %d, %s)\n", ctx, funcname, layer, origin, severity, number, fmt);
187 :
188 470 : va_start(ap, fmt);
189 :
190 470 : if (ctx->cslibmsg_cb) {
191 300 : cm.severity = severity;
192 600 : cm.msgnumber = (((layer << 24) & 0xFF000000)
193 300 : | ((origin << 16) & 0x00FF0000)
194 300 : | ((severity << 8) & 0x0000FF00)
195 300 : | ((number) & 0x000000FF));
196 300 : msgstr = _cs_get_msgstr(funcname, layer, origin, severity, number);
197 300 : tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
198 300 : cm.msgstring[cm.msgstringlen] = '\0';
199 300 : free(msgstr);
200 300 : cm.osnumber = 0;
201 300 : cm.osstring[0] = '\0';
202 300 : cm.osstringlen = 0;
203 300 : cm.status = 0;
204 : /* cm.sqlstate */
205 300 : cm.sqlstatelen = 0;
206 300 : ctx->cslibmsg_cb(ctx, &cm);
207 : }
208 :
209 470 : va_end(ap);
210 470 : }
211 :
212 : /**
213 : * Allocate new CS_LOCALE and initialize it
214 : * returns NULL on out of memory errors
215 : */
216 : static CS_LOCALE *
217 20 : _cs_locale_alloc(void)
218 : {
219 20 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_alloc()\n");
220 :
221 20 : return tds_new0(CS_LOCALE, 1);
222 : }
223 :
224 : static void
225 20 : _cs_locale_free_contents(CS_LOCALE *locale)
226 : {
227 20 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_free_contents(%p)\n", locale);
228 :
229 : /* free strings */
230 20 : free(locale->language);
231 20 : locale->language = NULL;
232 20 : free(locale->charset);
233 20 : locale->charset = NULL;
234 20 : free(locale->time);
235 20 : locale->time = NULL;
236 20 : free(locale->collate);
237 20 : locale->collate = NULL;
238 20 : }
239 :
240 : void
241 20 : _cs_locale_free(CS_LOCALE *locale)
242 : {
243 20 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_free(%p)\n", locale);
244 :
245 : /* free contents */
246 20 : _cs_locale_free_contents(locale);
247 :
248 : /* free the data structure */
249 20 : free(locale);
250 20 : }
251 :
252 : /* returns 0 on out of memory errors, 1 for OK */
253 : int
254 0 : _cs_locale_copy_inplace(CS_LOCALE *new_locale, CS_LOCALE *orig)
255 : {
256 0 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_copy_inplace(%p, %p)\n", new_locale, orig);
257 :
258 0 : _cs_locale_free_contents(new_locale);
259 0 : if (orig->language) {
260 0 : new_locale->language = strdup(orig->language);
261 0 : if (!new_locale->language)
262 : goto Cleanup;
263 : }
264 :
265 0 : if (orig->charset) {
266 0 : new_locale->charset = strdup(orig->charset);
267 0 : if (!new_locale->charset)
268 : goto Cleanup;
269 : }
270 :
271 0 : if (orig->time) {
272 0 : new_locale->time = strdup(orig->time);
273 0 : if (!new_locale->time)
274 : goto Cleanup;
275 : }
276 :
277 0 : if (orig->collate) {
278 0 : new_locale->collate = strdup(orig->collate);
279 0 : if (!new_locale->collate)
280 : goto Cleanup;
281 : }
282 :
283 : return 1;
284 :
285 0 : Cleanup:
286 0 : _cs_locale_free_contents(new_locale);
287 0 : return 0;
288 : }
289 :
290 : /* returns NULL on out of memory errors */
291 : CS_LOCALE *
292 0 : _cs_locale_copy(CS_LOCALE *orig)
293 : {
294 : CS_LOCALE *new_locale;
295 :
296 0 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_copy(%p)\n", orig);
297 :
298 0 : new_locale = _cs_locale_alloc();
299 0 : if (!new_locale)
300 : return NULL;
301 :
302 0 : if (orig->language) {
303 0 : new_locale->language = strdup(orig->language);
304 0 : if (!new_locale->language)
305 : goto Cleanup;
306 : }
307 :
308 0 : if (orig->charset) {
309 0 : new_locale->charset = strdup(orig->charset);
310 0 : if (!new_locale->charset)
311 : goto Cleanup;
312 : }
313 :
314 0 : if (orig->time) {
315 0 : new_locale->time = strdup(orig->time);
316 0 : if (!new_locale->time)
317 : goto Cleanup;
318 : }
319 :
320 0 : if (orig->collate) {
321 0 : new_locale->collate = strdup(orig->collate);
322 0 : if (!new_locale->collate)
323 : goto Cleanup;
324 : }
325 :
326 : return new_locale;
327 :
328 0 : Cleanup:
329 0 : _cs_locale_free(new_locale);
330 0 : return NULL;
331 : }
332 :
333 : CS_RETCODE
334 1410 : cs_ctx_alloc(CS_INT version, CS_CONTEXT ** out_ctx)
335 : {
336 : TDSCONTEXT *tds_ctx;
337 : CS_CONTEXT *ctx;
338 :
339 1410 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_alloc(%d, %p)\n", version, out_ctx);
340 :
341 1410 : ctx = tds_new0(CS_CONTEXT, 1);
342 1410 : if (!ctx)
343 : return CS_FAIL;
344 1410 : ctx->use_large_identifiers = _ct_is_large_identifiers_version(version);
345 1410 : tds_ctx = tds_alloc_context(ctx);
346 1410 : if (!tds_ctx) {
347 0 : free(ctx);
348 0 : return CS_FAIL;
349 : }
350 1410 : ctx->tds_ctx = tds_ctx;
351 1410 : if (tds_ctx->locale && !tds_ctx->locale->datetime_fmt) {
352 : /* set default in case there's no locale file */
353 0 : tds_ctx->locale->datetime_fmt = strdup(STD_DATETIME_FMT);
354 : }
355 :
356 1410 : ctx->login_timeout = -1;
357 1410 : ctx->query_timeout = -1;
358 :
359 1410 : *out_ctx = ctx;
360 1410 : return CS_SUCCEED;
361 : }
362 :
363 : CS_RETCODE
364 0 : cs_ctx_global(CS_INT version, CS_CONTEXT ** ctx)
365 : {
366 : static CS_CONTEXT *global_cs_ctx = NULL;
367 :
368 0 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_global(%d, %p)\n", version, ctx);
369 :
370 0 : if (global_cs_ctx != NULL) {
371 0 : *ctx = global_cs_ctx;
372 0 : return CS_SUCCEED;
373 : }
374 0 : if (cs_ctx_alloc(version, ctx) != CS_SUCCEED) {
375 : return CS_FAIL;
376 : }
377 0 : global_cs_ctx = *ctx;
378 0 : return CS_SUCCEED;
379 : }
380 :
381 : CS_RETCODE
382 1410 : cs_ctx_drop(CS_CONTEXT * ctx)
383 : {
384 1410 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_drop(%p)\n", ctx);
385 :
386 1410 : if (ctx) {
387 1410 : _ct_diag_clearmsg(ctx, CS_ALLMSG_TYPE);
388 1410 : free(ctx->userdata);
389 1410 : if (ctx->tds_ctx)
390 1410 : tds_free_context(ctx->tds_ctx);
391 1410 : free(ctx);
392 : }
393 1410 : return CS_SUCCEED;
394 : }
395 :
396 : CS_RETCODE
397 240 : cs_config(CS_CONTEXT * ctx, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
398 : {
399 : CS_INT maxcp; /* declared for - CS_USERDATA changes - swapna*/
400 :
401 240 : tdsdump_log(TDS_DBG_FUNC, "cs_config(%p, %d, %d, %p, %d, %p)\n", ctx, action, property, buffer, buflen, outlen);
402 :
403 240 : if (action == CS_GET) {
404 80 : if (buffer == NULL) {
405 : return CS_SUCCEED;
406 : }
407 80 : switch (property) {
408 0 : case CS_MESSAGE_CB:
409 0 : *(CS_CSLIBMSG_FUNC*) buffer = ctx->cslibmsg_cb;
410 0 : return CS_SUCCEED;
411 80 : case CS_USERDATA:
412 80 : if (buflen < 0) {
413 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
414 10 : return CS_FAIL;
415 : }
416 :
417 70 : maxcp = ctx->userdata_len;
418 70 : if (outlen)
419 40 : *outlen = maxcp;
420 :
421 70 : if (buflen < maxcp) {
422 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 2, "%d", buflen);
423 10 : return CS_FAIL;
424 : }
425 60 : memcpy(buffer, ctx->userdata, maxcp);
426 60 : return CS_SUCCEED;
427 :
428 0 : default:
429 : case CS_EXTRA_INF:
430 : case CS_LOC_PROP:
431 : case CS_VERSION:
432 0 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
433 0 : return CS_FAIL;
434 : break;
435 : }
436 : }
437 160 : if (action == CS_SET) {
438 150 : switch (property) {
439 30 : case CS_MESSAGE_CB:
440 30 : if ( ctx->cs_errhandletype == _CS_ERRHAND_INLINE) {
441 0 : cs_diag_clearmsg(ctx, CS_UNUSED);
442 : }
443 30 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) buffer;
444 30 : ctx->cs_errhandletype = _CS_ERRHAND_CB;
445 30 : return CS_SUCCEED;
446 110 : case CS_USERDATA:
447 110 : if (buflen < 0 && buflen != CS_NULLTERM) {
448 60 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
449 60 : return CS_FAIL;
450 : }
451 :
452 50 : maxcp = _ct_get_string_length(buffer, buflen);
453 50 : free(ctx->userdata);
454 50 : ctx->userdata = (void *) malloc(maxcp);
455 50 : if ( ctx->userdata == NULL) {
456 : return CS_FAIL;
457 : }
458 50 : ctx->userdata_len = maxcp;
459 :
460 50 : if (buffer) {
461 50 : memcpy(ctx->userdata, buffer, maxcp);
462 : } else {
463 : return CS_FAIL;
464 : }
465 50 : return CS_SUCCEED;
466 :
467 10 : default:
468 : case CS_EXTRA_INF:
469 : case CS_LOC_PROP:
470 : case CS_VERSION:
471 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
472 10 : return CS_FAIL;
473 : break;
474 : }
475 : }
476 10 : if (action == CS_CLEAR) {
477 0 : switch (property) {
478 0 : case CS_MESSAGE_CB:
479 0 : if ( ctx->cs_errhandletype == _CS_ERRHAND_INLINE) {
480 0 : cs_diag_clearmsg(ctx, CS_UNUSED);
481 : }
482 0 : ctx->cslibmsg_cb = NULL;
483 0 : ctx->cs_errhandletype = 0;
484 0 : return CS_SUCCEED;
485 0 : case CS_USERDATA:
486 0 : free(ctx->userdata);
487 0 : ctx->userdata = NULL;
488 0 : ctx->userdata_len = 0;
489 :
490 0 : return CS_SUCCEED;
491 :
492 0 : default:
493 : case CS_EXTRA_INF:
494 : case CS_LOC_PROP:
495 : case CS_VERSION:
496 0 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
497 0 : return CS_FAIL;
498 : break;
499 : }
500 : }
501 :
502 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", action, "action");
503 10 : return CS_FAIL;
504 : }
505 :
506 : CS_RETCODE
507 9095 : _cs_convert(CS_CONTEXT * ctx, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata,
508 : const CS_DATAFMT_COMMON * destfmt, CS_VOID * destdata, CS_INT * resultlen, TDS_SERVER_TYPE desttype)
509 : {
510 : TDS_SERVER_TYPE src_type;
511 : int src_len, destlen, len;
512 : CONV_RESULT cres;
513 : unsigned char *dest;
514 : CS_RETCODE ret;
515 : CS_INT dummy, datatype;
516 9095 : CS_VARCHAR *destvc = NULL;
517 :
518 9095 : tdsdump_log(TDS_DBG_FUNC, "cs_convert(%p, %p, %p, %p, %p, %p, %d)\n",
519 : ctx, srcfmt, srcdata, destfmt, destdata, resultlen, desttype);
520 :
521 : /* If destfmt is NULL we have a problem */
522 9095 : if (destfmt == NULL) {
523 20 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destfmt");
524 20 : return CS_FAIL;
525 : }
526 :
527 : /* If destination is NULL we have a problem */
528 9075 : if (destdata == NULL) {
529 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destdata");
530 10 : return CS_FAIL;
531 :
532 : }
533 :
534 9065 : if (resultlen == NULL)
535 40 : resultlen = &dummy;
536 :
537 : /* If source is indicated to be NULL, set dest to low values */
538 9065 : if (srcdata == NULL) {
539 : /* TODO: implement cs_setnull */
540 0 : tdsdump_log(TDS_DBG_FUNC, "srcdata is null\n");
541 0 : memset(destdata, '\0', destfmt->maxlength);
542 0 : *resultlen = 0;
543 0 : return CS_SUCCEED;
544 : }
545 :
546 9065 : datatype = srcfmt->datatype;
547 9065 : src_type = _ct_get_server_type(NULL, datatype);
548 9065 : if (src_type == TDS_INVALID_TYPE) {
549 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", srcfmt->datatype, destfmt->datatype);
550 10 : return CS_FAIL;
551 : }
552 9055 : src_len = srcfmt->maxlength;
553 9055 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
554 0 : CS_VARCHAR *vc = (CS_VARCHAR *) srcdata;
555 0 : src_len = vc->len;
556 0 : srcdata = vc->str;
557 : }
558 :
559 9055 : datatype = destfmt->datatype;
560 9055 : if (desttype == TDS_INVALID_TYPE) {
561 9055 : desttype = _ct_get_server_type(NULL, datatype);
562 9055 : if (desttype == TDS_INVALID_TYPE) {
563 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d",
564 : srcfmt->datatype, destfmt->datatype);
565 10 : return CS_FAIL;
566 : }
567 : }
568 9045 : destlen = destfmt->maxlength;
569 9045 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
570 30 : destvc = (CS_VARCHAR *) destdata;
571 30 : destlen = sizeof(destvc->str);
572 30 : destdata = destvc->str;
573 9015 : } else if (is_numeric_type(desttype)) {
574 250 : destlen = sizeof(TDS_NUMERIC);
575 : }
576 :
577 9045 : tdsdump_log(TDS_DBG_FUNC, "converting type %d (%d bytes) to type = %d (%d bytes)\n",
578 : src_type, src_len, desttype, destlen);
579 :
580 9045 : if (!is_fixed_type(desttype) && destlen < 0) {
581 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", destlen, "maxlength");
582 10 : return CS_FAIL;
583 : }
584 :
585 9035 : dest = (unsigned char *) destdata;
586 :
587 : /* many times we are asked to convert a data type to itself */
588 :
589 9035 : if (src_type == desttype) {
590 3018 : int minlen = src_len < destlen? src_len : destlen;
591 :
592 3018 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() srctype == desttype\n");
593 3018 : switch (desttype) {
594 :
595 140 : case SYBLONGBINARY:
596 : case SYBBINARY:
597 : case SYBVARBINARY:
598 : case SYBIMAGE:
599 140 : memcpy(dest, srcdata, minlen);
600 140 : *resultlen = minlen;
601 :
602 140 : if (src_len > destlen) {
603 20 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
604 20 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
605 20 : ret = CS_FAIL;
606 : } else {
607 120 : switch (destfmt->format) {
608 0 : case CS_FMT_PADNULL:
609 0 : memset(dest + src_len, '\0', destlen - src_len);
610 0 : *resultlen = destlen;
611 : /* fall through */
612 : case CS_FMT_UNUSED:
613 : ret = CS_SUCCEED;
614 : break;
615 : default:
616 : ret = CS_FAIL;
617 : break;
618 : }
619 : }
620 140 : if (destvc) {
621 0 : destvc->len = minlen;
622 0 : *resultlen = sizeof(*destvc);
623 : }
624 : break;
625 :
626 2526 : case SYBCHAR:
627 : case SYBVARCHAR:
628 : case SYBTEXT:
629 2526 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() desttype = character\n");
630 :
631 2526 : memcpy(dest, srcdata, minlen);
632 2526 : *resultlen = minlen;
633 :
634 2526 : if (src_len > destlen) {
635 10 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
636 10 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
637 10 : ret = CS_FAIL;
638 : } else {
639 2516 : switch (destfmt->format) {
640 2158 : case CS_FMT_NULLTERM:
641 2158 : if (src_len == destlen) {
642 0 : *resultlen = src_len;
643 0 : tdsdump_log(TDS_DBG_FUNC, "error: no room for null terminator\n");
644 : ret = CS_FAIL;
645 : } else {
646 2158 : dest[src_len] = '\0';
647 2158 : *resultlen = src_len + 1;
648 2158 : ret = CS_SUCCEED;
649 : }
650 : break;
651 :
652 0 : case CS_FMT_PADBLANK:
653 0 : memset(dest + src_len, ' ', destlen - src_len);
654 0 : *resultlen = destlen;
655 0 : ret = CS_SUCCEED;
656 0 : break;
657 0 : case CS_FMT_PADNULL:
658 0 : memset(dest + src_len, '\0', destlen - src_len);
659 0 : *resultlen = destlen;
660 0 : ret = CS_SUCCEED;
661 0 : break;
662 : case CS_FMT_UNUSED:
663 : ret = CS_SUCCEED;
664 : break;
665 0 : default:
666 0 : tdsdump_log(TDS_DBG_FUNC, "no destination format specified!\n");
667 : ret = CS_FAIL;
668 : break;
669 : }
670 : }
671 2526 : if (destvc) {
672 0 : destvc->len = minlen;
673 0 : *resultlen = sizeof(*destvc);
674 : }
675 : break;
676 342 : case SYBINT1:
677 : case SYBUINT1:
678 : case SYBINT2:
679 : case SYBUINT2:
680 : case SYBINT4:
681 : case SYBUINT4:
682 : case SYBINT8:
683 : case SYBUINT8:
684 : case SYBFLT8:
685 : case SYBREAL:
686 : case SYBBIT:
687 : case SYBMONEY:
688 : case SYBMONEY4:
689 : case SYBDATETIME:
690 : case SYBDATETIME4:
691 : case SYBTIME:
692 : case SYBDATE:
693 : case SYB5BIGDATETIME:
694 : case SYB5BIGTIME:
695 342 : *resultlen = tds_get_size_by_type(src_type);
696 342 : if (*resultlen > 0)
697 342 : memcpy(dest, srcdata, *resultlen);
698 : ret = CS_SUCCEED;
699 : break;
700 :
701 10 : case SYBNUMERIC:
702 : case SYBDECIMAL:
703 10 : src_len = tds_numeric_bytes_per_prec[((TDS_NUMERIC *) srcdata)->precision] + 2;
704 10 : case SYBBITN:
705 : case SYBUNIQUE:
706 10 : memcpy(dest, srcdata, minlen);
707 10 : *resultlen = minlen;
708 :
709 10 : if (src_len > destlen) {
710 0 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
711 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
712 0 : ret = CS_FAIL;
713 : } else {
714 : ret = CS_SUCCEED;
715 : }
716 : break;
717 :
718 0 : default:
719 0 : tdsdump_log(TDS_DBG_FUNC, "error: unrecognized type\n");
720 : ret = CS_FAIL;
721 : break;
722 : }
723 :
724 3018 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret));
725 : return ret;
726 :
727 : }
728 :
729 : assert(src_type != desttype);
730 :
731 : /* set the output precision/scale for conversions to numeric type */
732 6017 : if (is_numeric_type(desttype)) {
733 240 : cres.n.precision = destfmt->precision;
734 240 : cres.n.scale = destfmt->scale;
735 240 : if (destfmt->precision == CS_SRC_VALUE)
736 0 : cres.n.precision = srcfmt->precision;
737 240 : if (destfmt->scale == CS_SRC_VALUE)
738 0 : cres.n.scale = srcfmt->scale;
739 : }
740 :
741 6017 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() calling tds_convert\n");
742 6017 : len = tds_convert(ctx->tds_ctx, src_type, srcdata, src_len, desttype, &cres);
743 :
744 6017 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() tds_convert returned %d\n", len);
745 :
746 6017 : switch (len) {
747 30 : case TDS_CONVERT_NOAVAIL:
748 30 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", src_type, desttype);
749 30 : return CS_FAIL;
750 : break;
751 40 : case TDS_CONVERT_SYNTAX:
752 40 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 24, "");
753 40 : return CS_FAIL;
754 : break;
755 0 : case TDS_CONVERT_NOMEM:
756 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 3, "");
757 0 : return CS_FAIL;
758 : break;
759 60 : case TDS_CONVERT_OVERFLOW:
760 60 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 20, "");
761 60 : return CS_FAIL;
762 : break;
763 : case TDS_CONVERT_FAIL:
764 : return CS_FAIL;
765 : break;
766 5887 : default:
767 5887 : if (len < 0) {
768 : return CS_FAIL;
769 : }
770 : break;
771 : }
772 :
773 5887 : switch (desttype) {
774 100 : case SYBBINARY:
775 : case SYBVARBINARY:
776 : case SYBIMAGE:
777 100 : ret = CS_SUCCEED;
778 100 : if (len > destlen) {
779 30 : tdsdump_log(TDS_DBG_FUNC, "error_handler: Data-conversion resulted in overflow\n");
780 30 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
781 30 : ret = CS_FAIL;
782 30 : len = destlen;
783 : }
784 100 : memcpy(dest, cres.ib, len);
785 100 : free(cres.ib);
786 100 : *resultlen = len;
787 100 : if (destvc) {
788 20 : destvc->len = len;
789 20 : *resultlen = sizeof(*destvc);
790 80 : } else if (destfmt->format == CS_FMT_PADNULL) {
791 20 : *resultlen = destlen;
792 20 : memset(dest + len, '\0', destlen - len);
793 : }
794 : break;
795 1396 : case SYBBIT:
796 : case SYBBITN:
797 : /* fall trough, act same way of TINYINT */
798 : case SYBINT1:
799 : case SYBUINT1:
800 : case SYBINT2:
801 : case SYBUINT2:
802 : case SYBINT4:
803 : case SYBUINT4:
804 : case SYBINT8:
805 : case SYBUINT8:
806 : case SYBFLT8:
807 : case SYBREAL:
808 : case SYBMONEY:
809 : case SYBMONEY4:
810 : case SYBDATETIME:
811 : case SYBDATETIME4:
812 : case SYBTIME:
813 : case SYBDATE:
814 : case SYBUNIQUE:
815 : case SYB5BIGDATETIME:
816 : case SYB5BIGTIME:
817 1396 : *resultlen = tds_get_size_by_type(desttype);
818 1396 : memcpy(dest, &(cres.ti), *resultlen);
819 1396 : ret = CS_SUCCEED;
820 1396 : break;
821 240 : case SYBNUMERIC:
822 : case SYBDECIMAL:
823 240 : src_len = tds_numeric_bytes_per_prec[cres.n.precision] + 2;
824 240 : memcpy(dest, &(cres.n), src_len);
825 240 : *resultlen = src_len;
826 240 : ret = CS_SUCCEED;
827 240 : break;
828 0 : case SYBMSTIME:
829 : case SYBMSDATE:
830 : case SYBMSDATETIME2:
831 : case SYBMSDATETIMEOFFSET:
832 0 : *resultlen = sizeof(TDS_DATETIMEALL);
833 0 : memcpy(dest, &(cres.dta), *resultlen);
834 0 : ret = CS_SUCCEED;
835 0 : break;
836 4151 : case SYBCHAR:
837 : case SYBVARCHAR:
838 : case SYBTEXT:
839 4151 : ret = CS_SUCCEED;
840 4151 : if (len > destlen) {
841 10 : tdsdump_log(TDS_DBG_FUNC, "Data-conversion resulted in overflow\n");
842 10 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
843 10 : len = destlen;
844 10 : ret = CS_FAIL;
845 : }
846 4151 : switch (destfmt->format) {
847 :
848 2435 : case CS_FMT_NULLTERM:
849 2435 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_NULLTERM\n");
850 2435 : if (len == destlen) {
851 0 : tdsdump_log(TDS_DBG_FUNC, "not enough room for data + a null terminator - error\n");
852 : ret = CS_FAIL; /* not enough room for data + a null terminator - error */
853 : } else {
854 2435 : memcpy(dest, cres.c, len);
855 2435 : dest[len] = 0;
856 2435 : *resultlen = len + 1;
857 : }
858 : break;
859 :
860 0 : case CS_FMT_PADBLANK:
861 0 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADBLANK\n");
862 : /* strcpy here can lead to a small buffer overflow */
863 0 : memcpy(dest, cres.c, len);
864 0 : memset(dest + len, ' ', destlen - len);
865 0 : *resultlen = destlen;
866 0 : break;
867 :
868 0 : case CS_FMT_PADNULL:
869 0 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADNULL\n");
870 : /* strcpy here can lead to a small buffer overflow */
871 0 : memcpy(dest, cres.c, len);
872 0 : memset(dest + len, '\0', destlen - len);
873 0 : *resultlen = destlen;
874 0 : break;
875 1716 : case CS_FMT_UNUSED:
876 1716 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_UNUSED\n");
877 1716 : memcpy(dest, cres.c, len);
878 1716 : *resultlen = len;
879 1716 : break;
880 : default:
881 : ret = CS_FAIL;
882 : break;
883 : }
884 4151 : if (destvc) {
885 10 : destvc->len = len;
886 10 : *resultlen = sizeof(*destvc);
887 : }
888 4151 : free(cres.c);
889 4151 : break;
890 : default:
891 : ret = CS_FAIL;
892 : break;
893 : }
894 5887 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret));
895 : return (ret);
896 : }
897 :
898 : CS_RETCODE
899 2390 : cs_convert(CS_CONTEXT * ctx, CS_DATAFMT * srcfmt, CS_VOID * srcdata, CS_DATAFMT * destfmt, CS_VOID * destdata, CS_INT * resultlen)
900 : {
901 2390 : return _cs_convert(ctx, _ct_datafmt_common(ctx, srcfmt), srcdata,
902 : _ct_datafmt_common(ctx, destfmt), destdata, resultlen, TDS_INVALID_TYPE);
903 : }
904 :
905 : CS_RETCODE
906 0 : cs_dt_crack_v2(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
907 : {
908 : TDSDATEREC dr;
909 : TDS_INT tds_type;
910 0 : bool extended = false;
911 :
912 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack_v2(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
913 :
914 0 : switch (datetype) {
915 : case CS_DATETIME_TYPE:
916 : tds_type = SYBDATETIME;
917 : break;
918 0 : case CS_DATETIME4_TYPE:
919 0 : tds_type = SYBDATETIME4;
920 0 : break;
921 0 : case CS_DATE_TYPE:
922 0 : tds_type = SYBDATE;
923 0 : break;
924 0 : case CS_TIME_TYPE:
925 0 : tds_type = SYBTIME;
926 0 : break;
927 0 : case CS_BIGDATETIME_TYPE:
928 0 : tds_type = SYB5BIGDATETIME;
929 0 : extended = true;
930 0 : break;
931 0 : case CS_BIGTIME_TYPE:
932 0 : tds_type = SYB5BIGTIME;
933 0 : extended = true;
934 0 : break;
935 : default:
936 : return CS_FAIL;
937 : }
938 0 : tds_datecrack(tds_type, dateval, &dr);
939 :
940 : /* Sybase CT-Library does not set these fields for CS_BIGTIME_TYPE */
941 0 : if (tds_type != SYB5BIGTIME) {
942 0 : daterec->dateyear = dr.year;
943 0 : daterec->datemonth = dr.month;
944 0 : daterec->datedmonth = dr.day;
945 0 : daterec->datedyear = dr.dayofyear;
946 0 : daterec->datedweek = dr.weekday;
947 : }
948 0 : daterec->datehour = dr.hour;
949 0 : daterec->dateminute = dr.minute;
950 0 : daterec->datesecond = dr.second;
951 0 : daterec->datemsecond = dr.decimicrosecond / 10000u;
952 0 : daterec->datetzone = dr.timezone;
953 0 : if (extended) {
954 0 : daterec->datesecfrac = dr.decimicrosecond / 10u;
955 0 : daterec->datesecprec = 1000000;
956 : }
957 :
958 : return CS_SUCCEED;
959 : }
960 :
961 : CS_RETCODE
962 0 : cs_dt_crack(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
963 : {
964 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
965 :
966 : /* Avoid handling CS_BIGDATETIME_TYPE and CS_BIGTIME_TYPE as these
967 : * types requires a larger structure that would cause a buffer overflow. */
968 0 : if (datetype != CS_BIGDATETIME_TYPE && datetype != CS_BIGTIME_TYPE)
969 0 : return cs_dt_crack_v2(ctx, datetype, dateval, daterec);
970 : return CS_FAIL;
971 : }
972 :
973 : CS_RETCODE
974 40 : cs_loc_alloc(CS_CONTEXT * ctx, CS_LOCALE ** loc_pointer)
975 : {
976 : CS_LOCALE *tds_csloc;
977 :
978 40 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_alloc(%p, %p)\n", ctx, loc_pointer);
979 :
980 40 : if (!ctx)
981 : return CS_FAIL;
982 :
983 30 : if (!loc_pointer) {
984 10 : _csclient_msg(ctx, "cs_loc_alloc", 2, 1, 1, 4, "loc_pointer");
985 10 : return CS_FAIL;
986 : }
987 :
988 20 : tds_csloc = _cs_locale_alloc();
989 20 : if (!tds_csloc)
990 : return CS_FAIL;
991 :
992 20 : *loc_pointer = tds_csloc;
993 20 : return CS_SUCCEED;
994 : }
995 :
996 : CS_RETCODE
997 40 : cs_loc_drop(CS_CONTEXT * ctx, CS_LOCALE * locale)
998 : {
999 40 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_drop(%p, %p)\n", ctx, locale);
1000 :
1001 40 : if (!ctx)
1002 : return CS_FAIL;
1003 :
1004 30 : if (!locale) {
1005 10 : _csclient_msg(ctx, "cs_loc_drop", 2, 1, 1, 4, "locale");
1006 10 : return CS_FAIL;
1007 : }
1008 :
1009 20 : _cs_locale_free(locale);
1010 20 : return CS_SUCCEED;
1011 : }
1012 :
1013 : CS_RETCODE
1014 60 : cs_locale(CS_CONTEXT * ctx, CS_INT action, CS_LOCALE * locale, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
1015 : {
1016 : static const char func[] = "cs_locale";
1017 60 : CS_RETCODE code = CS_FAIL;
1018 :
1019 60 : tdsdump_log(TDS_DBG_FUNC, "cs_locale(%p, %d, %p, %d, %p, %d, %p)\n", ctx, action, locale, type, buffer, buflen, outlen);
1020 :
1021 60 : if (!ctx)
1022 : return CS_FAIL;
1023 :
1024 50 : if (!locale) {
1025 10 : _csclient_msg(ctx, func, 2, 1, 1, 4, "locale");
1026 10 : return CS_FAIL;
1027 : }
1028 :
1029 40 : if (action == CS_SET) {
1030 30 : switch (type) {
1031 0 : case CS_LC_ALL:
1032 : /* what to do here if there is locale data? */
1033 0 : if (!buffer) {
1034 0 : code = CS_SUCCEED;
1035 : }
1036 : break;
1037 :
1038 20 : case CS_SYB_CHARSET:
1039 20 : buflen = _ct_get_string_length(buffer, buflen);
1040 20 : if (buflen < 0) {
1041 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1042 10 : return CS_FAIL;
1043 : }
1044 :
1045 10 : free(locale->charset);
1046 10 : locale->charset = tds_strndup(buffer, buflen);
1047 10 : if (!locale->charset)
1048 : break;
1049 :
1050 10 : code = CS_SUCCEED;
1051 10 : break;
1052 :
1053 0 : case CS_SYB_LANG:
1054 0 : buflen = _ct_get_string_length(buffer, buflen);
1055 0 : if (buflen < 0) {
1056 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1057 0 : return CS_FAIL;
1058 : }
1059 :
1060 0 : free(locale->language);
1061 0 : locale->language = tds_strndup(buffer, buflen);
1062 0 : if (!locale->language)
1063 : break;
1064 :
1065 0 : code = CS_SUCCEED;
1066 0 : break;
1067 :
1068 0 : case CS_SYB_LANG_CHARSET:
1069 : {
1070 : int i;
1071 0 : char *b = (char *)buffer;
1072 :
1073 0 : buflen = _ct_get_string_length(buffer, buflen);
1074 0 : if (buflen < 0) {
1075 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1076 0 : return CS_FAIL;
1077 : }
1078 :
1079 : /* find '.' character */
1080 0 : for (i = 0; i < buflen; ++i) {
1081 0 : if (b[i] == '.') {
1082 : break;
1083 : }
1084 : }
1085 : /* not found */
1086 0 : if (i == buflen) {
1087 : break;
1088 : }
1089 0 : if (i) {
1090 0 : free(locale->language);
1091 0 : locale->language = tds_strndup(b, i);
1092 0 : if (!locale->language)
1093 : break;
1094 : }
1095 0 : if (i != (buflen - 1)) {
1096 0 : free(locale->charset);
1097 0 : locale->charset = tds_strndup(b + i + 1, buflen - i - 1);
1098 0 : if (!locale->charset)
1099 : break;
1100 : }
1101 : code = CS_SUCCEED;
1102 : break;
1103 : }
1104 :
1105 : /* TODO commented out until the code works end-to-end
1106 : case CS_SYB_SORTORDER:
1107 : buflen = _ct_get_string_length(buffer, buflen);
1108 : if (buflen < 0) {
1109 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1110 : return CS_FAIL;
1111 : }
1112 :
1113 : free(locale->collate);
1114 : locale->collate = tds_strndup(buffer, buflen);
1115 : if (!locale->collate)
1116 : break;
1117 :
1118 : code = CS_SUCCEED;
1119 : break;
1120 : */
1121 :
1122 10 : default:
1123 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1124 10 : code = CS_FAIL;
1125 10 : break;
1126 : }
1127 0 : }
1128 10 : else if (action == CS_GET)
1129 : {
1130 : CS_INT tlen;
1131 :
1132 0 : switch (type) {
1133 0 : case CS_SYB_CHARSET:
1134 0 : tlen = (locale->charset ? (CS_INT) strlen(locale->charset) : 0) + 1;
1135 0 : if (buflen < tlen)
1136 : {
1137 0 : if (outlen)
1138 0 : *outlen = tlen;
1139 : break;
1140 : }
1141 0 : if (locale->charset)
1142 0 : strcpy((char *)buffer, locale->charset);
1143 : else
1144 0 : ((char *)buffer)[0] = '\0';
1145 : code = CS_SUCCEED;
1146 : break;
1147 :
1148 0 : case CS_SYB_LANG:
1149 0 : tlen = (locale->language ? (CS_INT) strlen(locale->language) : 0) + 1;
1150 0 : if (buflen < tlen)
1151 : {
1152 0 : if (outlen)
1153 0 : *outlen = tlen;
1154 : break;
1155 : }
1156 0 : if (locale->language)
1157 0 : strcpy((char *)buffer, locale->language);
1158 : else
1159 0 : ((char *)buffer)[0] = '\0';
1160 : code = CS_SUCCEED;
1161 : break;
1162 :
1163 0 : case CS_SYB_LANG_CHARSET:
1164 : {
1165 : CS_INT clen;
1166 :
1167 0 : tlen = (locale->language ? (CS_INT) strlen(locale->language) : 0) + 1;
1168 0 : clen = (locale->charset ? (CS_INT) strlen(locale->charset) : 0) + 1;
1169 :
1170 0 : if (buflen < (tlen + clen))
1171 : {
1172 0 : if (outlen)
1173 0 : *outlen = tlen + clen;
1174 : break;
1175 : }
1176 0 : if (locale->language)
1177 0 : strcpy((char *)buffer, locale->language);
1178 : else
1179 0 : ((char *)buffer)[0] = '\0';
1180 0 : strcat((char *)buffer, ".");
1181 0 : if (locale->charset) {
1182 0 : tlen = (CS_INT) strlen((char *)buffer);
1183 0 : strcpy((char *)buffer + tlen, locale->charset);
1184 : }
1185 : code = CS_SUCCEED;
1186 : break;
1187 : }
1188 :
1189 0 : case CS_SYB_SORTORDER:
1190 0 : tlen = (locale->collate ? (CS_INT) strlen(locale->collate) : 0) + 1;
1191 0 : if (buflen < tlen)
1192 : {
1193 0 : if (outlen)
1194 0 : *outlen = tlen;
1195 : break;
1196 : }
1197 0 : if (locale->collate)
1198 0 : strcpy((char *)buffer, locale->collate);
1199 : else
1200 0 : ((char *)buffer)[0] = '\0';
1201 : code = CS_SUCCEED;
1202 : break;
1203 :
1204 0 : default:
1205 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1206 0 : code = CS_FAIL;
1207 0 : break;
1208 : }
1209 : } else {
1210 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, action", action);
1211 10 : code = CS_FAIL;
1212 : }
1213 : return code;
1214 : }
1215 :
1216 : typedef struct
1217 : {
1218 : CS_INT convfmt;
1219 : const char datetime[26];
1220 : uint8_t date_len;
1221 : uint8_t time_start;
1222 : } CONV_FORMAT;
1223 :
1224 : #define ONLY_DATE(convfmt, datetime) \
1225 : { convfmt, datetime, sizeof(datetime)-1, sizeof(datetime)-1 }
1226 : #define DATE_TIME(convfmt, date, time) \
1227 : { convfmt, date " " time, sizeof(date)-1, sizeof(date) }
1228 : #define ALL__SAME(convfmt, datetime) \
1229 : { convfmt, datetime, sizeof(datetime)-1, 0 }
1230 : static const CONV_FORMAT formats[] = {
1231 : DATE_TIME(CS_DATES_SHORT, "%b %e %Y", "%l:%M%p"),
1232 : ONLY_DATE(CS_DATES_MDY1, "%m/%d/%y"),
1233 : ONLY_DATE(CS_DATES_YMD1, "%y.%m.%d"),
1234 : ONLY_DATE(CS_DATES_DMY1, "%d/%m/%y"),
1235 : ONLY_DATE(CS_DATES_DMY2, "%d.%m.%y"),
1236 : ONLY_DATE(CS_DATES_DMY3, "%d-%m-%y"),
1237 : ONLY_DATE(CS_DATES_DMY4, "%d %b %y"),
1238 : ONLY_DATE(CS_DATES_MDY2, "%b %d, %y"),
1239 : ALL__SAME(CS_DATES_HMS, "%H:%M:%S"),
1240 : DATE_TIME(CS_DATES_LONG, "%b %e %Y", "%l:%M:%S:%z%p"),
1241 : ONLY_DATE(CS_DATES_MDY3, "%m-%d-%y"),
1242 : ONLY_DATE(CS_DATES_YMD2, "%y/%m/%d"),
1243 : ONLY_DATE(CS_DATES_YMD3, "%y%m%d"),
1244 : ONLY_DATE(CS_DATES_YDM1, "%y/%d/%m"),
1245 : ONLY_DATE(CS_DATES_MYD1, "%m/%y/%d"),
1246 : ONLY_DATE(CS_DATES_DYM1, "%d/%y/%m"),
1247 : ALL__SAME(CS_DATES_MDYHMS, "%b %e %Y %H:%M:%S"),
1248 : ALL__SAME(CS_DATES_HMA, "%l:%M%p"),
1249 : ALL__SAME(CS_DATES_HM, "%H:%M"),
1250 : ALL__SAME(CS_DATES_HMSZA, "%l:%M:%S:%3z%p"),
1251 : ALL__SAME(CS_DATES_HMSZ, "%H:%M:%S:%3z"),
1252 : ALL__SAME(CS_DATES_YMDHMS, "%y/%m/%d %H:%M:%S"),
1253 : ALL__SAME(CS_DATES_YMDHMA, "%y/%m/%d %l:%M%p"),
1254 : ALL__SAME(CS_DATES_YMDTHMS, "%Y-%m-%dT%H:%M:%S"),
1255 : ALL__SAME(CS_DATES_HMSUSA, "%l:%M:%S.%6z%p"),
1256 : ALL__SAME(CS_DATES_HMSUS, "%H:%M:%S.%6z"),
1257 : ALL__SAME(CS_DATES_LONGUSA, "%b %e %y %l:%M:%S.%6z%p"),
1258 : ALL__SAME(CS_DATES_LONGUS, "%b %e %y %H:%M:%S.%6z"),
1259 : ALL__SAME(CS_DATES_YMDHMSUS, "%y-%m-%d %H:%M:%S.%6z"),
1260 : ALL__SAME(CS_DATES_SHORT_ALT, "%b %e %Y %l:%M%p"),
1261 : ONLY_DATE(CS_DATES_MDY1_YYYY, "%m/%d/%Y"),
1262 : ONLY_DATE(CS_DATES_YMD1_YYYY, "%Y.%m.%d"),
1263 : ONLY_DATE(CS_DATES_DMY1_YYYY, "%d/%m/%Y"),
1264 : ONLY_DATE(CS_DATES_DMY2_YYYY, "%d.%m.%Y"),
1265 : ONLY_DATE(CS_DATES_DMY3_YYYY, "%d-%m-%Y"),
1266 : ONLY_DATE(CS_DATES_DMY4_YYYY, "%d %b %Y"),
1267 : ONLY_DATE(CS_DATES_MDY2_YYYY, "%b %d, %Y"),
1268 : ALL__SAME(CS_DATES_HMS_ALT, "%H:%M:%S"),
1269 : ALL__SAME(CS_DATES_LONG_ALT, "%b %e %Y %l:%M:%S:%3z%p"),
1270 : ONLY_DATE(CS_DATES_MDY3_YYYY, "%m-%d-%Y"),
1271 : ONLY_DATE(CS_DATES_YMD2_YYYY, "%Y/%m/%d"),
1272 : ONLY_DATE(CS_DATES_YMD3_YYYY, "%Y%m%d"),
1273 : ONLY_DATE(CS_DATES_YDM1_YYYY, "%Y/%d/%m"),
1274 : ONLY_DATE(CS_DATES_MYD1_YYYY, "%m/%Y/%d"),
1275 : ONLY_DATE(CS_DATES_DYM1_YYYY, "%d/%Y/%m"),
1276 : ALL__SAME(CS_DATES_MDYHMS_ALT, "%b %e %Y %H:%M:%S"),
1277 : ALL__SAME(CS_DATES_HMA_ALT, "%l:%M%p"),
1278 : ALL__SAME(CS_DATES_HM_ALT, "%H:%M"),
1279 : ALL__SAME(CS_DATES_YMDHMS_YYYY, "%Y/%m/%d %H:%M:%S"),
1280 : ALL__SAME(CS_DATES_YMDHMA_YYYY, "%Y/%m/%d %l:%M%p"),
1281 : ALL__SAME(CS_DATES_HMSUSA_YYYY, "%l:%M:%S.%6z%p"),
1282 : ALL__SAME(CS_DATES_HMSUS_YYYY, "%H:%M:%S.%6z"),
1283 : ALL__SAME(CS_DATES_LONGUSA_YYYY, "%b %e %Y %l:%M:%S.%6z%p"),
1284 : ALL__SAME(CS_DATES_LONGUS_YYYY, "%b %e %Y %H:%M:%S.%6z"),
1285 : ALL__SAME(CS_DATES_YMDHMSUS_YYYY, "%Y-%m-%d %H:%M:%S.%6z"),
1286 : {-1, "", 0, 0}
1287 : };
1288 :
1289 : static CS_RETCODE
1290 1880 : _cs_set_locale_convfmt(CS_CONTEXT *ctx, TDSLOCALE *loc, CS_INT convfmt)
1291 : {
1292 : const CONV_FORMAT *fmt;
1293 :
1294 33460 : for (fmt = formats; fmt->convfmt >= 0; ++fmt) {
1295 : char *datetime, *date, *time;
1296 :
1297 16730 : if (fmt->convfmt != convfmt)
1298 14850 : continue;
1299 1880 : datetime = strdup(fmt->datetime);
1300 1880 : date = tds_strndup(fmt->datetime, fmt->date_len);
1301 1880 : time = strdup(fmt->datetime + fmt->time_start);
1302 1880 : if (!datetime || !date || !time) {
1303 0 : free(datetime);
1304 0 : free(date);
1305 0 : free(time);
1306 0 : _csclient_msg(ctx, "cs_dt_info", 2, 4, 1, 3, "");
1307 0 : return CS_FAIL;
1308 : }
1309 1880 : free(loc->datetime_fmt);
1310 1880 : loc->datetime_fmt = datetime;
1311 1880 : free(loc->date_fmt);
1312 1880 : loc->date_fmt = date;
1313 1880 : free(loc->time_fmt);
1314 1880 : loc->time_fmt = time;
1315 1880 : break;
1316 : }
1317 : return CS_SUCCEED;
1318 : }
1319 :
1320 : CS_RETCODE
1321 1990 : cs_dt_info(CS_CONTEXT *ctx, CS_INT action, CS_LOCALE *locale, CS_INT type, CS_INT item, CS_VOID *buffer, CS_INT buflen,
1322 : CS_INT *outlen)
1323 : {
1324 : static const char func[] = "cs_dt_info";
1325 :
1326 1990 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_info(%p, %d, %p, %d, %d, %p, %d, %p)\n",
1327 : ctx, action, locale, type, item, buffer, buflen, outlen);
1328 :
1329 1990 : if (!ctx)
1330 : return CS_FAIL;
1331 :
1332 1980 : if (action == CS_SET) {
1333 1960 : switch (type) {
1334 1950 : case CS_DT_CONVFMT:
1335 1950 : if (buflen < 0) {
1336 20 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1337 20 : return CS_FAIL;
1338 : }
1339 1930 : if (!locale && buffer) {
1340 1880 : CS_INT convfmt = *(CS_INT *) buffer;
1341 1880 : TDSLOCALE *loc = ctx->tds_ctx->locale;
1342 :
1343 1880 : return _cs_set_locale_convfmt(ctx, loc, convfmt);
1344 : }
1345 : break;
1346 10 : default:
1347 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1348 10 : return CS_FAIL;
1349 : break;
1350 : }
1351 20 : } else if (action == CS_GET) {
1352 : switch (type) {
1353 10 : default:
1354 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1355 10 : return CS_FAIL;
1356 : break;
1357 : }
1358 : } else {
1359 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, action", action);
1360 10 : return CS_FAIL;
1361 : }
1362 : return CS_SUCCEED;
1363 : }
1364 :
1365 : CS_RETCODE
1366 0 : cs_strbuild(CS_CONTEXT * ctx, CS_CHAR * buffer, CS_INT buflen, CS_INT * resultlen, CS_CHAR * text, CS_INT textlen,
1367 : CS_CHAR * formats, CS_INT formatlen, ...)
1368 : {
1369 : va_list ap;
1370 : TDSRET rc;
1371 :
1372 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strbuild(%p, %p, %d, %p, %p, %d, %p, %d)\n",
1373 : ctx, buffer, buflen, resultlen, text, textlen, formats, formatlen);
1374 :
1375 0 : va_start(ap, formatlen);
1376 0 : rc = tds_vstrbuild(buffer, buflen, resultlen, text, textlen, formats, formatlen, ap);
1377 0 : va_end(ap);
1378 :
1379 0 : return TDS_SUCCEED(rc) ? CS_SUCCEED : CS_FAIL;
1380 : }
1381 :
1382 : CS_RETCODE
1383 0 : cs_calc(CS_CONTEXT * ctx, CS_INT op, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_VOID * dest)
1384 : {
1385 :
1386 0 : tdsdump_log(TDS_DBG_FUNC, "cs_calc(%p, %d, %d, %p, %p, %p)\n", ctx, op, datatype, var1, var2, dest);
1387 :
1388 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_calc()\n");
1389 0 : return CS_FAIL;
1390 : }
1391 :
1392 : CS_RETCODE
1393 0 : cs_cmp(CS_CONTEXT * ctx, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_INT * result)
1394 : {
1395 :
1396 0 : tdsdump_log(TDS_DBG_FUNC, "cs_cmp(%p, %d, %p, %p, %p)\n", ctx, datatype, var1, var2, result);
1397 :
1398 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_cmp()\n");
1399 0 : return CS_FAIL;
1400 : }
1401 :
1402 : CS_RETCODE
1403 0 : cs_conv_mult(CS_CONTEXT * ctx, CS_LOCALE * srcloc, CS_LOCALE * destloc, CS_INT * conv_multiplier)
1404 : {
1405 :
1406 0 : tdsdump_log(TDS_DBG_FUNC, "cs_conv_mult(%p, %p, %p, %p)\n", ctx, srcloc, destloc, conv_multiplier);
1407 :
1408 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_conv_mult()\n");
1409 0 : return CS_FAIL;
1410 : }
1411 :
1412 : CS_RETCODE
1413 70 : cs_diag(CS_CONTEXT * ctx, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
1414 : {
1415 70 : tdsdump_log(TDS_DBG_FUNC, "cs_diag(%p, %d, %d, %d, %p)\n", ctx, operation, type, idx, buffer);
1416 :
1417 70 : switch (operation) {
1418 :
1419 10 : case CS_INIT:
1420 10 : if ( ctx->cs_errhandletype == _CS_ERRHAND_CB) {
1421 : /* contrary to the manual page you don't seem to */
1422 : /* be able to turn on inline message handling */
1423 : /* using cs_diag, once a callback is installed! */
1424 : return CS_FAIL;
1425 : }
1426 10 : ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
1427 10 : ctx->cs_diag_msglimit = CS_NO_LIMIT;
1428 10 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) cs_diag_storemsg;
1429 10 : break;
1430 0 : case CS_MSGLIMIT:
1431 0 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1432 : return CS_FAIL;
1433 : }
1434 0 : ctx->cs_diag_msglimit = *(CS_INT *)buffer;
1435 0 : break;
1436 10 : case CS_CLEAR:
1437 10 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1438 : return CS_FAIL;
1439 : }
1440 10 : return (cs_diag_clearmsg(ctx, type));
1441 :
1442 : break;
1443 30 : case CS_GET:
1444 30 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1445 : return CS_FAIL;
1446 : }
1447 30 : if (buffer == NULL)
1448 : return CS_FAIL;
1449 :
1450 30 : if (idx == 0 || (ctx->cs_diag_msglimit != CS_NO_LIMIT && idx > ctx->cs_diag_msglimit) )
1451 : return CS_FAIL;
1452 :
1453 30 : return (cs_diag_getmsg(ctx, idx, (CS_CLIENTMSG *)buffer));
1454 :
1455 : break;
1456 20 : case CS_STATUS:
1457 20 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1458 : return CS_FAIL;
1459 : }
1460 20 : if (buffer == NULL)
1461 : return CS_FAIL;
1462 :
1463 20 : return (cs_diag_countmsg(ctx, (CS_INT *)buffer));
1464 : break;
1465 : }
1466 : return CS_SUCCEED;
1467 :
1468 : }
1469 :
1470 : CS_RETCODE
1471 0 : cs_manage_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_CHAR * srcname, CS_INT srcnamelen, CS_INT desttype,
1472 : CS_CHAR * destname, CS_INT destnamelen, CS_INT * conv_multiplier, CS_CONV_FUNC * func)
1473 : {
1474 :
1475 0 : tdsdump_log(TDS_DBG_FUNC, "cs_manage_convert(%p, %d, %d, %p, %d, %d, %p, %d, %p, %p)\n",
1476 : ctx, action, srctype, srcname, srcnamelen, desttype, destname, destnamelen, conv_multiplier, func);
1477 :
1478 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_manage_convert()\n");
1479 0 : return CS_FAIL;
1480 : }
1481 :
1482 : CS_RETCODE
1483 0 : cs_objects(CS_CONTEXT * ctx, CS_INT action, CS_OBJNAME * objname, CS_OBJDATA * objdata)
1484 : {
1485 :
1486 0 : tdsdump_log(TDS_DBG_FUNC, "cs_objects(%p, %d, %p, %p)\n", ctx, action, objname, objdata);
1487 :
1488 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_objects()\n");
1489 0 : return CS_FAIL;
1490 : }
1491 :
1492 : CS_RETCODE
1493 0 : cs_set_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_INT desttype, CS_CONV_FUNC * func)
1494 : {
1495 :
1496 0 : tdsdump_log(TDS_DBG_FUNC, "cs_set_convert(%p, %d, %d, %d, %p)\n", ctx, action, srctype, desttype, func);
1497 :
1498 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_set_convert()\n");
1499 0 : return CS_FAIL;
1500 : }
1501 :
1502 : CS_RETCODE
1503 0 : cs_setnull(CS_CONTEXT * ctx, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT buflen)
1504 : {
1505 :
1506 0 : tdsdump_log(TDS_DBG_FUNC, "cs_setnull(%p, %p, %p, %d)\n", ctx, datafmt, buffer, buflen);
1507 :
1508 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_setnull()\n");
1509 0 : return CS_FAIL;
1510 : }
1511 :
1512 : CS_RETCODE
1513 0 : cs_strcmp(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_INT type, CS_CHAR * str1, CS_INT len1, CS_CHAR * str2, CS_INT len2,
1514 : CS_INT * result)
1515 : {
1516 :
1517 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strcmp(%p, %p, %d, %p, %d, %p, %d, %p)\n",
1518 : ctx, locale, type, str1, len1, str2, len2, result);
1519 :
1520 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_strcmp()\n");
1521 0 : return CS_FAIL;
1522 : }
1523 :
1524 : CS_RETCODE
1525 0 : cs_time(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen, CS_DATEREC * daterec)
1526 : {
1527 :
1528 0 : tdsdump_log(TDS_DBG_FUNC, "cs_time(%p, %p, %p, %d, %p, %p)\n", ctx, locale, buffer, buflen, outlen, daterec);
1529 :
1530 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_time()\n");
1531 0 : return CS_FAIL;
1532 : }
1533 :
1534 : CS_RETCODE
1535 935300 : cs_will_convert(CS_CONTEXT * ctx, CS_INT srctype, CS_INT desttype, CS_BOOL * result)
1536 : {
1537 :
1538 935300 : tdsdump_log(TDS_DBG_FUNC, "cs_will_convert(%p, %d, %d, %p)\n", ctx, srctype, desttype, result);
1539 :
1540 935300 : srctype = _ct_get_server_type(NULL, srctype);
1541 935300 : desttype = _ct_get_server_type(NULL, desttype);
1542 935300 : *result = (tds_willconvert(srctype, desttype) ? CS_TRUE : CS_FALSE);
1543 935300 : return CS_SUCCEED;
1544 : }
1545 :
1546 : static CS_INT
1547 20 : cs_diag_storemsg(CS_CONTEXT *context, CS_CLIENTMSG *message)
1548 : {
1549 : struct cs_diag_msg **curptr;
1550 20 : CS_INT msg_count = 0;
1551 :
1552 20 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_storemsg(%p, %p)\n", context, message);
1553 :
1554 20 : curptr = &(context->msgstore);
1555 :
1556 : /* if we already have a list of messages, */
1557 : /* go to the end of the list... */
1558 :
1559 50 : while (*curptr != NULL) {
1560 10 : msg_count++;
1561 10 : curptr = &((*curptr)->next);
1562 : }
1563 :
1564 : /* messages over and above the agreed limit */
1565 : /* are simply discarded... */
1566 :
1567 20 : if (context->cs_diag_msglimit != CS_NO_LIMIT &&
1568 : msg_count >= context->cs_diag_msglimit) {
1569 : return CS_FAIL;
1570 : }
1571 :
1572 20 : *curptr = tds_new(struct cs_diag_msg, 1);
1573 20 : if (*curptr == NULL) {
1574 : return CS_FAIL;
1575 : } else {
1576 20 : (*curptr)->next = NULL;
1577 20 : (*curptr)->msg = tds_new(CS_CLIENTMSG, 1);
1578 20 : if ((*curptr)->msg == NULL) {
1579 : return CS_FAIL;
1580 : } else {
1581 20 : memcpy((*curptr)->msg, message, sizeof(CS_CLIENTMSG));
1582 : }
1583 : }
1584 :
1585 20 : return CS_SUCCEED;
1586 : }
1587 :
1588 : static CS_INT
1589 30 : cs_diag_getmsg(CS_CONTEXT *context, CS_INT idx, CS_CLIENTMSG *message)
1590 : {
1591 : struct cs_diag_msg *curptr;
1592 30 : CS_INT msg_count = 0, msg_found = 0;
1593 :
1594 30 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_getmsg(%p, %d, %p)\n", context, idx, message);
1595 :
1596 30 : curptr = context->msgstore;
1597 :
1598 : /* if we already have a list of messages, */
1599 : /* go to the end of the list... */
1600 :
1601 90 : while (curptr != NULL) {
1602 50 : msg_count++;
1603 50 : if (msg_count == idx) {
1604 : msg_found++;
1605 : break;
1606 : }
1607 30 : curptr = curptr->next;
1608 : }
1609 30 : if (msg_found) {
1610 20 : memcpy(message, curptr->msg, sizeof(CS_CLIENTMSG));
1611 20 : return CS_SUCCEED;
1612 : } else {
1613 : return CS_NOMSG;
1614 : }
1615 : }
1616 :
1617 : static CS_INT
1618 10 : cs_diag_clearmsg(CS_CONTEXT *context, CS_INT type)
1619 : {
1620 : struct cs_diag_msg *curptr, *freeptr;
1621 :
1622 10 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_clearmsg(%p, %d)\n", context, type);
1623 :
1624 10 : curptr = context->msgstore;
1625 10 : context->msgstore = NULL;
1626 :
1627 40 : while (curptr != NULL ) {
1628 20 : freeptr = curptr;
1629 20 : curptr = freeptr->next;
1630 20 : free(freeptr->msg);
1631 20 : free(freeptr);
1632 : }
1633 10 : return CS_SUCCEED;
1634 : }
1635 :
1636 : static CS_INT
1637 20 : cs_diag_countmsg(CS_CONTEXT *context, CS_INT *count)
1638 : {
1639 : struct cs_diag_msg *curptr;
1640 20 : CS_INT msg_count = 0;
1641 :
1642 20 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_countmsg(%p, %p)\n", context, count);
1643 :
1644 20 : curptr = context->msgstore;
1645 :
1646 60 : while (curptr != NULL) {
1647 20 : msg_count++;
1648 20 : curptr = curptr->next;
1649 : }
1650 20 : *count = msg_count;
1651 20 : return CS_SUCCEED;
1652 : }
1653 :
1654 : /**
1655 : * Try to convert to a type we can handle.
1656 : * Used before calling _cs_convert to handle TDS types that do not have a
1657 : * corresponding CS_xxx_TYPE.
1658 : * @param ctx Library context, used for conversion, can be NULL.
1659 : * @param curcol Column with data to convert.
1660 : * @param convert_buffer Buffer to store conversion, can be NULL.
1661 : * @param p_src Pointer to pointer to source data, can be NULL.
1662 : * @return Converted type or CS_ILLEGAL_TYPE.
1663 : */
1664 : int
1665 6785 : _cs_convert_not_client(CS_CONTEXT *ctx, const TDSCOLUMN *curcol, CONV_RESULT *convert_buffer, unsigned char **p_src)
1666 : {
1667 : int ct_type;
1668 6785 : TDS_SERVER_TYPE desttype, srctype = curcol->column_type;
1669 :
1670 6785 : if (srctype == SYBVARIANT)
1671 554 : srctype = ((const TDSVARIANT *) curcol->column_data)->type;
1672 :
1673 6785 : switch (srctype) {
1674 : case SYBMSDATE:
1675 : desttype = SYBDATE;
1676 : ct_type = CS_DATE_TYPE;
1677 : break;
1678 40 : case SYBMSTIME:
1679 40 : desttype = SYB5BIGTIME;
1680 40 : ct_type = CS_BIGTIME_TYPE;
1681 40 : break;
1682 80 : case SYBMSDATETIME2:
1683 : case SYBMSDATETIMEOFFSET:
1684 80 : desttype = SYB5BIGDATETIME;
1685 80 : ct_type = CS_BIGDATETIME_TYPE;
1686 80 : break;
1687 : default:
1688 : return CS_ILLEGAL_TYPE;
1689 : }
1690 :
1691 160 : if (convert_buffer) {
1692 160 : int len = tds_convert(ctx->tds_ctx, srctype, *p_src,
1693 80 : curcol->column_cur_size, desttype, convert_buffer);
1694 80 : if (len < 0)
1695 : return CS_ILLEGAL_TYPE; /* TODO _csclient_msg ?? */
1696 80 : *p_src = (unsigned char *) convert_buffer;
1697 : }
1698 : return ct_type;
1699 : }
|