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 200 : _cs_get_layer(int layer)
88 : {
89 200 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_layer(%d)\n", layer);
90 :
91 200 : 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 200 : _cs_get_origin(int origin)
103 : {
104 200 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_origin(%d)\n", origin);
105 :
106 200 : 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 8 : case 4:
114 8 : 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 200 : _cs_get_user_api_layer_error(int error)
127 : {
128 200 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_user_api_layer_error(%d)\n", error);
129 :
130 200 : 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 48 : case 4:
138 48 : return "The parameter %1! cannot be NULL.";
139 : break;
140 96 : case 6:
141 96 : return "An illegal value of %1! was given for parameter %2!.";
142 : break;
143 32 : case 16:
144 32 : return "Conversion between %1! and %2! datatypes is not supported.";
145 : break;
146 8 : case 18:
147 8 : return "An illegal value of %1! was placed in the %2! field of the CS_DATAFMT structure.";
148 : break;
149 8 : case 20:
150 8 : 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 200 : _cs_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
166 : {
167 : char *m;
168 :
169 200 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_msgstr(%s, %d, %d, %d, %d)\n", funcname, layer, origin, severity, number);
170 :
171 200 : 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 200 : return m;
177 : }
178 :
179 : static void
180 336 : _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 336 : tdsdump_log(TDS_DBG_FUNC, "_csclient_msg(%p, %s, %d, %d, %d, %d, %s)\n", ctx, funcname, layer, origin, severity, number, fmt);
187 :
188 336 : va_start(ap, fmt);
189 :
190 336 : if (ctx->cslibmsg_cb) {
191 200 : cm.severity = severity;
192 400 : cm.msgnumber = (((layer << 24) & 0xFF000000)
193 200 : | ((origin << 16) & 0x00FF0000)
194 200 : | ((severity << 8) & 0x0000FF00)
195 200 : | ((number) & 0x000000FF));
196 200 : msgstr = _cs_get_msgstr(funcname, layer, origin, severity, number);
197 200 : tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
198 200 : cm.msgstring[cm.msgstringlen] = '\0';
199 200 : free(msgstr);
200 200 : cm.osnumber = 0;
201 200 : cm.osstring[0] = '\0';
202 200 : cm.osstringlen = 0;
203 200 : cm.status = 0;
204 : /* cm.sqlstate */
205 200 : cm.sqlstatelen = 0;
206 200 : ctx->cslibmsg_cb(ctx, &cm);
207 : }
208 :
209 336 : va_end(ap);
210 336 : }
211 :
212 : /**
213 : * Allocate new CS_LOCALE and initialize it
214 : * returns NULL on out of memory errors
215 : */
216 : static CS_LOCALE *
217 8 : _cs_locale_alloc(void)
218 : {
219 8 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_alloc()\n");
220 :
221 8 : return tds_new0(CS_LOCALE, 1);
222 : }
223 :
224 : static void
225 8 : _cs_locale_free_contents(CS_LOCALE *locale)
226 : {
227 8 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_free_contents(%p)\n", locale);
228 :
229 : /* free strings */
230 8 : free(locale->language);
231 8 : locale->language = NULL;
232 8 : free(locale->charset);
233 8 : locale->charset = NULL;
234 8 : free(locale->time);
235 8 : locale->time = NULL;
236 8 : free(locale->collate);
237 8 : locale->collate = NULL;
238 8 : }
239 :
240 : void
241 8 : _cs_locale_free(CS_LOCALE *locale)
242 : {
243 8 : tdsdump_log(TDS_DBG_FUNC, "_cs_locale_free(%p)\n", locale);
244 :
245 : /* free contents */
246 8 : _cs_locale_free_contents(locale);
247 :
248 : /* free the data structure */
249 8 : free(locale);
250 8 : }
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 1112 : cs_ctx_alloc(CS_INT version, CS_CONTEXT ** out_ctx)
335 : {
336 : TDSCONTEXT *tds_ctx;
337 : CS_CONTEXT *ctx;
338 :
339 1112 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_alloc(%d, %p)\n", version, out_ctx);
340 :
341 1112 : ctx = tds_new0(CS_CONTEXT, 1);
342 1112 : if (!ctx)
343 : return CS_FAIL;
344 1112 : ctx->use_large_identifiers = _ct_is_large_identifiers_version(version);
345 1112 : tds_ctx = tds_alloc_context(ctx);
346 1112 : if (!tds_ctx) {
347 0 : free(ctx);
348 0 : return CS_FAIL;
349 : }
350 1112 : ctx->tds_ctx = tds_ctx;
351 1112 : 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 1112 : ctx->login_timeout = -1;
357 1112 : ctx->query_timeout = -1;
358 :
359 1112 : *out_ctx = ctx;
360 1112 : 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 1112 : cs_ctx_drop(CS_CONTEXT * ctx)
383 : {
384 1112 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_drop(%p)\n", ctx);
385 :
386 1112 : if (ctx) {
387 1112 : _ct_diag_clearmsg(ctx, CS_ALLMSG_TYPE);
388 1112 : free(ctx->userdata);
389 1112 : if (ctx->tds_ctx)
390 1112 : tds_free_context(ctx->tds_ctx);
391 1112 : free(ctx);
392 : }
393 1112 : return CS_SUCCEED;
394 : }
395 :
396 : CS_RETCODE
397 192 : 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 192 : tdsdump_log(TDS_DBG_FUNC, "cs_config(%p, %d, %d, %p, %d, %p)\n", ctx, action, property, buffer, buflen, outlen);
402 :
403 192 : if (action == CS_GET) {
404 64 : if (buffer == NULL) {
405 : return CS_SUCCEED;
406 : }
407 64 : switch (property) {
408 0 : case CS_MESSAGE_CB:
409 0 : *(CS_CSLIBMSG_FUNC*) buffer = ctx->cslibmsg_cb;
410 0 : return CS_SUCCEED;
411 64 : case CS_USERDATA:
412 64 : if (buflen < 0) {
413 8 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
414 8 : return CS_FAIL;
415 : }
416 :
417 56 : maxcp = ctx->userdata_len;
418 56 : if (outlen)
419 32 : *outlen = maxcp;
420 :
421 56 : if (buflen < maxcp) {
422 8 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 2, "%d", buflen);
423 8 : return CS_FAIL;
424 : }
425 48 : memcpy(buffer, ctx->userdata, maxcp);
426 48 : 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 128 : if (action == CS_SET) {
438 120 : switch (property) {
439 24 : case CS_MESSAGE_CB:
440 24 : if ( ctx->cs_errhandletype == _CS_ERRHAND_INLINE) {
441 0 : cs_diag_clearmsg(ctx, CS_UNUSED);
442 : }
443 24 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) buffer;
444 24 : ctx->cs_errhandletype = _CS_ERRHAND_CB;
445 24 : return CS_SUCCEED;
446 88 : case CS_USERDATA:
447 88 : if (buflen < 0 && buflen != CS_NULLTERM) {
448 48 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
449 48 : return CS_FAIL;
450 : }
451 :
452 40 : maxcp = _ct_get_string_length(buffer, buflen);
453 40 : free(ctx->userdata);
454 40 : ctx->userdata = (void *) malloc(maxcp);
455 40 : if ( ctx->userdata == NULL) {
456 : return CS_FAIL;
457 : }
458 40 : ctx->userdata_len = maxcp;
459 :
460 40 : if (buffer) {
461 40 : memcpy(ctx->userdata, buffer, maxcp);
462 : } else {
463 : return CS_FAIL;
464 : }
465 40 : return CS_SUCCEED;
466 :
467 8 : default:
468 : case CS_EXTRA_INF:
469 : case CS_LOC_PROP:
470 : case CS_VERSION:
471 8 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
472 8 : return CS_FAIL;
473 : break;
474 : }
475 : }
476 8 : 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 8 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", action, "action");
503 8 : return CS_FAIL;
504 : }
505 :
506 : CS_RETCODE
507 4933 : _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)
509 : {
510 : TDS_SERVER_TYPE src_type, desttype;
511 : int src_len, destlen, len;
512 : CONV_RESULT cres;
513 : unsigned char *dest;
514 : CS_RETCODE ret;
515 : CS_INT dummy, datatype;
516 4933 : CS_VARCHAR *destvc = NULL;
517 :
518 4933 : tdsdump_log(TDS_DBG_FUNC, "cs_convert(%p, %p, %p, %p, %p, %p)\n", ctx, srcfmt, srcdata, destfmt, destdata, resultlen);
519 :
520 : /* If destfmt is NULL we have a problem */
521 4933 : if (destfmt == NULL) {
522 16 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destfmt");
523 16 : return CS_FAIL;
524 : }
525 :
526 : /* If destination is NULL we have a problem */
527 4917 : if (destdata == NULL) {
528 8 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destdata");
529 8 : return CS_FAIL;
530 :
531 : }
532 :
533 4909 : if (resultlen == NULL)
534 32 : resultlen = &dummy;
535 :
536 : /* If source is indicated to be NULL, set dest to low values */
537 4909 : if (srcdata == NULL) {
538 : /* TODO: implement cs_setnull */
539 0 : tdsdump_log(TDS_DBG_FUNC, "srcdata is null\n");
540 0 : memset(destdata, '\0', destfmt->maxlength);
541 0 : *resultlen = 0;
542 0 : return CS_SUCCEED;
543 : }
544 :
545 4909 : datatype = srcfmt->datatype;
546 4909 : src_type = _ct_get_server_type(NULL, datatype);
547 4909 : if (src_type == TDS_INVALID_TYPE) {
548 8 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", srcfmt->datatype, destfmt->datatype);
549 8 : return CS_FAIL;
550 : }
551 4901 : src_len = srcfmt->maxlength;
552 4901 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
553 0 : CS_VARCHAR *vc = (CS_VARCHAR *) srcdata;
554 0 : src_len = vc->len;
555 0 : srcdata = vc->str;
556 : }
557 :
558 4901 : datatype = destfmt->datatype;
559 4901 : desttype = _ct_get_server_type(NULL, datatype);
560 4901 : if (desttype == TDS_INVALID_TYPE) {
561 8 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", srcfmt->datatype, destfmt->datatype);
562 8 : return CS_FAIL;
563 : }
564 4893 : destlen = destfmt->maxlength;
565 4893 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
566 24 : destvc = (CS_VARCHAR *) destdata;
567 24 : destlen = sizeof(destvc->str);
568 24 : destdata = destvc->str;
569 4869 : } else if (is_numeric_type(desttype)) {
570 168 : destlen = sizeof(TDS_NUMERIC);
571 : }
572 :
573 4893 : tdsdump_log(TDS_DBG_FUNC, "converting type %d (%d bytes) to type = %d (%d bytes)\n",
574 : src_type, src_len, desttype, destlen);
575 :
576 4893 : if (!is_fixed_type(desttype) && destlen < 0) {
577 8 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", destlen, "maxlength");
578 8 : return CS_FAIL;
579 : }
580 :
581 4885 : dest = (unsigned char *) destdata;
582 :
583 : /* many times we are asked to convert a data type to itself */
584 :
585 4885 : if (src_type == desttype) {
586 1884 : int minlen = src_len < destlen? src_len : destlen;
587 :
588 1884 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() srctype == desttype\n");
589 1884 : switch (desttype) {
590 :
591 32 : case SYBLONGBINARY:
592 : case SYBBINARY:
593 : case SYBVARBINARY:
594 : case SYBIMAGE:
595 32 : memcpy(dest, srcdata, minlen);
596 32 : *resultlen = minlen;
597 :
598 32 : if (src_len > destlen) {
599 16 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
600 16 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
601 16 : ret = CS_FAIL;
602 : } else {
603 16 : switch (destfmt->format) {
604 0 : case CS_FMT_PADNULL:
605 0 : memset(dest + src_len, '\0', destlen - src_len);
606 0 : *resultlen = destlen;
607 : /* fall through */
608 : case CS_FMT_UNUSED:
609 : ret = CS_SUCCEED;
610 : break;
611 : default:
612 : ret = CS_FAIL;
613 : break;
614 : }
615 : }
616 32 : if (destvc) {
617 0 : destvc->len = minlen;
618 0 : *resultlen = sizeof(*destvc);
619 : }
620 : break;
621 :
622 1574 : case SYBCHAR:
623 : case SYBVARCHAR:
624 : case SYBTEXT:
625 1574 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() desttype = character\n");
626 :
627 1574 : memcpy(dest, srcdata, minlen);
628 1574 : *resultlen = minlen;
629 :
630 1574 : if (src_len > destlen) {
631 8 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
632 8 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
633 8 : ret = CS_FAIL;
634 : } else {
635 1566 : switch (destfmt->format) {
636 1312 : case CS_FMT_NULLTERM:
637 1312 : if (src_len == destlen) {
638 0 : *resultlen = src_len;
639 0 : tdsdump_log(TDS_DBG_FUNC, "error: no room for null terminator\n");
640 : ret = CS_FAIL;
641 : } else {
642 1312 : dest[src_len] = '\0';
643 1312 : *resultlen = src_len + 1;
644 1312 : ret = CS_SUCCEED;
645 : }
646 : break;
647 :
648 0 : case CS_FMT_PADBLANK:
649 0 : memset(dest + src_len, ' ', destlen - src_len);
650 0 : *resultlen = destlen;
651 0 : ret = CS_SUCCEED;
652 0 : break;
653 0 : case CS_FMT_PADNULL:
654 0 : memset(dest + src_len, '\0', destlen - src_len);
655 0 : *resultlen = destlen;
656 0 : ret = CS_SUCCEED;
657 0 : break;
658 : case CS_FMT_UNUSED:
659 : ret = CS_SUCCEED;
660 : break;
661 0 : default:
662 0 : tdsdump_log(TDS_DBG_FUNC, "no destination format specified!\n");
663 : ret = CS_FAIL;
664 : break;
665 : }
666 : }
667 1574 : if (destvc) {
668 0 : destvc->len = minlen;
669 0 : *resultlen = sizeof(*destvc);
670 : }
671 : break;
672 270 : case SYBINT1:
673 : case SYBUINT1:
674 : case SYBINT2:
675 : case SYBUINT2:
676 : case SYBINT4:
677 : case SYBUINT4:
678 : case SYBINT8:
679 : case SYBUINT8:
680 : case SYBFLT8:
681 : case SYBREAL:
682 : case SYBBIT:
683 : case SYBMONEY:
684 : case SYBMONEY4:
685 : case SYBDATETIME:
686 : case SYBDATETIME4:
687 : case SYBTIME:
688 : case SYBDATE:
689 : case SYB5BIGDATETIME:
690 : case SYB5BIGTIME:
691 270 : *resultlen = tds_get_size_by_type(src_type);
692 270 : if (*resultlen > 0)
693 270 : memcpy(dest, srcdata, *resultlen);
694 : ret = CS_SUCCEED;
695 : break;
696 :
697 8 : case SYBNUMERIC:
698 : case SYBDECIMAL:
699 8 : src_len = tds_numeric_bytes_per_prec[((TDS_NUMERIC *) srcdata)->precision] + 2;
700 8 : case SYBBITN:
701 : case SYBUNIQUE:
702 8 : memcpy(dest, srcdata, minlen);
703 8 : *resultlen = minlen;
704 :
705 8 : if (src_len > destlen) {
706 0 : tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n");
707 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
708 0 : ret = CS_FAIL;
709 : } else {
710 : ret = CS_SUCCEED;
711 : }
712 : break;
713 :
714 0 : default:
715 0 : tdsdump_log(TDS_DBG_FUNC, "error: unrecognized type\n");
716 : ret = CS_FAIL;
717 : break;
718 : }
719 :
720 1884 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret));
721 : return ret;
722 :
723 : }
724 :
725 : assert(src_type != desttype);
726 :
727 : /* set the output precision/scale for conversions to numeric type */
728 3001 : if (is_numeric_type(desttype)) {
729 160 : cres.n.precision = destfmt->precision;
730 160 : cres.n.scale = destfmt->scale;
731 160 : if (destfmt->precision == CS_SRC_VALUE)
732 0 : cres.n.precision = srcfmt->precision;
733 160 : if (destfmt->scale == CS_SRC_VALUE)
734 0 : cres.n.scale = srcfmt->scale;
735 : }
736 :
737 3001 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() calling tds_convert\n");
738 3001 : len = tds_convert(ctx->tds_ctx, src_type, srcdata, src_len, desttype, &cres);
739 :
740 3001 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() tds_convert returned %d\n", len);
741 :
742 3001 : switch (len) {
743 24 : case TDS_CONVERT_NOAVAIL:
744 24 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", src_type, desttype);
745 24 : return CS_FAIL;
746 : break;
747 32 : case TDS_CONVERT_SYNTAX:
748 32 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 24, "");
749 32 : return CS_FAIL;
750 : break;
751 0 : case TDS_CONVERT_NOMEM:
752 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 3, "");
753 0 : return CS_FAIL;
754 : break;
755 48 : case TDS_CONVERT_OVERFLOW:
756 48 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 20, "");
757 48 : return CS_FAIL;
758 : break;
759 : case TDS_CONVERT_FAIL:
760 : return CS_FAIL;
761 : break;
762 2897 : default:
763 2897 : if (len < 0) {
764 : return CS_FAIL;
765 : }
766 : break;
767 : }
768 :
769 2897 : switch (desttype) {
770 80 : case SYBBINARY:
771 : case SYBVARBINARY:
772 : case SYBIMAGE:
773 80 : ret = CS_SUCCEED;
774 80 : if (len > destlen) {
775 24 : tdsdump_log(TDS_DBG_FUNC, "error_handler: Data-conversion resulted in overflow\n");
776 24 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
777 24 : ret = CS_FAIL;
778 24 : len = destlen;
779 : }
780 80 : memcpy(dest, cres.ib, len);
781 80 : free(cres.ib);
782 80 : *resultlen = len;
783 80 : if (destvc) {
784 16 : destvc->len = len;
785 16 : *resultlen = sizeof(*destvc);
786 64 : } else if (destfmt->format == CS_FMT_PADNULL) {
787 16 : *resultlen = destlen;
788 16 : memset(dest + len, '\0', destlen - len);
789 : }
790 : break;
791 972 : case SYBBIT:
792 : case SYBBITN:
793 : /* fall trough, act same way of TINYINT */
794 : case SYBINT1:
795 : case SYBUINT1:
796 : case SYBINT2:
797 : case SYBUINT2:
798 : case SYBINT4:
799 : case SYBUINT4:
800 : case SYBINT8:
801 : case SYBUINT8:
802 : case SYBFLT8:
803 : case SYBREAL:
804 : case SYBMONEY:
805 : case SYBMONEY4:
806 : case SYBDATETIME:
807 : case SYBDATETIME4:
808 : case SYBTIME:
809 : case SYBDATE:
810 : case SYBUNIQUE:
811 : case SYB5BIGDATETIME:
812 : case SYB5BIGTIME:
813 972 : *resultlen = tds_get_size_by_type(desttype);
814 972 : memcpy(dest, &(cres.ti), *resultlen);
815 972 : ret = CS_SUCCEED;
816 972 : break;
817 160 : case SYBNUMERIC:
818 : case SYBDECIMAL:
819 160 : src_len = tds_numeric_bytes_per_prec[cres.n.precision] + 2;
820 160 : memcpy(dest, &(cres.n), src_len);
821 160 : *resultlen = src_len;
822 160 : ret = CS_SUCCEED;
823 160 : break;
824 1685 : case SYBCHAR:
825 : case SYBVARCHAR:
826 : case SYBTEXT:
827 1685 : ret = CS_SUCCEED;
828 1685 : if (len > destlen) {
829 8 : tdsdump_log(TDS_DBG_FUNC, "Data-conversion resulted in overflow\n");
830 8 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
831 8 : len = destlen;
832 8 : ret = CS_FAIL;
833 : }
834 1685 : switch (destfmt->format) {
835 :
836 1633 : case CS_FMT_NULLTERM:
837 1633 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_NULLTERM\n");
838 1633 : if (len == destlen) {
839 0 : tdsdump_log(TDS_DBG_FUNC, "not enough room for data + a null terminator - error\n");
840 : ret = CS_FAIL; /* not enough room for data + a null terminator - error */
841 : } else {
842 1633 : memcpy(dest, cres.c, len);
843 1633 : dest[len] = 0;
844 1633 : *resultlen = len + 1;
845 : }
846 : break;
847 :
848 0 : case CS_FMT_PADBLANK:
849 0 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADBLANK\n");
850 : /* strcpy here can lead to a small buffer overflow */
851 0 : memcpy(dest, cres.c, len);
852 0 : memset(dest + len, ' ', destlen - len);
853 0 : *resultlen = destlen;
854 0 : break;
855 :
856 0 : case CS_FMT_PADNULL:
857 0 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADNULL\n");
858 : /* strcpy here can lead to a small buffer overflow */
859 0 : memcpy(dest, cres.c, len);
860 0 : memset(dest + len, '\0', destlen - len);
861 0 : *resultlen = destlen;
862 0 : break;
863 52 : case CS_FMT_UNUSED:
864 52 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_UNUSED\n");
865 52 : memcpy(dest, cres.c, len);
866 52 : *resultlen = len;
867 52 : break;
868 : default:
869 : ret = CS_FAIL;
870 : break;
871 : }
872 1685 : if (destvc) {
873 8 : destvc->len = len;
874 8 : *resultlen = sizeof(*destvc);
875 : }
876 1685 : free(cres.c);
877 1685 : break;
878 : default:
879 : ret = CS_FAIL;
880 : break;
881 : }
882 2897 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret));
883 : return (ret);
884 : }
885 :
886 : CS_RETCODE
887 592 : cs_convert(CS_CONTEXT * ctx, CS_DATAFMT * srcfmt, CS_VOID * srcdata, CS_DATAFMT * destfmt, CS_VOID * destdata, CS_INT * resultlen)
888 : {
889 592 : return _cs_convert(ctx, _ct_datafmt_common(ctx, srcfmt), srcdata,
890 : _ct_datafmt_common(ctx, destfmt), destdata, resultlen);
891 : }
892 :
893 : CS_RETCODE
894 0 : cs_dt_crack_v2(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
895 : {
896 : TDSDATEREC dr;
897 : TDS_INT tds_type;
898 0 : bool extended = false;
899 :
900 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack_v2(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
901 :
902 0 : switch (datetype) {
903 : case CS_DATETIME_TYPE:
904 : tds_type = SYBDATETIME;
905 : break;
906 0 : case CS_DATETIME4_TYPE:
907 0 : tds_type = SYBDATETIME4;
908 0 : break;
909 0 : case CS_DATE_TYPE:
910 0 : tds_type = SYBDATE;
911 0 : break;
912 0 : case CS_TIME_TYPE:
913 0 : tds_type = SYBTIME;
914 0 : break;
915 0 : case CS_BIGDATETIME_TYPE:
916 0 : tds_type = SYB5BIGDATETIME;
917 0 : extended = true;
918 0 : break;
919 0 : case CS_BIGTIME_TYPE:
920 0 : tds_type = SYB5BIGTIME;
921 0 : extended = true;
922 0 : break;
923 : default:
924 : return CS_FAIL;
925 : }
926 0 : tds_datecrack(tds_type, dateval, &dr);
927 :
928 : /* Sybase CT-Library does not set these fields for CS_BIGTIME_TYPE */
929 0 : if (tds_type != SYB5BIGTIME) {
930 0 : daterec->dateyear = dr.year;
931 0 : daterec->datemonth = dr.month;
932 0 : daterec->datedmonth = dr.day;
933 0 : daterec->datedyear = dr.dayofyear;
934 0 : daterec->datedweek = dr.weekday;
935 : }
936 0 : daterec->datehour = dr.hour;
937 0 : daterec->dateminute = dr.minute;
938 0 : daterec->datesecond = dr.second;
939 0 : daterec->datemsecond = dr.decimicrosecond / 10000u;
940 0 : daterec->datetzone = 0;
941 0 : if (extended) {
942 0 : daterec->datesecfrac = dr.decimicrosecond / 10u;
943 0 : daterec->datesecprec = 1000000;
944 : }
945 :
946 : return CS_SUCCEED;
947 : }
948 :
949 : CS_RETCODE
950 0 : cs_dt_crack(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
951 : {
952 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
953 :
954 0 : if (datetype != CS_BIGDATETIME_TYPE && datetype != CS_BIGTIME_TYPE)
955 0 : return cs_dt_crack_v2(ctx, datetype, dateval, daterec);
956 : return CS_FAIL;
957 : }
958 :
959 : CS_RETCODE
960 24 : cs_loc_alloc(CS_CONTEXT * ctx, CS_LOCALE ** loc_pointer)
961 : {
962 : CS_LOCALE *tds_csloc;
963 :
964 24 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_alloc(%p, %p)\n", ctx, loc_pointer);
965 :
966 24 : if (!ctx)
967 : return CS_FAIL;
968 :
969 16 : if (!loc_pointer) {
970 8 : _csclient_msg(ctx, "cs_loc_alloc", 2, 1, 1, 4, "loc_pointer");
971 8 : return CS_FAIL;
972 : }
973 :
974 8 : tds_csloc = _cs_locale_alloc();
975 8 : if (!tds_csloc)
976 : return CS_FAIL;
977 :
978 8 : *loc_pointer = tds_csloc;
979 8 : return CS_SUCCEED;
980 : }
981 :
982 : CS_RETCODE
983 24 : cs_loc_drop(CS_CONTEXT * ctx, CS_LOCALE * locale)
984 : {
985 24 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_drop(%p, %p)\n", ctx, locale);
986 :
987 24 : if (!ctx)
988 : return CS_FAIL;
989 :
990 16 : if (!locale) {
991 8 : _csclient_msg(ctx, "cs_loc_drop", 2, 1, 1, 4, "locale");
992 8 : return CS_FAIL;
993 : }
994 :
995 8 : _cs_locale_free(locale);
996 8 : return CS_SUCCEED;
997 : }
998 :
999 : CS_RETCODE
1000 48 : cs_locale(CS_CONTEXT * ctx, CS_INT action, CS_LOCALE * locale, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
1001 : {
1002 48 : CS_RETCODE code = CS_FAIL;
1003 :
1004 48 : tdsdump_log(TDS_DBG_FUNC, "cs_locale(%p, %d, %p, %d, %p, %d, %p)\n", ctx, action, locale, type, buffer, buflen, outlen);
1005 :
1006 48 : if (!ctx)
1007 : return CS_FAIL;
1008 :
1009 40 : if (!locale) {
1010 8 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 4, "locale");
1011 8 : return CS_FAIL;
1012 : }
1013 :
1014 32 : if (action == CS_SET) {
1015 24 : switch (type) {
1016 0 : case CS_LC_ALL:
1017 : /* what to do here if there is locale data? */
1018 0 : if (!buffer) {
1019 0 : code = CS_SUCCEED;
1020 : }
1021 : break;
1022 :
1023 16 : case CS_SYB_CHARSET:
1024 16 : buflen = _ct_get_string_length(buffer, buflen);
1025 16 : if (buflen < 0) {
1026 8 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, buflen", buflen);
1027 8 : return CS_FAIL;
1028 : }
1029 :
1030 8 : free(locale->charset);
1031 8 : locale->charset = tds_strndup(buffer, buflen);
1032 8 : if (!locale->charset)
1033 : break;
1034 :
1035 8 : code = CS_SUCCEED;
1036 8 : break;
1037 :
1038 0 : case CS_SYB_LANG:
1039 0 : buflen = _ct_get_string_length(buffer, buflen);
1040 0 : if (buflen < 0) {
1041 0 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, buflen", buflen);
1042 0 : return CS_FAIL;
1043 : }
1044 :
1045 0 : free(locale->language);
1046 0 : locale->language = tds_strndup(buffer, buflen);
1047 0 : if (!locale->language)
1048 : break;
1049 :
1050 0 : code = CS_SUCCEED;
1051 0 : break;
1052 :
1053 0 : case CS_SYB_LANG_CHARSET:
1054 : {
1055 : int i;
1056 0 : char *b = (char *)buffer;
1057 :
1058 0 : buflen = _ct_get_string_length(buffer, buflen);
1059 0 : if (buflen < 0) {
1060 0 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, buflen", buflen);
1061 0 : return CS_FAIL;
1062 : }
1063 :
1064 : /* find '.' character */
1065 0 : for (i = 0; i < buflen; ++i) {
1066 0 : if (b[i] == '.') {
1067 : break;
1068 : }
1069 : }
1070 : /* not found */
1071 0 : if (i == buflen) {
1072 : break;
1073 : }
1074 0 : if (i) {
1075 0 : free(locale->language);
1076 0 : locale->language = tds_strndup(b, i);
1077 0 : if (!locale->language)
1078 : break;
1079 : }
1080 0 : if (i != (buflen - 1)) {
1081 0 : free(locale->charset);
1082 0 : locale->charset = tds_strndup(b + i + 1, buflen - i - 1);
1083 0 : if (!locale->charset)
1084 : break;
1085 : }
1086 : code = CS_SUCCEED;
1087 : break;
1088 : }
1089 :
1090 : /* TODO commented out until the code works end-to-end
1091 : case CS_SYB_SORTORDER:
1092 : buflen = _ct_get_string_length(buffer, buflen);
1093 : if (buflen < 0) {
1094 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, buflen", buflen);
1095 : return CS_FAIL;
1096 : }
1097 :
1098 : free(locale->collate);
1099 : locale->collate = tds_strndup(buffer, buflen);
1100 : if (!locale->collate)
1101 : break;
1102 :
1103 : code = CS_SUCCEED;
1104 : break;
1105 : */
1106 :
1107 8 : default:
1108 8 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, type", type);
1109 8 : code = CS_FAIL;
1110 8 : break;
1111 : }
1112 0 : }
1113 8 : else if (action == CS_GET)
1114 : {
1115 : int tlen;
1116 :
1117 0 : switch (type) {
1118 0 : case CS_SYB_CHARSET:
1119 0 : tlen = (locale->charset ? strlen(locale->charset) : 0) + 1;
1120 0 : if (buflen < tlen)
1121 : {
1122 0 : if (outlen)
1123 0 : *outlen = tlen;
1124 : break;
1125 : }
1126 0 : if (locale->charset)
1127 0 : strcpy((char *)buffer, locale->charset);
1128 : else
1129 0 : ((char *)buffer)[0] = '\0';
1130 : code = CS_SUCCEED;
1131 : break;
1132 :
1133 0 : case CS_SYB_LANG:
1134 0 : tlen = (locale->language ? strlen(locale->language) : 0) + 1;
1135 0 : if (buflen < tlen)
1136 : {
1137 0 : if (outlen)
1138 0 : *outlen = tlen;
1139 : break;
1140 : }
1141 0 : if (locale->language)
1142 0 : strcpy((char *)buffer, locale->language);
1143 : else
1144 0 : ((char *)buffer)[0] = '\0';
1145 : code = CS_SUCCEED;
1146 : break;
1147 :
1148 0 : case CS_SYB_LANG_CHARSET:
1149 : {
1150 : int clen;
1151 :
1152 0 : tlen = (locale->language ? strlen(locale->language) : 0) + 1;
1153 0 : clen = (locale->charset ? strlen(locale->charset) : 0) + 1;
1154 :
1155 0 : if (buflen < (tlen + clen))
1156 : {
1157 0 : if (outlen)
1158 0 : *outlen = tlen + clen;
1159 : break;
1160 : }
1161 0 : if (locale->language)
1162 0 : strcpy((char *)buffer, locale->language);
1163 : else
1164 0 : ((char *)buffer)[0] = '\0';
1165 0 : strcat((char *)buffer, ".");
1166 0 : if (locale->charset) {
1167 0 : tlen = strlen((char *)buffer);
1168 0 : strcpy((char *)buffer + tlen, locale->charset);
1169 : }
1170 : code = CS_SUCCEED;
1171 : break;
1172 : }
1173 :
1174 0 : case CS_SYB_SORTORDER:
1175 0 : tlen = (locale->collate ? strlen(locale->collate) : 0) + 1;
1176 0 : if (buflen < tlen)
1177 : {
1178 0 : if (outlen)
1179 0 : *outlen = tlen;
1180 : break;
1181 : }
1182 0 : if (locale->collate)
1183 0 : strcpy((char *)buffer, locale->collate);
1184 : else
1185 0 : ((char *)buffer)[0] = '\0';
1186 : code = CS_SUCCEED;
1187 : break;
1188 :
1189 0 : default:
1190 0 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, type", type);
1191 0 : code = CS_FAIL;
1192 0 : break;
1193 : }
1194 : } else {
1195 8 : _csclient_msg(ctx, "cs_locale", 2, 1, 1, 6, "%d, action", action);
1196 8 : code = CS_FAIL;
1197 : }
1198 : return code;
1199 : }
1200 :
1201 : CS_RETCODE
1202 0 : cs_dt_info(CS_CONTEXT * ctx, CS_INT action, CS_LOCALE * locale, CS_INT type, CS_INT item, CS_VOID * buffer, CS_INT buflen,
1203 : CS_INT * outlen)
1204 : {
1205 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_info(%p, %d, %p, %d, %d, %p, %d, %p)\n",
1206 : ctx, action, locale, type, item, buffer, buflen, outlen);
1207 :
1208 : if (action == CS_SET) {
1209 : switch (type) {
1210 : case CS_DT_CONVFMT:
1211 : break;
1212 : }
1213 : }
1214 0 : return CS_SUCCEED;
1215 : }
1216 :
1217 : CS_RETCODE
1218 0 : cs_strbuild(CS_CONTEXT * ctx, CS_CHAR * buffer, CS_INT buflen, CS_INT * resultlen, CS_CHAR * text, CS_INT textlen,
1219 : CS_CHAR * formats, CS_INT formatlen, ...)
1220 : {
1221 : va_list ap;
1222 : TDSRET rc;
1223 :
1224 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strbuild(%p, %p, %d, %p, %p, %d, %p, %d)\n",
1225 : ctx, buffer, buflen, resultlen, text, textlen, formats, formatlen);
1226 :
1227 0 : va_start(ap, formatlen);
1228 0 : rc = tds_vstrbuild(buffer, buflen, resultlen, text, textlen, formats, formatlen, ap);
1229 0 : va_end(ap);
1230 :
1231 0 : return TDS_SUCCEED(rc) ? CS_SUCCEED : CS_FAIL;
1232 : }
1233 :
1234 : CS_RETCODE
1235 0 : cs_calc(CS_CONTEXT * ctx, CS_INT op, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_VOID * dest)
1236 : {
1237 :
1238 0 : tdsdump_log(TDS_DBG_FUNC, "cs_calc(%p, %d, %d, %p, %p, %p)\n", ctx, op, datatype, var1, var2, dest);
1239 :
1240 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_calc()\n");
1241 0 : return CS_FAIL;
1242 : }
1243 :
1244 : CS_RETCODE
1245 0 : cs_cmp(CS_CONTEXT * ctx, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_INT * result)
1246 : {
1247 :
1248 0 : tdsdump_log(TDS_DBG_FUNC, "cs_cmp(%p, %d, %p, %p, %p)\n", ctx, datatype, var1, var2, result);
1249 :
1250 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_cmp()\n");
1251 0 : return CS_FAIL;
1252 : }
1253 :
1254 : CS_RETCODE
1255 0 : cs_conv_mult(CS_CONTEXT * ctx, CS_LOCALE * srcloc, CS_LOCALE * destloc, CS_INT * conv_multiplier)
1256 : {
1257 :
1258 0 : tdsdump_log(TDS_DBG_FUNC, "cs_conv_mult(%p, %p, %p, %p)\n", ctx, srcloc, destloc, conv_multiplier);
1259 :
1260 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_conv_mult()\n");
1261 0 : return CS_FAIL;
1262 : }
1263 :
1264 : CS_RETCODE
1265 56 : cs_diag(CS_CONTEXT * ctx, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
1266 : {
1267 56 : tdsdump_log(TDS_DBG_FUNC, "cs_diag(%p, %d, %d, %d, %p)\n", ctx, operation, type, idx, buffer);
1268 :
1269 56 : switch (operation) {
1270 :
1271 8 : case CS_INIT:
1272 8 : if ( ctx->cs_errhandletype == _CS_ERRHAND_CB) {
1273 : /* contrary to the manual page you don't seem to */
1274 : /* be able to turn on inline message handling */
1275 : /* using cs_diag, once a callback is installed! */
1276 : return CS_FAIL;
1277 : }
1278 8 : ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
1279 8 : ctx->cs_diag_msglimit = CS_NO_LIMIT;
1280 8 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) cs_diag_storemsg;
1281 8 : break;
1282 0 : case CS_MSGLIMIT:
1283 0 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1284 : return CS_FAIL;
1285 : }
1286 0 : ctx->cs_diag_msglimit = *(CS_INT *)buffer;
1287 0 : break;
1288 8 : case CS_CLEAR:
1289 8 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1290 : return CS_FAIL;
1291 : }
1292 8 : return (cs_diag_clearmsg(ctx, type));
1293 :
1294 : break;
1295 24 : case CS_GET:
1296 24 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1297 : return CS_FAIL;
1298 : }
1299 24 : if (buffer == NULL)
1300 : return CS_FAIL;
1301 :
1302 24 : if (idx == 0 || (ctx->cs_diag_msglimit != CS_NO_LIMIT && idx > ctx->cs_diag_msglimit) )
1303 : return CS_FAIL;
1304 :
1305 24 : return (cs_diag_getmsg(ctx, idx, (CS_CLIENTMSG *)buffer));
1306 :
1307 : break;
1308 16 : case CS_STATUS:
1309 16 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1310 : return CS_FAIL;
1311 : }
1312 16 : if (buffer == NULL)
1313 : return CS_FAIL;
1314 :
1315 16 : return (cs_diag_countmsg(ctx, (CS_INT *)buffer));
1316 : break;
1317 : }
1318 : return CS_SUCCEED;
1319 :
1320 : }
1321 :
1322 : CS_RETCODE
1323 0 : cs_manage_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_CHAR * srcname, CS_INT srcnamelen, CS_INT desttype,
1324 : CS_CHAR * destname, CS_INT destnamelen, CS_INT * conv_multiplier, CS_CONV_FUNC * func)
1325 : {
1326 :
1327 0 : tdsdump_log(TDS_DBG_FUNC, "cs_manage_convert(%p, %d, %d, %p, %d, %d, %p, %d, %p, %p)\n",
1328 : ctx, action, srctype, srcname, srcnamelen, desttype, destname, destnamelen, conv_multiplier, func);
1329 :
1330 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_manage_convert()\n");
1331 0 : return CS_FAIL;
1332 : }
1333 :
1334 : CS_RETCODE
1335 0 : cs_objects(CS_CONTEXT * ctx, CS_INT action, CS_OBJNAME * objname, CS_OBJDATA * objdata)
1336 : {
1337 :
1338 0 : tdsdump_log(TDS_DBG_FUNC, "cs_objects(%p, %d, %p, %p)\n", ctx, action, objname, objdata);
1339 :
1340 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_objects()\n");
1341 0 : return CS_FAIL;
1342 : }
1343 :
1344 : CS_RETCODE
1345 0 : cs_set_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_INT desttype, CS_CONV_FUNC * func)
1346 : {
1347 :
1348 0 : tdsdump_log(TDS_DBG_FUNC, "cs_set_convert(%p, %d, %d, %d, %p)\n", ctx, action, srctype, desttype, func);
1349 :
1350 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_set_convert()\n");
1351 0 : return CS_FAIL;
1352 : }
1353 :
1354 : CS_RETCODE
1355 0 : cs_setnull(CS_CONTEXT * ctx, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT buflen)
1356 : {
1357 :
1358 0 : tdsdump_log(TDS_DBG_FUNC, "cs_setnull(%p, %p, %p, %d)\n", ctx, datafmt, buffer, buflen);
1359 :
1360 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_setnull()\n");
1361 0 : return CS_FAIL;
1362 : }
1363 :
1364 : CS_RETCODE
1365 0 : cs_strcmp(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_INT type, CS_CHAR * str1, CS_INT len1, CS_CHAR * str2, CS_INT len2,
1366 : CS_INT * result)
1367 : {
1368 :
1369 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strcmp(%p, %p, %d, %p, %d, %p, %d, %p)\n",
1370 : ctx, locale, type, str1, len1, str2, len2, result);
1371 :
1372 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_strcmp()\n");
1373 0 : return CS_FAIL;
1374 : }
1375 :
1376 : CS_RETCODE
1377 0 : cs_time(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen, CS_DATEREC * daterec)
1378 : {
1379 :
1380 0 : tdsdump_log(TDS_DBG_FUNC, "cs_time(%p, %p, %p, %d, %p, %p)\n", ctx, locale, buffer, buflen, outlen, daterec);
1381 :
1382 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_time()\n");
1383 0 : return CS_FAIL;
1384 : }
1385 :
1386 : CS_RETCODE
1387 748240 : cs_will_convert(CS_CONTEXT * ctx, CS_INT srctype, CS_INT desttype, CS_BOOL * result)
1388 : {
1389 :
1390 748240 : tdsdump_log(TDS_DBG_FUNC, "cs_will_convert(%p, %d, %d, %p)\n", ctx, srctype, desttype, result);
1391 :
1392 748240 : srctype = _ct_get_server_type(NULL, srctype);
1393 748240 : desttype = _ct_get_server_type(NULL, desttype);
1394 748240 : *result = (tds_willconvert(srctype, desttype) ? CS_TRUE : CS_FALSE);
1395 748240 : return CS_SUCCEED;
1396 : }
1397 :
1398 : static CS_INT
1399 16 : cs_diag_storemsg(CS_CONTEXT *context, CS_CLIENTMSG *message)
1400 : {
1401 : struct cs_diag_msg **curptr;
1402 16 : CS_INT msg_count = 0;
1403 :
1404 16 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_storemsg(%p, %p)\n", context, message);
1405 :
1406 16 : curptr = &(context->msgstore);
1407 :
1408 : /* if we already have a list of messages, */
1409 : /* go to the end of the list... */
1410 :
1411 40 : while (*curptr != NULL) {
1412 8 : msg_count++;
1413 8 : curptr = &((*curptr)->next);
1414 : }
1415 :
1416 : /* messages over and above the agreed limit */
1417 : /* are simply discarded... */
1418 :
1419 16 : if (context->cs_diag_msglimit != CS_NO_LIMIT &&
1420 : msg_count >= context->cs_diag_msglimit) {
1421 : return CS_FAIL;
1422 : }
1423 :
1424 16 : *curptr = tds_new(struct cs_diag_msg, 1);
1425 16 : if (*curptr == NULL) {
1426 : return CS_FAIL;
1427 : } else {
1428 16 : (*curptr)->next = NULL;
1429 16 : (*curptr)->msg = tds_new(CS_CLIENTMSG, 1);
1430 16 : if ((*curptr)->msg == NULL) {
1431 : return CS_FAIL;
1432 : } else {
1433 16 : memcpy((*curptr)->msg, message, sizeof(CS_CLIENTMSG));
1434 : }
1435 : }
1436 :
1437 16 : return CS_SUCCEED;
1438 : }
1439 :
1440 : static CS_INT
1441 24 : cs_diag_getmsg(CS_CONTEXT *context, CS_INT idx, CS_CLIENTMSG *message)
1442 : {
1443 : struct cs_diag_msg *curptr;
1444 24 : CS_INT msg_count = 0, msg_found = 0;
1445 :
1446 24 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_getmsg(%p, %d, %p)\n", context, idx, message);
1447 :
1448 24 : curptr = context->msgstore;
1449 :
1450 : /* if we already have a list of messages, */
1451 : /* go to the end of the list... */
1452 :
1453 72 : while (curptr != NULL) {
1454 40 : msg_count++;
1455 40 : if (msg_count == idx) {
1456 : msg_found++;
1457 : break;
1458 : }
1459 24 : curptr = curptr->next;
1460 : }
1461 24 : if (msg_found) {
1462 16 : memcpy(message, curptr->msg, sizeof(CS_CLIENTMSG));
1463 16 : return CS_SUCCEED;
1464 : } else {
1465 : return CS_NOMSG;
1466 : }
1467 : }
1468 :
1469 : static CS_INT
1470 8 : cs_diag_clearmsg(CS_CONTEXT *context, CS_INT type)
1471 : {
1472 : struct cs_diag_msg *curptr, *freeptr;
1473 :
1474 8 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_clearmsg(%p, %d)\n", context, type);
1475 :
1476 8 : curptr = context->msgstore;
1477 8 : context->msgstore = NULL;
1478 :
1479 32 : while (curptr != NULL ) {
1480 16 : freeptr = curptr;
1481 16 : curptr = freeptr->next;
1482 16 : free(freeptr->msg);
1483 16 : free(freeptr);
1484 : }
1485 8 : return CS_SUCCEED;
1486 : }
1487 :
1488 : static CS_INT
1489 16 : cs_diag_countmsg(CS_CONTEXT *context, CS_INT *count)
1490 : {
1491 : struct cs_diag_msg *curptr;
1492 16 : CS_INT msg_count = 0;
1493 :
1494 16 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_countmsg(%p, %p)\n", context, count);
1495 :
1496 16 : curptr = context->msgstore;
1497 :
1498 48 : while (curptr != NULL) {
1499 16 : msg_count++;
1500 16 : curptr = curptr->next;
1501 : }
1502 16 : *count = msg_count;
1503 16 : return CS_SUCCEED;
1504 : }
1505 :
1506 : /**
1507 : * Try to convert to a type we can handle.
1508 : * Used before calling _cs_convert to handle TDS types that do not have a
1509 : * corresponding CS_xxx_TYPE.
1510 : * @param ctx Library context, used for conversion, can be NULL.
1511 : * @param curcol Column with data to convert.
1512 : * @param convert_buffer Buffer to store conversion, can be NULL.
1513 : * @param p_src Pointer to pointer to source data, can be NULL.
1514 : * @return Converted type or CS_ILLEGAL_TYPE.
1515 : */
1516 : int
1517 3205 : _cs_convert_not_client(CS_CONTEXT *ctx, const TDSCOLUMN *curcol, CONV_RESULT *convert_buffer, unsigned char **p_src)
1518 : {
1519 : int ct_type;
1520 3205 : TDS_SERVER_TYPE desttype, srctype = curcol->column_type;
1521 :
1522 3205 : if (srctype == SYBVARIANT)
1523 442 : srctype = ((const TDSVARIANT *) curcol->column_data)->type;
1524 :
1525 3205 : switch (srctype) {
1526 : case SYBMSDATE:
1527 : desttype = SYBDATE;
1528 : ct_type = CS_DATE_TYPE;
1529 : break;
1530 32 : case SYBMSTIME:
1531 32 : desttype = SYB5BIGTIME;
1532 32 : ct_type = CS_BIGTIME_TYPE;
1533 32 : break;
1534 64 : case SYBMSDATETIME2:
1535 : case SYBMSDATETIMEOFFSET:
1536 64 : desttype = SYB5BIGDATETIME;
1537 64 : ct_type = CS_BIGDATETIME_TYPE;
1538 64 : break;
1539 : default:
1540 : return CS_ILLEGAL_TYPE;
1541 : }
1542 :
1543 128 : if (convert_buffer) {
1544 128 : int len = tds_convert(ctx->tds_ctx, srctype, *p_src,
1545 64 : curcol->column_cur_size, desttype, convert_buffer);
1546 64 : if (len < 0)
1547 : return CS_ILLEGAL_TYPE; /* TODO _csclient_msg ?? */
1548 64 : *p_src = (unsigned char *) convert_buffer;
1549 : }
1550 : return ct_type;
1551 : }
|