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 630 : _cs_get_layer(int layer)
88 : {
89 630 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_layer(%d)\n", layer);
90 :
91 630 : 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 630 : _cs_get_origin(int origin)
103 : {
104 630 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_origin(%d)\n", origin);
105 :
106 630 : 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 200 : case 4:
114 200 : 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 630 : _cs_get_user_api_layer_error(int error)
127 : {
128 630 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_user_api_layer_error(%d)\n", error);
129 :
130 630 : 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 150 : case 18:
147 150 : return "An illegal value of %1! was placed in the %2! field of the CS_DATAFMT structure.";
148 : break;
149 60 : case 20:
150 60 : return "The conversion/operation resulted in overflow.";
151 : break;
152 50 : case 24:
153 50 : return "The conversion/operation was stopped due to a syntax error in the source field.";
154 : break;
155 90 : case 36:
156 90 : 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 630 : _cs_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
166 : {
167 : char *m;
168 :
169 630 : tdsdump_log(TDS_DBG_FUNC, "_cs_get_msgstr(%s, %d, %d, %d, %d)\n", funcname, layer, origin, severity, number);
170 :
171 630 : 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 630 : return m;
177 : }
178 :
179 : static void
180 640 : _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 640 : tdsdump_log(TDS_DBG_FUNC, "_csclient_msg(%p, %s, %d, %d, %d, %d, %s)\n", ctx, funcname, layer, origin, severity, number, fmt);
187 :
188 640 : va_start(ap, fmt);
189 :
190 640 : if (ctx->cslibmsg_cb) {
191 630 : cm.severity = severity;
192 1260 : cm.msgnumber = (((layer << 24) & 0xFF000000)
193 630 : | ((origin << 16) & 0x00FF0000)
194 630 : | ((severity << 8) & 0x0000FF00)
195 630 : | ((number) & 0x000000FF));
196 630 : msgstr = _cs_get_msgstr(funcname, layer, origin, severity, number);
197 630 : tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
198 630 : cm.msgstring[cm.msgstringlen] = '\0';
199 630 : free(msgstr);
200 630 : cm.osnumber = 0;
201 630 : cm.osstring[0] = '\0';
202 630 : cm.osstringlen = 0;
203 630 : cm.status = 0;
204 : /* cm.sqlstate */
205 630 : cm.sqlstatelen = 0;
206 630 : ctx->cslibmsg_cb(ctx, &cm);
207 : }
208 :
209 640 : va_end(ap);
210 640 : }
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 1440 : cs_ctx_alloc(CS_INT version, CS_CONTEXT ** out_ctx)
335 : {
336 : TDSCONTEXT *tds_ctx;
337 : CS_CONTEXT *ctx;
338 :
339 1440 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_alloc(%d, %p)\n", version, out_ctx);
340 :
341 1440 : ctx = tds_new0(CS_CONTEXT, 1);
342 1440 : if (!ctx)
343 : return CS_FAIL;
344 1440 : ctx->use_large_identifiers = _ct_is_large_identifiers_version(version);
345 1440 : ctx->version = version;
346 1440 : tds_ctx = tds_alloc_context(ctx);
347 1440 : if (!tds_ctx) {
348 0 : free(ctx);
349 0 : return CS_FAIL;
350 : }
351 1440 : ctx->tds_ctx = tds_ctx;
352 1440 : if (tds_ctx->locale && !tds_ctx->locale->datetime_fmt) {
353 : /* set default in case there's no locale file */
354 0 : tds_ctx->locale->datetime_fmt = strdup(STD_DATETIME_FMT);
355 : }
356 :
357 1440 : ctx->login_timeout = -1;
358 1440 : ctx->query_timeout = -1;
359 :
360 1440 : *out_ctx = ctx;
361 1440 : return CS_SUCCEED;
362 : }
363 :
364 : CS_RETCODE
365 0 : cs_ctx_global(CS_INT version, CS_CONTEXT ** ctx)
366 : {
367 : static CS_CONTEXT *global_cs_ctx = NULL;
368 :
369 0 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_global(%d, %p)\n", version, ctx);
370 :
371 0 : if (global_cs_ctx != NULL) {
372 0 : *ctx = global_cs_ctx;
373 0 : return CS_SUCCEED;
374 : }
375 0 : if (cs_ctx_alloc(version, ctx) != CS_SUCCEED) {
376 : return CS_FAIL;
377 : }
378 0 : global_cs_ctx = *ctx;
379 0 : return CS_SUCCEED;
380 : }
381 :
382 : CS_RETCODE
383 1440 : cs_ctx_drop(CS_CONTEXT * ctx)
384 : {
385 1440 : tdsdump_log(TDS_DBG_FUNC, "cs_ctx_drop(%p)\n", ctx);
386 :
387 1440 : if (ctx) {
388 1440 : _ct_diag_clearmsg(ctx, CS_ALLMSG_TYPE);
389 1440 : free(ctx->userdata);
390 1440 : if (ctx->tds_ctx)
391 1440 : tds_free_context(ctx->tds_ctx);
392 1440 : free(ctx);
393 : }
394 1440 : return CS_SUCCEED;
395 : }
396 :
397 : CS_RETCODE
398 260 : cs_config(CS_CONTEXT * ctx, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
399 : {
400 : CS_INT maxcp; /* declared for - CS_USERDATA changes - swapna*/
401 :
402 260 : tdsdump_log(TDS_DBG_FUNC, "cs_config(%p, %d, %d, %p, %d, %p)\n", ctx, action, property, buffer, buflen, outlen);
403 :
404 260 : if (action == CS_GET) {
405 80 : if (buffer == NULL) {
406 : return CS_SUCCEED;
407 : }
408 80 : switch (property) {
409 0 : case CS_MESSAGE_CB:
410 0 : *(CS_CSLIBMSG_FUNC*) buffer = ctx->cslibmsg_cb;
411 0 : return CS_SUCCEED;
412 80 : case CS_USERDATA:
413 80 : if (buflen < 0) {
414 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
415 10 : return CS_FAIL;
416 : }
417 :
418 70 : maxcp = ctx->userdata_len;
419 70 : if (outlen)
420 40 : *outlen = maxcp;
421 :
422 70 : if (buflen < maxcp) {
423 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 2, "%d", buflen);
424 10 : return CS_FAIL;
425 : }
426 60 : memcpy(buffer, ctx->userdata, maxcp);
427 60 : return CS_SUCCEED;
428 :
429 0 : default:
430 : case CS_EXTRA_INF:
431 : case CS_LOC_PROP:
432 : case CS_VERSION:
433 0 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
434 0 : return CS_FAIL;
435 : break;
436 : }
437 : }
438 180 : if (action == CS_SET) {
439 170 : switch (property) {
440 50 : case CS_MESSAGE_CB:
441 50 : if ( ctx->cs_errhandletype == _CS_ERRHAND_INLINE) {
442 0 : cs_diag_clearmsg(ctx, CS_UNUSED);
443 : }
444 50 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) buffer;
445 50 : ctx->cs_errhandletype = _CS_ERRHAND_CB;
446 50 : return CS_SUCCEED;
447 110 : case CS_USERDATA:
448 110 : if (buflen < 0 && buflen != CS_NULLTERM) {
449 60 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", buflen, "buflen");
450 60 : return CS_FAIL;
451 : }
452 :
453 50 : maxcp = _ct_get_string_length(buffer, buflen);
454 50 : free(ctx->userdata);
455 50 : ctx->userdata = (void *) malloc(maxcp);
456 50 : if ( ctx->userdata == NULL) {
457 : return CS_FAIL;
458 : }
459 50 : ctx->userdata_len = maxcp;
460 :
461 50 : if (buffer) {
462 50 : memcpy(ctx->userdata, buffer, maxcp);
463 : } else {
464 : return CS_FAIL;
465 : }
466 50 : return CS_SUCCEED;
467 :
468 10 : default:
469 : case CS_EXTRA_INF:
470 : case CS_LOC_PROP:
471 : case CS_VERSION:
472 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
473 10 : return CS_FAIL;
474 : break;
475 : }
476 : }
477 10 : if (action == CS_CLEAR) {
478 0 : switch (property) {
479 0 : case CS_MESSAGE_CB:
480 0 : if ( ctx->cs_errhandletype == _CS_ERRHAND_INLINE) {
481 0 : cs_diag_clearmsg(ctx, CS_UNUSED);
482 : }
483 0 : ctx->cslibmsg_cb = NULL;
484 0 : ctx->cs_errhandletype = 0;
485 0 : return CS_SUCCEED;
486 0 : case CS_USERDATA:
487 0 : free(ctx->userdata);
488 0 : ctx->userdata = NULL;
489 0 : ctx->userdata_len = 0;
490 :
491 0 : return CS_SUCCEED;
492 :
493 0 : default:
494 : case CS_EXTRA_INF:
495 : case CS_LOC_PROP:
496 : case CS_VERSION:
497 0 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", property, "property");
498 0 : return CS_FAIL;
499 : break;
500 : }
501 : }
502 :
503 10 : _csclient_msg(ctx, "cs_config", 2, 1, 1, 6, "%d, %s", action, "action");
504 10 : return CS_FAIL;
505 : }
506 :
507 : TDS_INT
508 133232 : _cs_cs2tds(CS_CONTEXT *ctx, const CS_DATAFMT_COMMON *srcfmt, const void *srcdata, int desttype, CONV_RESULT *cres)
509 : {
510 : TDS_SERVER_TYPE src_type;
511 : int src_len, len;
512 : CS_INT datatype;
513 :
514 133232 : datatype = srcfmt->datatype;
515 133232 : src_type = _ct_get_server_type(NULL, datatype);
516 133232 : if (src_type == TDS_INVALID_TYPE)
517 : return TDS_CONVERT_NOAVAIL;
518 :
519 133222 : src_len = srcfmt->maxlength;
520 133222 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
521 120 : const CS_VARCHAR *vc = (const CS_VARCHAR *) srcdata;
522 :
523 : /* Prevent overflows, Sybase accept wrong values as correct */
524 120 : src_len = TDS_CLAMP(vc->len, 0, sizeof(vc->str));
525 120 : srcdata = vc->str;
526 : }
527 :
528 : /* conversion from char to binary are a bit peculiar */
529 133222 : if (desttype == TDS_CONVERT_BINARY && is_char_type(src_type)) {
530 468 : const char *src = srcdata;
531 : TDS_INT full_len;
532 :
533 468 : src_len = tds_hex_trim(&src, src_len);
534 :
535 468 : full_len = ((unsigned int) src_len + 1) / 2;
536 468 : if (full_len > cres->cb.len)
537 90 : src_len = 2 * cres->cb.len - (src_len & 1);
538 :
539 468 : len = tds_char2hex(cres->cb.ib, cres->cb.len, src, src_len);
540 468 : return len < 0 ? len : full_len;
541 : }
542 :
543 132754 : tdsdump_log(TDS_DBG_FUNC, "converting type %d (%d bytes) to type = %d\n", src_type, src_len, desttype);
544 :
545 132754 : len = tds_convert(ctx->tds_ctx, src_type, srcdata, src_len, desttype, cres);
546 :
547 132754 : tdsdump_log(TDS_DBG_FUNC, "_cs_cs2tds() tds_convert returned %d\n", len);
548 :
549 132754 : switch (len) {
550 : case TDS_CONVERT_NOAVAIL:
551 : case TDS_CONVERT_SYNTAX:
552 : case TDS_CONVERT_OVERFLOW:
553 : /* for these errors messages depends on caller */
554 : break;
555 0 : case TDS_CONVERT_NOMEM:
556 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 3, "");
557 0 : break;
558 : case TDS_CONVERT_FAIL:
559 : /* TODO error reporting */
560 : break;
561 : }
562 : return len;
563 : }
564 :
565 : static inline bool
566 : is_power_of_two_or_zero(CS_INT value)
567 : {
568 7334 : return (value & (value - 1)) == 0;
569 : }
570 :
571 : CS_RETCODE
572 9470 : _cs_convert(CS_CONTEXT *ctx, const CS_DATAFMT_COMMON *srcfmt, CS_VOID *srcdata,
573 : const CS_DATAFMT_COMMON *destfmt, CS_VOID *destdata, CS_INT *resultlen)
574 : {
575 9470 : CONV_RESULT cr, *p_cr = &cr;
576 : TDS_INT res;
577 : CS_INT dummy, format;
578 9470 : CS_VARCHAR *destvc = NULL;
579 9470 : CS_RETCODE rc = CS_SUCCEED;
580 9470 : CS_INT maxlength = -1;
581 : TDS_SERVER_TYPE desttype;
582 :
583 9470 : tdsdump_log(TDS_DBG_FUNC, "cs_convert(%p, %p, %p, %p, %p, %p)\n", ctx, srcfmt, srcdata, destfmt, destdata, resultlen);
584 :
585 : /* If srcfmt is NULL we have a problem */
586 9470 : if (srcfmt == NULL) {
587 0 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "srcfmt");
588 0 : return CS_FAIL;
589 : }
590 :
591 : /* If destfmt is NULL we have a problem */
592 9470 : if (destfmt == NULL) {
593 20 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destfmt");
594 20 : return CS_FAIL;
595 : }
596 :
597 9450 : format = destfmt->format;
598 :
599 : /* If destination is NULL we have a problem */
600 9450 : if (destdata == NULL) {
601 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 4, "destdata");
602 10 : return CS_FAIL;
603 :
604 : }
605 :
606 9440 : if (resultlen == NULL)
607 40 : resultlen = &dummy;
608 :
609 : /* If source is indicated to be NULL, set dest to low values */
610 9440 : if (srcdata == NULL) {
611 : /* TODO: implement cs_setnull */
612 0 : tdsdump_log(TDS_DBG_FUNC, "srcdata is null\n");
613 0 : memset(destdata, '\0', destfmt->maxlength);
614 0 : *resultlen = 0;
615 0 : return CS_SUCCEED;
616 : }
617 :
618 : /* more or less from _ct_get_server_type */
619 9440 : switch (destfmt->datatype) {
620 : case CS_VARCHAR_TYPE:
621 : desttype = TDS_CONVERT_CHAR;
622 : goto cs_var_common;
623 64 : case CS_VARBINARY_TYPE:
624 64 : desttype = TDS_CONVERT_BINARY;
625 94 : cs_var_common:
626 94 : destvc = (CS_VARCHAR *) destdata;
627 94 : cr.cc.c = destvc->str;
628 94 : cr.cc.len = sizeof(destvc->str);
629 94 : maxlength = sizeof(destvc->str);
630 94 : format = CS_FMT_UNUSED;
631 94 : break;
632 446 : case CS_BINARY_TYPE:
633 : case CS_IMAGE_TYPE:
634 : case CS_LONGBINARY_TYPE:
635 446 : desttype = TDS_CONVERT_BINARY;
636 446 : if ((format & (~CS_FMT_PADNULL)) != 0) {
637 60 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", format, "format");
638 60 : return CS_FAIL;
639 : }
640 : goto cs_char_binary_common;
641 0 : case CS_UNICHAR_TYPE:
642 : case CS_UNITEXT_TYPE:
643 : /* like SAP library, copy binary data as they are */
644 0 : switch (srcfmt->datatype) {
645 0 : case CS_BINARY_TYPE:
646 : case CS_VARBINARY_TYPE:
647 : case CS_LONGBINARY_TYPE:
648 : case CS_IMAGE_TYPE:
649 0 : desttype = TDS_CONVERT_BINARY;
650 : /* single byte terminator or blank padding make no sense here */
651 0 : if (format != CS_FMT_PADNULL)
652 0 : format = CS_FMT_UNUSED;
653 : goto cs_char_binary_common;
654 : }
655 : /* fall through */
656 : case CS_CHAR_TYPE:
657 : case CS_TEXT_TYPE:
658 : case CS_LONGCHAR_TYPE:
659 7354 : desttype = TDS_CONVERT_CHAR;
660 14688 : if ((format & (~(CS_FMT_NULLTERM | CS_FMT_PADNULL | CS_FMT_PADBLANK))) != 0 || !is_power_of_two_or_zero(format)) {
661 20 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", format, "format");
662 20 : return CS_FAIL;
663 : }
664 7334 : cs_char_binary_common:
665 7720 : cr.cc.c = destdata;
666 7720 : cr.cc.len = destfmt->maxlength;
667 7720 : maxlength = destfmt->maxlength;
668 7720 : if (maxlength < 0) {
669 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", maxlength, "maxlength");
670 10 : return CS_FAIL;
671 : }
672 : break;
673 150 : case CS_NUMERIC_TYPE:
674 : case CS_DECIMAL_TYPE:
675 150 : desttype = SYBNUMERIC;
676 150 : format = CS_FMT_UNUSED;
677 : {
678 : /* set the output precision/scale for conversions to numeric type */
679 150 : CS_INT precision = destfmt->precision;
680 150 : CS_INT scale = destfmt->scale;
681 150 : bool src_is_numeric = (srcfmt->datatype == CS_NUMERIC_TYPE || srcfmt->datatype == CS_DECIMAL_TYPE);
682 :
683 150 : if (destfmt->precision == CS_SRC_VALUE && src_is_numeric)
684 10 : precision = ((TDS_NUMERIC *) srcdata)->precision;
685 150 : if (destfmt->scale == CS_SRC_VALUE && src_is_numeric)
686 20 : scale = ((TDS_NUMERIC *) srcdata)->scale;
687 150 : if (precision < 1 || precision > MAXPRECISION) {
688 30 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", precision, "precision");
689 30 : return CS_FAIL;
690 : }
691 120 : if (scale < 0 || scale > precision) {
692 30 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 18, "%d, %s", scale, "scale");
693 30 : return CS_FAIL;
694 : }
695 90 : cr.n.precision = precision;
696 90 : cr.n.scale = scale;
697 : }
698 90 : break;
699 1396 : default:
700 1396 : desttype = _ct_get_server_type(NULL, destfmt->datatype);
701 1396 : if (desttype == TDS_INVALID_TYPE) {
702 10 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", srcfmt->datatype, destfmt->datatype);
703 10 : return CS_FAIL;
704 : }
705 : p_cr = (CONV_RESULT *) destdata;
706 : break;
707 : }
708 :
709 9280 : res = _cs_cs2tds(ctx, srcfmt, srcdata, desttype, p_cr);
710 9280 : if (res < 0) {
711 : /* other errors are already reported */
712 150 : switch (res) {
713 40 : case TDS_CONVERT_NOAVAIL:
714 40 : _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", srcfmt->datatype, destfmt->datatype);
715 40 : break;
716 50 : case TDS_CONVERT_SYNTAX:
717 50 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 24, "");
718 50 : break;
719 60 : case TDS_CONVERT_OVERFLOW:
720 60 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 20, "");
721 60 : break;
722 : }
723 : return CS_FAIL;
724 : }
725 :
726 9130 : if (maxlength >= 0) {
727 : /* overflow check */
728 7774 : if (res > maxlength) {
729 90 : tdsdump_log(TDS_DBG_FUNC, "Data-conversion resulted in overflow\n");
730 90 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
731 90 : res = maxlength;
732 90 : rc = CS_FAIL;
733 : }
734 :
735 : /* padding */
736 7774 : switch (format) {
737 5280 : case CS_FMT_NULLTERM:
738 5280 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_NULLTERM\n");
739 5280 : if (res < maxlength) {
740 5280 : cr.cc.c[res] = 0;
741 5280 : res++;
742 0 : } else if (res == maxlength && rc == CS_SUCCEED) {
743 0 : tdsdump_log(TDS_DBG_FUNC, "not enough room for data + a null terminator - error\n");
744 0 : _csclient_msg(ctx, "cs_convert", 2, 4, 1, 36, "");
745 0 : rc = CS_FAIL; /* not enough room for data + a null terminator - error */
746 : }
747 : break;
748 10 : case CS_FMT_PADBLANK:
749 10 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADBLANK\n");
750 10 : memset(cr.cc.c + res, ' ', maxlength - res);
751 10 : res = maxlength;
752 10 : break;
753 40 : case CS_FMT_PADNULL:
754 40 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADNULL\n");
755 40 : memset(cr.cc.c + res, '\0', maxlength - res);
756 40 : res = maxlength;
757 40 : break;
758 2444 : case CS_FMT_UNUSED:
759 2444 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_UNUSED\n");
760 : break;
761 : default:
762 : rc = CS_FAIL;
763 : break;
764 : }
765 1356 : }
766 :
767 : /* fix varchar_type/varbinary_type */
768 9130 : if (destvc) {
769 94 : destvc->len = TDS_MIN(res, sizeof(destvc->str));
770 94 : res = sizeof(*destvc);
771 : }
772 :
773 : /* numeric */
774 9130 : if (desttype == SYBNUMERIC) {
775 90 : res = tds_numeric_bytes_per_prec[cr.n.precision] + 2;
776 90 : memcpy(destdata, &(cr.n), res);
777 : }
778 :
779 9130 : *resultlen = res;
780 9130 : tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(rc));
781 : return rc;
782 : }
783 :
784 : CS_RETCODE
785 3102 : cs_convert(CS_CONTEXT *ctx, CS_DATAFMT *srcfmt, CS_VOID *srcdata, CS_DATAFMT *destfmt, CS_VOID *destdata, CS_INT *resultlen)
786 : {
787 3102 : return _cs_convert(ctx, _ct_datafmt_common(ctx, srcfmt), srcdata, _ct_datafmt_common(ctx, destfmt), destdata, resultlen);
788 : }
789 :
790 : CS_RETCODE
791 0 : cs_dt_crack_v2(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
792 : {
793 : TDSDATEREC dr;
794 : TDS_INT tds_type;
795 0 : bool extended = false;
796 :
797 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack_v2(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
798 :
799 0 : switch (datetype) {
800 : case CS_DATETIME_TYPE:
801 : tds_type = SYBDATETIME;
802 : break;
803 0 : case CS_DATETIME4_TYPE:
804 0 : tds_type = SYBDATETIME4;
805 0 : break;
806 0 : case CS_DATE_TYPE:
807 0 : tds_type = SYBDATE;
808 0 : break;
809 0 : case CS_TIME_TYPE:
810 0 : tds_type = SYBTIME;
811 0 : break;
812 0 : case CS_BIGDATETIME_TYPE:
813 0 : tds_type = SYB5BIGDATETIME;
814 0 : extended = true;
815 0 : break;
816 0 : case CS_BIGTIME_TYPE:
817 0 : tds_type = SYB5BIGTIME;
818 0 : extended = true;
819 0 : break;
820 : default:
821 : return CS_FAIL;
822 : }
823 0 : tds_datecrack(tds_type, dateval, &dr);
824 :
825 : /* Sybase CT-Library does not set these fields for CS_BIGTIME_TYPE */
826 0 : if (tds_type != SYB5BIGTIME) {
827 0 : daterec->dateyear = dr.year;
828 0 : daterec->datemonth = dr.month;
829 0 : daterec->datedmonth = dr.day;
830 0 : daterec->datedyear = dr.dayofyear;
831 0 : daterec->datedweek = dr.weekday;
832 : }
833 0 : daterec->datehour = dr.hour;
834 0 : daterec->dateminute = dr.minute;
835 0 : daterec->datesecond = dr.second;
836 0 : daterec->datemsecond = dr.decimicrosecond / 10000u;
837 0 : daterec->datetzone = dr.timezone;
838 0 : if (extended) {
839 0 : daterec->datesecfrac = dr.decimicrosecond / 10u;
840 0 : daterec->datesecprec = 1000000;
841 : }
842 :
843 : return CS_SUCCEED;
844 : }
845 :
846 : CS_RETCODE
847 0 : cs_dt_crack(CS_CONTEXT * ctx, CS_INT datetype, CS_VOID * dateval, CS_DATEREC * daterec)
848 : {
849 0 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_crack(%p, %d, %p, %p)\n", ctx, datetype, dateval, daterec);
850 :
851 : /* Avoid handling CS_BIGDATETIME_TYPE and CS_BIGTIME_TYPE as these
852 : * types requires a larger structure that would cause a buffer overflow. */
853 0 : if (datetype != CS_BIGDATETIME_TYPE && datetype != CS_BIGTIME_TYPE)
854 0 : return cs_dt_crack_v2(ctx, datetype, dateval, daterec);
855 : return CS_FAIL;
856 : }
857 :
858 : CS_RETCODE
859 40 : cs_loc_alloc(CS_CONTEXT * ctx, CS_LOCALE ** loc_pointer)
860 : {
861 : CS_LOCALE *tds_csloc;
862 :
863 40 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_alloc(%p, %p)\n", ctx, loc_pointer);
864 :
865 40 : if (!ctx)
866 : return CS_FAIL;
867 :
868 30 : if (!loc_pointer) {
869 10 : _csclient_msg(ctx, "cs_loc_alloc", 2, 1, 1, 4, "loc_pointer");
870 10 : return CS_FAIL;
871 : }
872 :
873 20 : tds_csloc = _cs_locale_alloc();
874 20 : if (!tds_csloc)
875 : return CS_FAIL;
876 :
877 20 : *loc_pointer = tds_csloc;
878 20 : return CS_SUCCEED;
879 : }
880 :
881 : CS_RETCODE
882 40 : cs_loc_drop(CS_CONTEXT * ctx, CS_LOCALE * locale)
883 : {
884 40 : tdsdump_log(TDS_DBG_FUNC, "cs_loc_drop(%p, %p)\n", ctx, locale);
885 :
886 40 : if (!ctx)
887 : return CS_FAIL;
888 :
889 30 : if (!locale) {
890 10 : _csclient_msg(ctx, "cs_loc_drop", 2, 1, 1, 4, "locale");
891 10 : return CS_FAIL;
892 : }
893 :
894 20 : _cs_locale_free(locale);
895 20 : return CS_SUCCEED;
896 : }
897 :
898 : CS_RETCODE
899 60 : cs_locale(CS_CONTEXT * ctx, CS_INT action, CS_LOCALE * locale, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
900 : {
901 : static const char func[] = "cs_locale";
902 60 : CS_RETCODE code = CS_FAIL;
903 :
904 60 : tdsdump_log(TDS_DBG_FUNC, "cs_locale(%p, %d, %p, %d, %p, %d, %p)\n", ctx, action, locale, type, buffer, buflen, outlen);
905 :
906 60 : if (!ctx)
907 : return CS_FAIL;
908 :
909 50 : if (!locale) {
910 10 : _csclient_msg(ctx, func, 2, 1, 1, 4, "locale");
911 10 : return CS_FAIL;
912 : }
913 :
914 40 : if (action == CS_SET) {
915 30 : switch (type) {
916 0 : case CS_LC_ALL:
917 : /* what to do here if there is locale data? */
918 0 : if (!buffer) {
919 0 : code = CS_SUCCEED;
920 : }
921 : break;
922 :
923 20 : case CS_SYB_CHARSET:
924 20 : buflen = _ct_get_string_length(buffer, buflen);
925 20 : if (buflen < 0) {
926 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
927 10 : return CS_FAIL;
928 : }
929 :
930 10 : free(locale->charset);
931 10 : locale->charset = tds_strndup(buffer, buflen);
932 10 : if (!locale->charset)
933 : break;
934 :
935 10 : code = CS_SUCCEED;
936 10 : break;
937 :
938 0 : case CS_SYB_LANG:
939 0 : buflen = _ct_get_string_length(buffer, buflen);
940 0 : if (buflen < 0) {
941 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
942 0 : return CS_FAIL;
943 : }
944 :
945 0 : free(locale->language);
946 0 : locale->language = tds_strndup(buffer, buflen);
947 0 : if (!locale->language)
948 : break;
949 :
950 0 : code = CS_SUCCEED;
951 0 : break;
952 :
953 0 : case CS_SYB_LANG_CHARSET:
954 : {
955 : int i;
956 0 : char *b = (char *)buffer;
957 :
958 0 : buflen = _ct_get_string_length(buffer, buflen);
959 0 : if (buflen < 0) {
960 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
961 0 : return CS_FAIL;
962 : }
963 :
964 : /* find '.' character */
965 0 : for (i = 0; i < buflen; ++i) {
966 0 : if (b[i] == '.') {
967 : break;
968 : }
969 : }
970 : /* not found */
971 0 : if (i == buflen) {
972 : break;
973 : }
974 0 : if (i) {
975 0 : free(locale->language);
976 0 : locale->language = tds_strndup(b, i);
977 0 : if (!locale->language)
978 : break;
979 : }
980 0 : if (i != (buflen - 1)) {
981 0 : free(locale->charset);
982 0 : locale->charset = tds_strndup(b + i + 1, buflen - i - 1);
983 0 : if (!locale->charset)
984 : break;
985 : }
986 : code = CS_SUCCEED;
987 : break;
988 : }
989 :
990 : /* TODO commented out until the code works end-to-end
991 : case CS_SYB_SORTORDER:
992 : buflen = _ct_get_string_length(buffer, buflen);
993 : if (buflen < 0) {
994 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
995 : return CS_FAIL;
996 : }
997 :
998 : free(locale->collate);
999 : locale->collate = tds_strndup(buffer, buflen);
1000 : if (!locale->collate)
1001 : break;
1002 :
1003 : code = CS_SUCCEED;
1004 : break;
1005 : */
1006 :
1007 10 : default:
1008 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1009 10 : code = CS_FAIL;
1010 10 : break;
1011 : }
1012 0 : }
1013 10 : else if (action == CS_GET)
1014 : {
1015 : CS_INT tlen;
1016 :
1017 0 : switch (type) {
1018 0 : case CS_SYB_CHARSET:
1019 0 : tlen = (locale->charset ? (CS_INT) strlen(locale->charset) : 0) + 1;
1020 0 : if (buflen < tlen)
1021 : {
1022 0 : if (outlen)
1023 0 : *outlen = tlen;
1024 : break;
1025 : }
1026 0 : if (locale->charset)
1027 0 : strcpy((char *)buffer, locale->charset);
1028 : else
1029 0 : ((char *)buffer)[0] = '\0';
1030 : code = CS_SUCCEED;
1031 : break;
1032 :
1033 0 : case CS_SYB_LANG:
1034 0 : tlen = (locale->language ? (CS_INT) strlen(locale->language) : 0) + 1;
1035 0 : if (buflen < tlen)
1036 : {
1037 0 : if (outlen)
1038 0 : *outlen = tlen;
1039 : break;
1040 : }
1041 0 : if (locale->language)
1042 0 : strcpy((char *)buffer, locale->language);
1043 : else
1044 0 : ((char *)buffer)[0] = '\0';
1045 : code = CS_SUCCEED;
1046 : break;
1047 :
1048 0 : case CS_SYB_LANG_CHARSET:
1049 : {
1050 : CS_INT clen;
1051 :
1052 0 : tlen = (locale->language ? (CS_INT) strlen(locale->language) : 0) + 1;
1053 0 : clen = (locale->charset ? (CS_INT) strlen(locale->charset) : 0) + 1;
1054 :
1055 0 : if (buflen < (tlen + clen))
1056 : {
1057 0 : if (outlen)
1058 0 : *outlen = tlen + clen;
1059 : break;
1060 : }
1061 0 : if (locale->language)
1062 0 : strcpy((char *)buffer, locale->language);
1063 : else
1064 0 : ((char *)buffer)[0] = '\0';
1065 0 : strcat((char *)buffer, ".");
1066 0 : if (locale->charset) {
1067 0 : tlen = (CS_INT) strlen((char *)buffer);
1068 0 : strcpy((char *)buffer + tlen, locale->charset);
1069 : }
1070 : code = CS_SUCCEED;
1071 : break;
1072 : }
1073 :
1074 0 : case CS_SYB_SORTORDER:
1075 0 : tlen = (locale->collate ? (CS_INT) strlen(locale->collate) : 0) + 1;
1076 0 : if (buflen < tlen)
1077 : {
1078 0 : if (outlen)
1079 0 : *outlen = tlen;
1080 : break;
1081 : }
1082 0 : if (locale->collate)
1083 0 : strcpy((char *)buffer, locale->collate);
1084 : else
1085 0 : ((char *)buffer)[0] = '\0';
1086 : code = CS_SUCCEED;
1087 : break;
1088 :
1089 0 : default:
1090 0 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1091 0 : code = CS_FAIL;
1092 0 : break;
1093 : }
1094 : } else {
1095 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, action", action);
1096 10 : code = CS_FAIL;
1097 : }
1098 : return code;
1099 : }
1100 :
1101 : typedef struct
1102 : {
1103 : CS_INT convfmt;
1104 : const char datetime[26];
1105 : uint8_t date_len;
1106 : uint8_t time_start;
1107 : } CONV_FORMAT;
1108 :
1109 : #define ONLY_DATE(convfmt, datetime) \
1110 : { convfmt, datetime, sizeof(datetime)-1, sizeof(datetime)-1 }
1111 : #define DATE_TIME(convfmt, date, time) \
1112 : { convfmt, date " " time, sizeof(date)-1, sizeof(date) }
1113 : #define ALL__SAME(convfmt, datetime) \
1114 : { convfmt, datetime, sizeof(datetime)-1, 0 }
1115 : static const CONV_FORMAT formats[] = {
1116 : DATE_TIME(CS_DATES_SHORT, "%b %e %Y", "%l:%M%p"),
1117 : ONLY_DATE(CS_DATES_MDY1, "%m/%d/%y"),
1118 : ONLY_DATE(CS_DATES_YMD1, "%y.%m.%d"),
1119 : ONLY_DATE(CS_DATES_DMY1, "%d/%m/%y"),
1120 : ONLY_DATE(CS_DATES_DMY2, "%d.%m.%y"),
1121 : ONLY_DATE(CS_DATES_DMY3, "%d-%m-%y"),
1122 : ONLY_DATE(CS_DATES_DMY4, "%d %b %y"),
1123 : ONLY_DATE(CS_DATES_MDY2, "%b %d, %y"),
1124 : ALL__SAME(CS_DATES_HMS, "%H:%M:%S"),
1125 : DATE_TIME(CS_DATES_LONG, "%b %e %Y", "%l:%M:%S:%z%p"),
1126 : ONLY_DATE(CS_DATES_MDY3, "%m-%d-%y"),
1127 : ONLY_DATE(CS_DATES_YMD2, "%y/%m/%d"),
1128 : ONLY_DATE(CS_DATES_YMD3, "%y%m%d"),
1129 : ONLY_DATE(CS_DATES_YDM1, "%y/%d/%m"),
1130 : ONLY_DATE(CS_DATES_MYD1, "%m/%y/%d"),
1131 : ONLY_DATE(CS_DATES_DYM1, "%d/%y/%m"),
1132 : ALL__SAME(CS_DATES_MDYHMS, "%b %e %Y %H:%M:%S"),
1133 : ALL__SAME(CS_DATES_HMA, "%l:%M%p"),
1134 : ALL__SAME(CS_DATES_HM, "%H:%M"),
1135 : ALL__SAME(CS_DATES_HMSZA, "%l:%M:%S:%3z%p"),
1136 : ALL__SAME(CS_DATES_HMSZ, "%H:%M:%S:%3z"),
1137 : ALL__SAME(CS_DATES_YMDHMS, "%y/%m/%d %H:%M:%S"),
1138 : ALL__SAME(CS_DATES_YMDHMA, "%y/%m/%d %l:%M%p"),
1139 : ALL__SAME(CS_DATES_YMDTHMS, "%Y-%m-%dT%H:%M:%S"),
1140 : ALL__SAME(CS_DATES_HMSUSA, "%l:%M:%S.%6z%p"),
1141 : ALL__SAME(CS_DATES_HMSUS, "%H:%M:%S.%6z"),
1142 : ALL__SAME(CS_DATES_LONGUSA, "%b %e %y %l:%M:%S.%6z%p"),
1143 : ALL__SAME(CS_DATES_LONGUS, "%b %e %y %H:%M:%S.%6z"),
1144 : ALL__SAME(CS_DATES_YMDHMSUS, "%y-%m-%d %H:%M:%S.%6z"),
1145 : ALL__SAME(CS_DATES_SHORT_ALT, "%b %e %Y %l:%M%p"),
1146 : ONLY_DATE(CS_DATES_MDY1_YYYY, "%m/%d/%Y"),
1147 : ONLY_DATE(CS_DATES_YMD1_YYYY, "%Y.%m.%d"),
1148 : ONLY_DATE(CS_DATES_DMY1_YYYY, "%d/%m/%Y"),
1149 : ONLY_DATE(CS_DATES_DMY2_YYYY, "%d.%m.%Y"),
1150 : ONLY_DATE(CS_DATES_DMY3_YYYY, "%d-%m-%Y"),
1151 : ONLY_DATE(CS_DATES_DMY4_YYYY, "%d %b %Y"),
1152 : ONLY_DATE(CS_DATES_MDY2_YYYY, "%b %d, %Y"),
1153 : ALL__SAME(CS_DATES_HMS_ALT, "%H:%M:%S"),
1154 : ALL__SAME(CS_DATES_LONG_ALT, "%b %e %Y %l:%M:%S:%3z%p"),
1155 : ONLY_DATE(CS_DATES_MDY3_YYYY, "%m-%d-%Y"),
1156 : ONLY_DATE(CS_DATES_YMD2_YYYY, "%Y/%m/%d"),
1157 : ONLY_DATE(CS_DATES_YMD3_YYYY, "%Y%m%d"),
1158 : ONLY_DATE(CS_DATES_YDM1_YYYY, "%Y/%d/%m"),
1159 : ONLY_DATE(CS_DATES_MYD1_YYYY, "%m/%Y/%d"),
1160 : ONLY_DATE(CS_DATES_DYM1_YYYY, "%d/%Y/%m"),
1161 : ALL__SAME(CS_DATES_MDYHMS_ALT, "%b %e %Y %H:%M:%S"),
1162 : ALL__SAME(CS_DATES_HMA_ALT, "%l:%M%p"),
1163 : ALL__SAME(CS_DATES_HM_ALT, "%H:%M"),
1164 : ALL__SAME(CS_DATES_YMDHMS_YYYY, "%Y/%m/%d %H:%M:%S"),
1165 : ALL__SAME(CS_DATES_YMDHMA_YYYY, "%Y/%m/%d %l:%M%p"),
1166 : ALL__SAME(CS_DATES_HMSUSA_YYYY, "%l:%M:%S.%6z%p"),
1167 : ALL__SAME(CS_DATES_HMSUS_YYYY, "%H:%M:%S.%6z"),
1168 : ALL__SAME(CS_DATES_LONGUSA_YYYY, "%b %e %Y %l:%M:%S.%6z%p"),
1169 : ALL__SAME(CS_DATES_LONGUS_YYYY, "%b %e %Y %H:%M:%S.%6z"),
1170 : ALL__SAME(CS_DATES_YMDHMSUS_YYYY, "%Y-%m-%d %H:%M:%S.%6z"),
1171 : {-1, "", 0, 0}
1172 : };
1173 :
1174 : static CS_RETCODE
1175 1910 : _cs_set_locale_convfmt(CS_CONTEXT *ctx, TDSLOCALE *loc, CS_INT convfmt)
1176 : {
1177 : const CONV_FORMAT *fmt;
1178 :
1179 33520 : for (fmt = formats; fmt->convfmt >= 0; ++fmt) {
1180 : char *datetime, *date, *time;
1181 :
1182 16760 : if (fmt->convfmt != convfmt)
1183 14850 : continue;
1184 1910 : datetime = strdup(fmt->datetime);
1185 1910 : date = tds_strndup(fmt->datetime, fmt->date_len);
1186 1910 : time = strdup(fmt->datetime + fmt->time_start);
1187 1910 : if (!datetime || !date || !time) {
1188 0 : free(datetime);
1189 0 : free(date);
1190 0 : free(time);
1191 0 : _csclient_msg(ctx, "cs_dt_info", 2, 4, 1, 3, "");
1192 0 : return CS_FAIL;
1193 : }
1194 1910 : free(loc->datetime_fmt);
1195 1910 : loc->datetime_fmt = datetime;
1196 1910 : free(loc->date_fmt);
1197 1910 : loc->date_fmt = date;
1198 1910 : free(loc->time_fmt);
1199 1910 : loc->time_fmt = time;
1200 1910 : break;
1201 : }
1202 : return CS_SUCCEED;
1203 : }
1204 :
1205 : CS_RETCODE
1206 2020 : cs_dt_info(CS_CONTEXT *ctx, CS_INT action, CS_LOCALE *locale, CS_INT type, CS_INT item, CS_VOID *buffer, CS_INT buflen,
1207 : CS_INT *outlen)
1208 : {
1209 : static const char func[] = "cs_dt_info";
1210 :
1211 2020 : tdsdump_log(TDS_DBG_FUNC, "cs_dt_info(%p, %d, %p, %d, %d, %p, %d, %p)\n",
1212 : ctx, action, locale, type, item, buffer, buflen, outlen);
1213 :
1214 2020 : if (!ctx)
1215 : return CS_FAIL;
1216 :
1217 2010 : if (action == CS_SET) {
1218 1990 : switch (type) {
1219 1980 : case CS_DT_CONVFMT:
1220 1980 : if (buflen < 0) {
1221 20 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, buflen", buflen);
1222 20 : return CS_FAIL;
1223 : }
1224 1960 : if (!locale && buffer) {
1225 1910 : CS_INT convfmt = *(CS_INT *) buffer;
1226 1910 : TDSLOCALE *loc = ctx->tds_ctx->locale;
1227 :
1228 1910 : return _cs_set_locale_convfmt(ctx, loc, convfmt);
1229 : }
1230 : break;
1231 10 : default:
1232 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1233 10 : return CS_FAIL;
1234 : break;
1235 : }
1236 20 : } else if (action == CS_GET) {
1237 : switch (type) {
1238 10 : default:
1239 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, type", type);
1240 10 : return CS_FAIL;
1241 : break;
1242 : }
1243 : } else {
1244 10 : _csclient_msg(ctx, func, 2, 1, 1, 6, "%d, action", action);
1245 10 : return CS_FAIL;
1246 : }
1247 : return CS_SUCCEED;
1248 : }
1249 :
1250 : CS_RETCODE
1251 0 : cs_strbuild(CS_CONTEXT * ctx, CS_CHAR * buffer, CS_INT buflen, CS_INT * resultlen, CS_CHAR * text, CS_INT textlen,
1252 : CS_CHAR * formats, CS_INT formatlen, ...)
1253 : {
1254 : va_list ap;
1255 : TDSRET rc;
1256 :
1257 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strbuild(%p, %p, %d, %p, %p, %d, %p, %d)\n",
1258 : ctx, buffer, buflen, resultlen, text, textlen, formats, formatlen);
1259 :
1260 0 : va_start(ap, formatlen);
1261 0 : rc = tds_vstrbuild(buffer, buflen, resultlen, text, textlen, formats, formatlen, ap);
1262 0 : va_end(ap);
1263 :
1264 0 : return TDS_SUCCEED(rc) ? CS_SUCCEED : CS_FAIL;
1265 : }
1266 :
1267 : CS_RETCODE
1268 0 : cs_calc(CS_CONTEXT * ctx, CS_INT op, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_VOID * dest)
1269 : {
1270 :
1271 0 : tdsdump_log(TDS_DBG_FUNC, "cs_calc(%p, %d, %d, %p, %p, %p)\n", ctx, op, datatype, var1, var2, dest);
1272 :
1273 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_calc()\n");
1274 0 : return CS_FAIL;
1275 : }
1276 :
1277 : CS_RETCODE
1278 0 : cs_cmp(CS_CONTEXT * ctx, CS_INT datatype, CS_VOID * var1, CS_VOID * var2, CS_INT * result)
1279 : {
1280 :
1281 0 : tdsdump_log(TDS_DBG_FUNC, "cs_cmp(%p, %d, %p, %p, %p)\n", ctx, datatype, var1, var2, result);
1282 :
1283 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_cmp()\n");
1284 0 : return CS_FAIL;
1285 : }
1286 :
1287 : CS_RETCODE
1288 0 : cs_conv_mult(CS_CONTEXT * ctx, CS_LOCALE * srcloc, CS_LOCALE * destloc, CS_INT * conv_multiplier)
1289 : {
1290 :
1291 0 : tdsdump_log(TDS_DBG_FUNC, "cs_conv_mult(%p, %p, %p, %p)\n", ctx, srcloc, destloc, conv_multiplier);
1292 :
1293 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_conv_mult()\n");
1294 0 : return CS_FAIL;
1295 : }
1296 :
1297 : CS_RETCODE
1298 70 : cs_diag(CS_CONTEXT * ctx, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
1299 : {
1300 70 : tdsdump_log(TDS_DBG_FUNC, "cs_diag(%p, %d, %d, %d, %p)\n", ctx, operation, type, idx, buffer);
1301 :
1302 70 : switch (operation) {
1303 :
1304 10 : case CS_INIT:
1305 10 : if ( ctx->cs_errhandletype == _CS_ERRHAND_CB) {
1306 : /* contrary to the manual page you don't seem to */
1307 : /* be able to turn on inline message handling */
1308 : /* using cs_diag, once a callback is installed! */
1309 : return CS_FAIL;
1310 : }
1311 10 : ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
1312 10 : ctx->cs_diag_msglimit = CS_NO_LIMIT;
1313 10 : ctx->cslibmsg_cb = (CS_CSLIBMSG_FUNC) cs_diag_storemsg;
1314 10 : break;
1315 0 : case CS_MSGLIMIT:
1316 0 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1317 : return CS_FAIL;
1318 : }
1319 0 : ctx->cs_diag_msglimit = *(CS_INT *)buffer;
1320 0 : break;
1321 10 : case CS_CLEAR:
1322 10 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1323 : return CS_FAIL;
1324 : }
1325 10 : return (cs_diag_clearmsg(ctx, type));
1326 :
1327 : break;
1328 30 : case CS_GET:
1329 30 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1330 : return CS_FAIL;
1331 : }
1332 30 : if (buffer == NULL)
1333 : return CS_FAIL;
1334 :
1335 30 : if (idx == 0 || (ctx->cs_diag_msglimit != CS_NO_LIMIT && idx > ctx->cs_diag_msglimit) )
1336 : return CS_FAIL;
1337 :
1338 30 : return (cs_diag_getmsg(ctx, idx, (CS_CLIENTMSG *)buffer));
1339 :
1340 : break;
1341 20 : case CS_STATUS:
1342 20 : if ( ctx->cs_errhandletype != _CS_ERRHAND_INLINE) {
1343 : return CS_FAIL;
1344 : }
1345 20 : if (buffer == NULL)
1346 : return CS_FAIL;
1347 :
1348 20 : return (cs_diag_countmsg(ctx, (CS_INT *)buffer));
1349 : break;
1350 : }
1351 : return CS_SUCCEED;
1352 :
1353 : }
1354 :
1355 : CS_RETCODE
1356 0 : cs_manage_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_CHAR * srcname, CS_INT srcnamelen, CS_INT desttype,
1357 : CS_CHAR * destname, CS_INT destnamelen, CS_INT * conv_multiplier, CS_CONV_FUNC * func)
1358 : {
1359 :
1360 0 : tdsdump_log(TDS_DBG_FUNC, "cs_manage_convert(%p, %d, %d, %p, %d, %d, %p, %d, %p, %p)\n",
1361 : ctx, action, srctype, srcname, srcnamelen, desttype, destname, destnamelen, conv_multiplier, func);
1362 :
1363 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_manage_convert()\n");
1364 0 : return CS_FAIL;
1365 : }
1366 :
1367 : CS_RETCODE
1368 0 : cs_objects(CS_CONTEXT * ctx, CS_INT action, CS_OBJNAME * objname, CS_OBJDATA * objdata)
1369 : {
1370 :
1371 0 : tdsdump_log(TDS_DBG_FUNC, "cs_objects(%p, %d, %p, %p)\n", ctx, action, objname, objdata);
1372 :
1373 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_objects()\n");
1374 0 : return CS_FAIL;
1375 : }
1376 :
1377 : CS_RETCODE
1378 0 : cs_set_convert(CS_CONTEXT * ctx, CS_INT action, CS_INT srctype, CS_INT desttype, CS_CONV_FUNC * func)
1379 : {
1380 :
1381 0 : tdsdump_log(TDS_DBG_FUNC, "cs_set_convert(%p, %d, %d, %d, %p)\n", ctx, action, srctype, desttype, func);
1382 :
1383 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_set_convert()\n");
1384 0 : return CS_FAIL;
1385 : }
1386 :
1387 : CS_RETCODE
1388 0 : cs_setnull(CS_CONTEXT * ctx, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT buflen)
1389 : {
1390 :
1391 0 : tdsdump_log(TDS_DBG_FUNC, "cs_setnull(%p, %p, %p, %d)\n", ctx, datafmt, buffer, buflen);
1392 :
1393 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_setnull()\n");
1394 0 : return CS_FAIL;
1395 : }
1396 :
1397 : CS_RETCODE
1398 0 : cs_strcmp(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_INT type, CS_CHAR * str1, CS_INT len1, CS_CHAR * str2, CS_INT len2,
1399 : CS_INT * result)
1400 : {
1401 :
1402 0 : tdsdump_log(TDS_DBG_FUNC, "cs_strcmp(%p, %p, %d, %p, %d, %p, %d, %p)\n",
1403 : ctx, locale, type, str1, len1, str2, len2, result);
1404 :
1405 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_strcmp()\n");
1406 0 : return CS_FAIL;
1407 : }
1408 :
1409 : CS_RETCODE
1410 0 : cs_time(CS_CONTEXT * ctx, CS_LOCALE * locale, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen, CS_DATEREC * daterec)
1411 : {
1412 :
1413 0 : tdsdump_log(TDS_DBG_FUNC, "cs_time(%p, %p, %p, %d, %p, %p)\n", ctx, locale, buffer, buflen, outlen, daterec);
1414 :
1415 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED cs_time()\n");
1416 0 : return CS_FAIL;
1417 : }
1418 :
1419 : CS_RETCODE
1420 935300 : cs_will_convert(CS_CONTEXT * ctx, CS_INT srctype, CS_INT desttype, CS_BOOL * result)
1421 : {
1422 :
1423 935300 : tdsdump_log(TDS_DBG_FUNC, "cs_will_convert(%p, %d, %d, %p)\n", ctx, srctype, desttype, result);
1424 :
1425 935300 : srctype = _ct_get_server_type(NULL, srctype);
1426 935300 : desttype = _ct_get_server_type(NULL, desttype);
1427 935300 : *result = (tds_willconvert(srctype, desttype) ? CS_TRUE : CS_FALSE);
1428 935300 : return CS_SUCCEED;
1429 : }
1430 :
1431 : static CS_INT
1432 20 : cs_diag_storemsg(CS_CONTEXT *context, CS_CLIENTMSG *message)
1433 : {
1434 : struct cs_diag_msg **curptr;
1435 20 : CS_INT msg_count = 0;
1436 :
1437 20 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_storemsg(%p, %p)\n", context, message);
1438 :
1439 20 : curptr = &(context->msgstore);
1440 :
1441 : /* if we already have a list of messages, */
1442 : /* go to the end of the list... */
1443 :
1444 50 : while (*curptr != NULL) {
1445 10 : msg_count++;
1446 10 : curptr = &((*curptr)->next);
1447 : }
1448 :
1449 : /* messages over and above the agreed limit */
1450 : /* are simply discarded... */
1451 :
1452 20 : if (context->cs_diag_msglimit != CS_NO_LIMIT &&
1453 : msg_count >= context->cs_diag_msglimit) {
1454 : return CS_FAIL;
1455 : }
1456 :
1457 20 : *curptr = tds_new(struct cs_diag_msg, 1);
1458 20 : if (*curptr == NULL) {
1459 : return CS_FAIL;
1460 : } else {
1461 20 : (*curptr)->next = NULL;
1462 20 : (*curptr)->msg = tds_new(CS_CLIENTMSG, 1);
1463 20 : if ((*curptr)->msg == NULL) {
1464 : return CS_FAIL;
1465 : } else {
1466 20 : memcpy((*curptr)->msg, message, sizeof(CS_CLIENTMSG));
1467 : }
1468 : }
1469 :
1470 20 : return CS_SUCCEED;
1471 : }
1472 :
1473 : static CS_INT
1474 30 : cs_diag_getmsg(CS_CONTEXT *context, CS_INT idx, CS_CLIENTMSG *message)
1475 : {
1476 : struct cs_diag_msg *curptr;
1477 30 : CS_INT msg_count = 0, msg_found = 0;
1478 :
1479 30 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_getmsg(%p, %d, %p)\n", context, idx, message);
1480 :
1481 30 : curptr = context->msgstore;
1482 :
1483 : /* if we already have a list of messages, */
1484 : /* go to the end of the list... */
1485 :
1486 90 : while (curptr != NULL) {
1487 50 : msg_count++;
1488 50 : if (msg_count == idx) {
1489 : msg_found++;
1490 : break;
1491 : }
1492 30 : curptr = curptr->next;
1493 : }
1494 30 : if (msg_found) {
1495 20 : memcpy(message, curptr->msg, sizeof(CS_CLIENTMSG));
1496 20 : return CS_SUCCEED;
1497 : } else {
1498 : return CS_NOMSG;
1499 : }
1500 : }
1501 :
1502 : static CS_INT
1503 10 : cs_diag_clearmsg(CS_CONTEXT *context, CS_INT type)
1504 : {
1505 : struct cs_diag_msg *curptr, *freeptr;
1506 :
1507 10 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_clearmsg(%p, %d)\n", context, type);
1508 :
1509 10 : curptr = context->msgstore;
1510 10 : context->msgstore = NULL;
1511 :
1512 40 : while (curptr != NULL ) {
1513 20 : freeptr = curptr;
1514 20 : curptr = freeptr->next;
1515 20 : free(freeptr->msg);
1516 20 : free(freeptr);
1517 : }
1518 10 : return CS_SUCCEED;
1519 : }
1520 :
1521 : static CS_INT
1522 20 : cs_diag_countmsg(CS_CONTEXT *context, CS_INT *count)
1523 : {
1524 : struct cs_diag_msg *curptr;
1525 20 : CS_INT msg_count = 0;
1526 :
1527 20 : tdsdump_log(TDS_DBG_FUNC, "cs_diag_countmsg(%p, %p)\n", context, count);
1528 :
1529 20 : curptr = context->msgstore;
1530 :
1531 60 : while (curptr != NULL) {
1532 20 : msg_count++;
1533 20 : curptr = curptr->next;
1534 : }
1535 20 : *count = msg_count;
1536 20 : return CS_SUCCEED;
1537 : }
1538 :
1539 : /**
1540 : * Try to convert to a type we can handle.
1541 : * Used before calling _cs_convert to handle TDS types that do not have a
1542 : * corresponding CS_xxx_TYPE.
1543 : * @param ctx Library context, used for conversion, can be NULL.
1544 : * @param curcol Column with data to convert.
1545 : * @param convert_buffer Buffer to store conversion, can be NULL.
1546 : * @param p_src Pointer to pointer to source data, can be NULL.
1547 : * @return Converted type or CS_ILLEGAL_TYPE.
1548 : */
1549 : int
1550 6608 : _cs_convert_not_client(CS_CONTEXT *ctx, const TDSCOLUMN *curcol, CONV_RESULT *convert_buffer, unsigned char **p_src)
1551 : {
1552 : int ct_type;
1553 6608 : TDS_SERVER_TYPE desttype, srctype = curcol->column_type;
1554 :
1555 6608 : if (srctype == SYBVARIANT)
1556 554 : srctype = ((const TDSVARIANT *) curcol->column_data)->type;
1557 :
1558 6608 : switch (srctype) {
1559 : case SYBMSDATE:
1560 : desttype = SYBDATE;
1561 : ct_type = CS_DATE_TYPE;
1562 : break;
1563 72 : case SYBMSTIME:
1564 72 : desttype = SYB5BIGTIME;
1565 72 : ct_type = CS_BIGTIME_TYPE;
1566 72 : break;
1567 176 : case SYBMSDATETIME2:
1568 : case SYBMSDATETIMEOFFSET:
1569 176 : desttype = SYB5BIGDATETIME;
1570 176 : ct_type = CS_BIGDATETIME_TYPE;
1571 176 : break;
1572 : default:
1573 : return CS_ILLEGAL_TYPE;
1574 : }
1575 :
1576 320 : if (convert_buffer) {
1577 160 : int len = tds_convert(ctx->tds_ctx, srctype, *p_src,
1578 80 : curcol->column_cur_size, desttype, convert_buffer);
1579 80 : if (len < 0)
1580 : return CS_ILLEGAL_TYPE; /* TODO _csclient_msg ?? */
1581 80 : *p_src = (unsigned char *) convert_buffer;
1582 : }
1583 : return ct_type;
1584 : }
|