LCOV - code coverage report
Current view: top level - src/ctlib - cs.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 441 727 60.7 %
Date: 2026-11-07 23:58:45 Functions: 26 42 61.9 %

          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             : }

Generated by: LCOV version 1.13