LCOV - code coverage report
Current view: top level - src/ctlib - ct.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1586 2464 64.4 %
Date: 2025-01-18 11:50:39 Functions: 55 62 88.7 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001  Brian Bruns
       3             :  * Copyright (C) 2002, 2003, 2004, 2005  James K. Lowden
       4             :  * Copyright (C) 2011-2015  Frediano Ziglio
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Library General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2 of the License, or (at your option) any later version.
      10             :  *
      11             :  * This library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Library General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Library General Public
      17             :  * License along with this library; if not, write to the
      18             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      19             :  * Boston, MA 02111-1307, USA.
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : 
      24             : #include <stdarg.h>
      25             : #include <stdio.h>
      26             : #include <assert.h>
      27             : 
      28             : #if HAVE_STDLIB_H
      29             : #include <stdlib.h>
      30             : #endif /* HAVE_STDLIB_H */
      31             : 
      32             : #if HAVE_STRING_H
      33             : #include <string.h>
      34             : #endif /* HAVE_STRING_H */
      35             : 
      36             : #include "ctpublic.h"
      37             : #include "ctlib.h"
      38             : #include <freetds/utils/string.h>
      39             : #include <freetds/utils.h>
      40             : #include <freetds/enum_cap.h>
      41             : #include <freetds/data.h>
      42             : #include <freetds/replacements.h>
      43             : 
      44             : 
      45             : static const char * ct_describe_cmd_state(CS_INT state);
      46             : /**
      47             :  * Read a row of data
      48             :  * @return 0 on success
      49             :  */
      50             : static int _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read);
      51             : static int _ct_fetchable_results(CS_COMMAND * cmd);
      52             : static TDSRET _ct_process_return_status(TDSSOCKET * tds);
      53             : 
      54             : static int _ct_fill_param(CS_INT cmd_type, CS_PARAM * param, const CS_DATAFMT_LARGE * datafmt, CS_VOID * data,
      55             :                           CS_INT * datalen, CS_SMALLINT * indicator, CS_BYTE byvalue);
      56             : static void _ct_initialise_cmd(CS_COMMAND *cmd);
      57             : static CS_RETCODE _ct_cancel_cleanup(CS_COMMAND * cmd);
      58             : static CS_INT _ct_map_compute_op(CS_INT comp_op);
      59             : 
      60             : /* Added for CT_DIAG */
      61             : /* Code changes starts here - CT_DIAG - 01 */
      62             : 
      63             : static CS_INT ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message);
      64             : static CS_INT ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message);
      65             : static CS_INT ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count);
      66             : static CS_INT ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message);
      67             : static CS_INT ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message);
      68             : 
      69             : /* Code changes ends here - CT_DIAG - 01 */
      70             : 
      71             : /* Added code for RPC functionality -SUHA */
      72             : /* RPC Code changes starts here */
      73             : 
      74             : static void rpc_clear(CSREMOTE_PROC * rpc);
      75             : static void param_clear(CSREMOTE_PROC_PARAM * pparam);
      76             : 
      77             : static TDSPARAMINFO *paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param);
      78             : 
      79             : static CS_DYNAMIC * _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen);
      80             : static CS_INT  _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn);
      81             : static CS_DYNAMIC * _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen);
      82             : 
      83             : /* RPC Code changes ends here */
      84             : 
      85             : static const char *
      86         256 : _ct_get_layer(int layer)
      87             : {
      88         256 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_layer(%d)\n", layer);
      89             : 
      90         256 :         switch (layer) {
      91             :         case 1:
      92             :                 return "user api layer";
      93             :                 break;
      94           0 :         case 2:
      95           0 :                 return "blk layer";
      96             :                 break;
      97             :         default:
      98             :                 break;
      99             :         }
     100           0 :         return "unrecognized layer";
     101             : }
     102             : 
     103             : static const char *
     104         256 : _ct_get_origin(int origin)
     105             : {
     106         256 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_origin(%d)\n", origin);
     107             : 
     108         256 :         switch (origin) {
     109             :         case 1:
     110             :                 return "external error";
     111             :                 break;
     112           0 :         case 2:
     113           0 :                 return "internal CT-Library error";
     114             :                 break;
     115           0 :         case 4:
     116           0 :                 return "common library error";
     117             :                 break;
     118           0 :         case 5:
     119           0 :                 return "intl library error";
     120             :                 break;
     121           0 :         case 6:
     122           0 :                 return "user error";
     123             :                 break;
     124           0 :         case 7:
     125           0 :                 return "internal BLK-Library error";
     126             :                 break;
     127             :         default:
     128             :                 break;
     129             :         }
     130           0 :         return "unrecognized origin";
     131             : }
     132             : 
     133             : static const char *
     134         256 : _ct_get_user_api_layer_error(int error)
     135             : {
     136         256 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_user_api_layer_error(%d)\n", error);
     137             : 
     138         256 :         switch (error) {
     139             :         case 2:
     140             :                 return "Memory allocation failure.";
     141             :                 break;
     142          16 :         case 3:
     143          16 :                 return "The parameter %1! cannot be NULL.";
     144             :                 break;
     145           8 :         case 4:
     146           8 :                 return "Parameter %1! has an illegal value of %2!.";
     147             :                 break;
     148         168 :         case 5:
     149         168 :                 return "An illegal value of %1! given for parameter %2!.";
     150             :                 break;
     151           8 :         case 6:
     152           8 :                 return "The parameter %1! cannot be NULL.";
     153             :                 break;
     154           8 :         case 15:
     155           8 :                 return "Use direction CS_BLK_IN or CS_BLK_OUT for a bulk copy operation.";
     156             :                 break;
     157           8 :         case 51:
     158           8 :                 return "Exactly one of context and connection must be non-NULL.";
     159             :                 break;
     160          16 :         case 135:
     161          16 :                 return "The specified id does not exist on this connection.";
     162             :                 break;
     163          16 :         case 137:
     164          16 :                 return  "A bind count of %1! is not consistent with the count supplied for existing binds. "
     165             :                         "The current bind count is %2!.";
     166             :                 break;
     167           0 :         case 140:
     168           0 :                 return "Failed when processing results from server.";
     169             :                 break;
     170           0 :         case 141:
     171           0 :                 return "Parameter %1! has an illegal value of %2!";
     172             :                 break;
     173           0 :         case 142:
     174           0 :                 return "No value or default value available and NULL not allowed. col = %1! row = %2! .";
     175             :                 break;
     176           0 :         case 143:
     177           0 :                 return "parameter name(s) must be supplied for LANGUAGE command.";
     178             :                 break;
     179           8 :         case 155:
     180           8 :                 return "This routine cannot be called when the command structure is idle.";
     181             :                 break;
     182             :         default:
     183             :                 break;
     184             :         }
     185           0 :         return "unrecognized error";
     186             : }
     187             : 
     188             : static char *
     189         256 : _ct_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
     190             : {
     191             :         char *m;
     192             : 
     193         256 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_msgstr(%s, %d, %d, %d, %d)\n", funcname, layer, origin, severity, number);
     194             : 
     195         256 :         if (asprintf(&m,
     196             :                      "%s: %s: %s: %s", funcname, _ct_get_layer(layer), _ct_get_origin(origin), _ct_get_user_api_layer_error(number)
     197             :             ) < 0) {
     198             :                 return NULL;
     199             :         }
     200         256 :         return m;
     201             : }
     202             : 
     203             : void
     204         256 : _ctclient_msg(CS_CONTEXT *ctx, CS_CONNECTION * con, const char *funcname,
     205             :               int layer, int origin, int severity, int number, const char *fmt, ...)
     206             : {
     207             :         va_list ap;
     208             :         CS_CLIENTMSG cm;
     209             :         char *msgstr;
     210         256 :         CS_CLIENTMSG_FUNC clientmsg_cb = NULL;
     211             : 
     212         256 :         tdsdump_log(TDS_DBG_FUNC, "_ctclient_msg(%p, %p, %s, %d, %d, %d, %d, %s)\n",
     213             :                     ctx, con, funcname, layer, origin, severity, number, fmt);
     214             : 
     215         256 :         if (!con && !ctx)
     216           0 :                 return;
     217             : 
     218         256 :         if (con) {
     219         240 :                 ctx = con->ctx;
     220         240 :                 clientmsg_cb = con->clientmsg_cb;
     221             :         }
     222         240 :         if (!clientmsg_cb)
     223          64 :                 clientmsg_cb = ctx->clientmsg_cb;
     224             : 
     225         256 :         va_start(ap, fmt);
     226             : 
     227         256 :         if (clientmsg_cb) {
     228         256 :                 cm.severity = severity;
     229         512 :                 cm.msgnumber = (((layer << 24) & 0xFF000000)
     230         256 :                                 | ((origin << 16) & 0x00FF0000)
     231         256 :                                 | ((severity << 8) & 0x0000FF00)
     232         256 :                                 | ((number) & 0x000000FF));
     233         256 :                 msgstr = _ct_get_msgstr(funcname, layer, origin, severity, number);
     234         256 :                 tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
     235         256 :                 cm.msgstring[cm.msgstringlen] = '\0';
     236         256 :                 free(msgstr);
     237         256 :                 cm.osnumber = 0;
     238         256 :                 cm.osstring[0] = '\0';
     239         256 :                 cm.osstringlen = 0;
     240         256 :                 cm.status = 0;
     241             :                 /* cm.sqlstate */
     242         256 :                 cm.sqlstatelen = 0;
     243         256 :                 clientmsg_cb(ctx, con, &cm);
     244             :         }
     245             : 
     246         256 :         va_end(ap);
     247             : }
     248             : 
     249             : static CS_RETCODE
     250       14096 : ct_set_command_state(CS_COMMAND *cmd, CS_INT state)
     251             : {
     252       14096 :         tdsdump_log(TDS_DBG_FUNC, "setting command state to %s (from %s)\n",
     253             :                     ct_describe_cmd_state(state),
     254             :                     ct_describe_cmd_state(cmd->command_state));
     255             : 
     256       14096 :         cmd->command_state = state;
     257             : 
     258       14096 :         return CS_SUCCEED;
     259             : }
     260             : 
     261             : static const char *
     262           0 : ct_describe_cmd_state(CS_INT state)
     263             : {
     264           0 :         tdsdump_log(TDS_DBG_FUNC, "ct_describe_cmd_state(%d)\n", state);
     265             : 
     266           0 :         switch (state) {
     267             :         case _CS_COMMAND_IDLE:
     268             :                 return "IDLE";
     269           0 :         case _CS_COMMAND_BUILDING:
     270           0 :                 return "BUILDING";
     271           0 :         case _CS_COMMAND_READY:
     272           0 :                 return "READY";
     273           0 :         case _CS_COMMAND_SENT:
     274           0 :                 return "SENT";
     275             :         }
     276           0 :         return "???";
     277             : }
     278             : 
     279             : CS_RETCODE
     280        1096 : ct_exit(CS_CONTEXT * ctx, CS_INT unused)
     281             : {
     282        1096 :         tdsdump_log(TDS_DBG_FUNC, "ct_exit(%p, %d)\n", ctx, unused);
     283             : 
     284        1096 :         return CS_SUCCEED;
     285             : }
     286             : 
     287             : CS_RETCODE
     288        1096 : ct_init(CS_CONTEXT * ctx, CS_INT version)
     289             : {
     290             :         /* uncomment the next line to get pre-login trace */
     291             :         /* tdsdump_open("/tmp/tds2.log"); */
     292        1096 :         tdsdump_log(TDS_DBG_FUNC, "ct_init(%p, %d)\n", ctx, version);
     293             : 
     294        1096 :         ctx->tds_ctx->msg_handler = _ct_handle_server_message;
     295        1096 :         ctx->tds_ctx->err_handler = _ct_handle_client_message;
     296        1096 :         ctx->use_large_identifiers = _ct_is_large_identifiers_version(version);
     297             : 
     298        1096 :         return CS_SUCCEED;
     299             : }
     300             : 
     301             : CS_RETCODE
     302        1088 : ct_con_alloc(CS_CONTEXT * ctx, CS_CONNECTION ** con)
     303             : {
     304             :         TDSLOGIN *login;
     305             : 
     306        1088 :         tdsdump_log(TDS_DBG_FUNC, "ct_con_alloc(%p, %p)\n", ctx, con);
     307             : 
     308        1088 :         login = tds_alloc_login(true);
     309        1088 :         if (!login)
     310             :                 return CS_FAIL;
     311             : 
     312             :         /* set default values */
     313        1088 :         if (!tds_set_library(login, "CT-Library")) {
     314           0 :                 tds_free_login(login);
     315           0 :                 return CS_FAIL;
     316             :         }
     317             : 
     318        1088 :         *con = tds_new0(CS_CONNECTION, 1);
     319        1088 :         if (!*con) {
     320           0 :                 tds_free_login(login);
     321           0 :                 return CS_FAIL;
     322             :         }
     323        1088 :         (*con)->tds_login = login;
     324        1088 :         (*con)->server_addr = NULL;
     325             : 
     326             :         /* so we know who we belong to */
     327        1088 :         (*con)->ctx = ctx;
     328             : 
     329             :         /* tds_set_packet((*con)->tds_login, TDS_DEF_BLKSZ); */
     330        1088 :         return CS_SUCCEED;
     331             : }
     332             : 
     333             : CS_RETCODE
     334        2270 : ct_callback(CS_CONTEXT * ctx, CS_CONNECTION * con, CS_INT action, CS_INT type, CS_VOID * func)
     335             : {
     336        2270 :         int (*funcptr) (void *, void *, void *) = (int (*)(void *, void *, void *)) func;
     337             : 
     338        2270 :         tdsdump_log(TDS_DBG_FUNC, "ct_callback(%p, %p, %d, %d, %p)\n", ctx, con, action, type, func);
     339             : 
     340        2270 :         tdsdump_log(TDS_DBG_FUNC, "ct_callback() action = %s\n", CS_GET ? "CS_GET" : "CS_SET");
     341             :         /* one of these has to be defined */
     342        2270 :         if (!ctx && !con)
     343             :                 return CS_FAIL;
     344             : 
     345        2262 :         if (!!ctx == !!con) {
     346           8 :                 _ctclient_msg(ctx, con, "ct_callback()", 1, 1, 1, 51, "");
     347           8 :                 return CS_FAIL;
     348             :         }
     349             : 
     350        2254 :         if (action != CS_GET && action != CS_SET) {
     351          16 :                 _ctclient_msg(ctx, con, "ct_callback()", 1, 1, 1, 5, "%d, %s", action, "action");
     352          16 :                 return CS_FAIL;
     353             :         }
     354             : 
     355        2238 :         if (action == CS_GET) {
     356             :                 CS_VOID *out_func;
     357             : 
     358          32 :                 switch (type) {
     359           8 :                 case CS_CLIENTMSG_CB:
     360           8 :                         out_func = (CS_VOID *) (con ? con->clientmsg_cb : ctx->clientmsg_cb);
     361             :                         break;
     362           8 :                 case CS_SERVERMSG_CB:
     363           8 :                         out_func = (CS_VOID *) (con ? con->servermsg_cb : ctx->servermsg_cb);
     364             :                         break;
     365           0 :                 case CS_INTERRUPT_CB:
     366           0 :                         out_func = (CS_VOID *) (con ? con->interrupt_cb : ctx->interrupt_cb);
     367             :                         break;
     368          16 :                 default:
     369          16 :                         _ctclient_msg(ctx, con, "ct_callback()", 1, 1, 1, 5, "%d, %s", type, "type");
     370          16 :                         return CS_FAIL;
     371             :                 }
     372             : 
     373          16 :                 if (!func) {
     374          16 :                         _ctclient_msg(ctx, con, "ct_callback()", 1, 1, 1, 3, "func");
     375          16 :                         return CS_FAIL;
     376             :                 }
     377           0 :                 *(void **) func = out_func;
     378           0 :                 return CS_SUCCEED;
     379             :         }
     380             : 
     381             :         /* CS_SET */
     382        2206 :         switch (type) {
     383        1096 :         case CS_CLIENTMSG_CB:
     384        1096 :                 if (con)
     385          24 :                         con->clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
     386             :                 else
     387        1072 :                         ctx->clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
     388             :                 break;
     389        1086 :         case CS_SERVERMSG_CB:
     390        1086 :                 if (con)
     391           8 :                         con->servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
     392             :                 else
     393        1078 :                         ctx->servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
     394             :                 break;
     395           8 :         case CS_INTERRUPT_CB:
     396           8 :                 if (funcptr) {
     397           8 :                         if (con)
     398           8 :                                 ctx = con->ctx;
     399             :                         /* install shim on demand */
     400           8 :                         ctx->tds_ctx->int_handler = _ct_handle_interrupt;
     401             :                 }
     402           8 :                 if (con)
     403           8 :                         con->interrupt_cb = (CS_INTERRUPT_FUNC) funcptr;
     404             :                 else
     405           0 :                         ctx->interrupt_cb = (CS_INTERRUPT_FUNC) funcptr;
     406             :                 break;
     407          16 :         default:
     408          16 :                 _ctclient_msg(ctx, con, "ct_callback()", 1, 1, 1, 5, "%d, %s", type, "type");
     409          16 :                 return CS_FAIL;
     410             :         }
     411             :         return CS_SUCCEED;
     412             : }
     413             : 
     414             : CS_RETCODE
     415        3304 : ct_con_props(CS_CONNECTION * con, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
     416             : {
     417             :         CS_INT intval, maxcp;
     418             :         TDSSOCKET *tds;
     419             :         TDSLOGIN *tds_login;
     420             : 
     421        3304 :         tdsdump_log(TDS_DBG_FUNC, "ct_con_props(%p, %d, %d, %p, %d, %p)\n", con, action, property, buffer, buflen, out_len);
     422             : 
     423        3304 :         if (!con)
     424             :                 return CS_FAIL;
     425             : 
     426        3296 :         tdsdump_log(TDS_DBG_FUNC, "ct_con_props() action = %s property = %d\n", action == CS_GET ? "CS_GET" : "CS_SET", property);
     427             : 
     428        3296 :         tds = con->tds_socket;
     429        3296 :         tds_login = con->tds_login;
     430             : 
     431        3296 :         if (action == CS_SET) {
     432        3240 :                 char *set_buffer = NULL;
     433        3240 :                 bool copy_ret = true;
     434             : 
     435        3240 :                 switch (property) {
     436             :                 /* string properties */
     437        2160 :                 case CS_USERNAME:
     438             :                 case CS_PASSWORD:
     439             :                 case CS_APPNAME:
     440             :                 case CS_HOSTNAME:
     441             :                 case CS_CLIENTCHARSET:
     442             :                 case CS_DATABASE:
     443             :                 case CS_SERVERADDR:
     444             :                 case CS_SEC_SERVERPRINCIPAL:
     445        2160 :                         buflen = _ct_get_string_length(buffer, buflen);
     446        2160 :                         if (buflen < 0) {
     447          16 :                                 _ctclient_msg(NULL, con, "ct_con_props(SET,APPNAME)", 1, 1, 1, 5, "%d, %s", buflen, "buflen");
     448          16 :                                 return CS_FAIL;
     449             :                         }
     450        2144 :                         set_buffer = tds_strndup(buffer, buflen);
     451        2144 :                         if (!set_buffer)
     452             :                                 return CS_FAIL;
     453             :                         break;
     454             :                 }
     455             : 
     456             :                 /*
     457             :                  * XXX "login" properties shouldn't be set after
     458             :                  * login.  I don't know if it should fail silently
     459             :                  * or return an error.
     460             :                  */
     461        3224 :                 switch (property) {
     462        1072 :                 case CS_USERNAME:
     463        1072 :                         copy_ret = tds_set_user(tds_login, set_buffer);
     464        1072 :                         break;
     465        1072 :                 case CS_PASSWORD:
     466        1072 :                         copy_ret = tds_set_passwd(tds_login, set_buffer);
     467        1072 :                         break;
     468           0 :                 case CS_APPNAME:
     469           0 :                         copy_ret = tds_set_app(tds_login, set_buffer);
     470           0 :                         break;
     471           0 :                 case CS_HOSTNAME:
     472           0 :                         copy_ret = tds_set_host(tds_login, set_buffer);
     473           0 :                         break;
     474           0 :                 case CS_CLIENTCHARSET:
     475           0 :                         copy_ret = tds_set_client_charset(tds_login, set_buffer);
     476           0 :                         break;
     477           0 :                 case CS_PORT:
     478           0 :                         tds_set_port(tds_login, *((int *) buffer));
     479           0 :                         break;
     480           0 :                 case CS_DATABASE:
     481           0 :                         copy_ret = !!tds_dstr_copy(&tds_login->database, set_buffer);
     482           0 :                         break;
     483           0 :                 case CS_SERVERADDR: {
     484             :                         /* Format of this property: "[hostname] [port]" */
     485           0 :                         char *host, *port, *lasts = NULL;
     486             :                         int portno;
     487           0 :                         host= strtok_r(set_buffer, " ", &lasts);
     488           0 :                         port= strtok_r(NULL, " ", &lasts);
     489           0 :                         if (!host || !port) {
     490           0 :                                 free(set_buffer);
     491           0 :                                 return CS_FAIL;
     492             :                         }
     493             : 
     494           0 :                         portno = (int)strtol(port, NULL, 10);
     495           0 :                         if (portno < 1 || portno >= 65536) {
     496           0 :                                 free(set_buffer);
     497           0 :                                 return CS_FAIL;
     498             :                         }
     499           0 :                         con->server_addr = strdup(host);
     500           0 :                         tds_set_port(tds_login, portno);
     501           0 :                         break;
     502             :                 }
     503           0 :                 case CS_SEC_SERVERPRINCIPAL:
     504           0 :                         copy_ret = !!tds_dstr_copy(&tds_login->server_spn, set_buffer);
     505           0 :                         break;
     506           0 :                 case CS_LOC_PROP:
     507             :                         /* sybase docs say that this structure must be copied, not referenced */
     508           0 :                         if (!buffer)
     509             :                                 return CS_FAIL;
     510             : 
     511           0 :                         if (con->locale)
     512           0 :                                 _cs_locale_free(con->locale);
     513           0 :                         con->locale = _cs_locale_copy((CS_LOCALE *) buffer);
     514           0 :                         if (!con->locale)
     515             :                                 return CS_FAIL;
     516             :                         break;
     517           0 :                 case CS_USERDATA:
     518           0 :                         free(con->userdata);
     519           0 :                         con->userdata = (void *) malloc(buflen + 1);
     520           0 :                         if (!con->userdata)
     521             :                                 return CS_FAIL;
     522           0 :                         tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, con->userdata);
     523           0 :                         con->userdata_len = buflen;
     524           0 :                         memcpy(con->userdata, buffer, buflen);
     525           0 :                         break;
     526        1064 :                 case CS_BULK_LOGIN:
     527        1064 :                         memcpy(&intval, buffer, sizeof(intval));
     528        1064 :                         tds_set_bulk(tds_login, !!intval);
     529        1064 :                         break;
     530           0 :                 case CS_PACKETSIZE:
     531           0 :                         memcpy(&intval, buffer, sizeof(intval));
     532           0 :                         tds_set_packet(tds_login, (short) intval);
     533           0 :                         break;
     534           0 :                 case CS_TDS_VERSION:
     535             :                         /*
     536             :                          * FIXME
     537             :                          * (a) We don't support all versions in tds/login.c -
     538             :                          *     I tried to pick reasonable versions.
     539             :                          * (b) Might need support outside of tds/login.c
     540             :                          * (c) It's a "negotiated" property so probably
     541             :                          *     needs tds_process_env_chg() support
     542             :                          * (d) Minor - we don't check against context
     543             :                          *     which should limit the acceptable values
     544             :                          */
     545           0 :                         if (*(int *) buffer == CS_TDS_AUTO) {
     546           0 :                                 tds_set_version(tds_login, 0, 0);
     547           0 :                         } else if (*(int *) buffer == CS_TDS_40) {
     548           0 :                                 tds_set_version(tds_login, 4, 2);
     549           0 :                         } else if (*(int *) buffer == CS_TDS_42) {
     550           0 :                                 tds_set_version(tds_login, 4, 2);
     551           0 :                         } else if (*(int *) buffer == CS_TDS_46) {
     552           0 :                                 tds_set_version(tds_login, 4, 6);
     553           0 :                         } else if (*(int *) buffer == CS_TDS_495) {
     554           0 :                                 tds_set_version(tds_login, 4, 6);
     555           0 :                         } else if (*(int *) buffer == CS_TDS_50) {
     556           0 :                                 tds_set_version(tds_login, 5, 0);
     557           0 :                         } else if (*(int *) buffer == CS_TDS_70) {
     558           0 :                                 tds_set_version(tds_login, 7, 0);
     559           0 :                         } else if (*(int *) buffer == CS_TDS_71) {
     560           0 :                                 tds_set_version(tds_login, 7, 1);
     561           0 :                         } else if (*(int *) buffer == CS_TDS_72) {
     562           0 :                                 tds_set_version(tds_login, 7, 2);
     563           0 :                         } else if (*(int *) buffer == CS_TDS_73) {
     564           0 :                                 tds_set_version(tds_login, 7, 3);
     565           0 :                         } else if (*(int *) buffer == CS_TDS_74) {
     566           0 :                                 tds_set_version(tds_login, 7, 4);
     567           0 :                         } else if (*(int *) buffer == CS_TDS_80) {
     568           0 :                                 tds_set_version(tds_login, 8, 0);
     569             :                         } else {
     570             :                                 return CS_FAIL;
     571             :                         }
     572             :                         break;
     573          16 :                 case CS_TIMEOUT:
     574             :                         /* set the query timeout as an integer in seconds */
     575          16 :                         tds_login->query_timeout = *(CS_INT *) buffer;
     576          16 :                         if (tds_login->query_timeout == CS_NO_LIMIT)
     577           0 :                                 tds_login->query_timeout = 0;
     578          16 :                         if (tds)
     579          16 :                                 tds->query_timeout = tds_login->query_timeout;
     580             :                         break;
     581           0 :                 case CS_LOGIN_TIMEOUT:
     582             :                         /* set the connect timeout as an integer in seconds */
     583           0 :                         tds_login->connect_timeout = *(CS_INT *) buffer;
     584           0 :                         if (tds_login->connect_timeout == CS_NO_LIMIT)
     585           0 :                                 tds_login->connect_timeout = 0;
     586             :                         break;
     587           0 :                 case CS_SEC_NETWORKAUTH:
     588           0 :                         con->network_auth = !!(*(CS_INT *) buffer);
     589           0 :                         break;
     590           0 :                 case CS_SEC_MUTUALAUTH:
     591           0 :                         tds_login->mutual_authentication = !!(*(CS_INT *) buffer);
     592           0 :                         break;
     593           0 :                 case CS_SEC_DELEGATION:
     594           0 :                         tds_login->gssapi_use_delegation = !!(*(CS_INT *) buffer);
     595           0 :                         break;
     596           0 :                 default:
     597           0 :                         tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
     598             :                         break;
     599             :                 }
     600        3224 :                 free(set_buffer);
     601        3224 :                 if (!copy_ret)
     602             :                         return CS_FAIL;
     603          56 :         } else if (action == CS_GET) {
     604             :                 DSTR *s;
     605             : 
     606          56 :                 switch (property) {
     607           0 :                 case CS_USERNAME:
     608           0 :                         s = &tds_login->user_name;
     609           0 :                         goto str_copy;
     610           0 :                 case CS_PASSWORD:
     611           0 :                         s = &tds_login->password;
     612           0 :                         goto str_copy;
     613           0 :                 case CS_APPNAME:
     614           0 :                         s = &tds_login->app_name;
     615           0 :                         goto str_copy;
     616           0 :                 case CS_HOSTNAME:
     617           0 :                         s = &tds_login->client_host_name;
     618           0 :                         goto str_copy;
     619           0 :                 case CS_SERVERNAME:
     620           0 :                         s = &tds_login->server_name;
     621           0 :                         goto str_copy;
     622           0 :                 case CS_CLIENTCHARSET:
     623           0 :                         s = &tds_login->client_charset;
     624           0 :                         goto str_copy;
     625           0 :                 case CS_DATABASE:
     626           0 :                         s = &tds_login->database;
     627           0 :                 str_copy:
     628           0 :                         if (out_len)
     629           0 :                                 *out_len = tds_dstr_len(s);
     630           0 :                         strlcpy((char *) buffer, tds_dstr_cstr(s), buflen);
     631           0 :                         break;
     632           0 :                 case CS_PRODUCT_NAME:
     633           0 :                         if (IS_TDSDEAD(tds) || tds->conn->product_name == NULL)
     634             :                                 /* TODO return proper error */
     635             :                                 return CS_FAIL;
     636           0 :                         if (out_len)
     637           0 :                                 *out_len = (CS_INT) strlen(tds->conn->product_name);
     638           0 :                         strlcpy((char *) buffer, tds->conn->product_name, buflen);
     639           0 :                         break;
     640           0 :                 case CS_LOC_PROP:
     641           0 :                         if (buflen != CS_UNUSED || !con->locale || !buffer)
     642             :                                 return CS_FAIL;
     643             : 
     644           0 :                         if (!_cs_locale_copy_inplace((CS_LOCALE *) buffer, con->locale))
     645             :                                 return CS_FAIL;
     646             :                         break;
     647           0 :                 case CS_USERDATA:
     648           0 :                         tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", con->userdata);
     649           0 :                         maxcp = con->userdata_len;
     650           0 :                         if (out_len)
     651           0 :                                 *out_len = maxcp;
     652           0 :                         if (maxcp > buflen)
     653           0 :                                 maxcp = buflen;
     654           0 :                         memcpy(buffer, con->userdata, maxcp);
     655           0 :                         break;
     656           0 :                 case CS_CON_STATUS:
     657           0 :                         intval = 0;
     658           0 :                         if (!(IS_TDSDEAD(tds)))
     659           0 :                                 intval |= CS_CONSTAT_CONNECTED;
     660           0 :                         if (tds && tds->state == TDS_DEAD)
     661           0 :                                 intval |= CS_CONSTAT_DEAD;
     662           0 :                         memcpy(buffer, &intval, sizeof(intval));
     663           0 :                         break;
     664           0 :                 case CS_BULK_LOGIN:
     665           0 :                         if (tds_login->bulk_copy)
     666             :                                 intval = CS_FALSE;
     667             :                         else
     668           0 :                                 intval = CS_TRUE;
     669           0 :                         memcpy(buffer, &intval, sizeof(intval));
     670           0 :                         break;
     671           0 :                 case CS_PACKETSIZE:
     672           0 :                         if (tds)
     673           0 :                                 intval = tds->conn->env.block_size;
     674             :                         else
     675           0 :                                 intval = tds_login->block_size;
     676           0 :                         memcpy(buffer, &intval, sizeof(intval));
     677           0 :                         if (out_len)
     678           0 :                                 *out_len = sizeof(intval);
     679             :                         break;
     680          16 :                 case CS_TDS_VERSION:
     681          16 :                         switch (tds->conn->tds_version) {
     682           0 :                         case 0x400:
     683           0 :                                 (*(int *) buffer = CS_TDS_40);
     684           0 :                                 break;
     685           0 :                         case 0x402:
     686           0 :                                 (*(int *) buffer = CS_TDS_42);
     687           0 :                                 break;
     688           0 :                         case 0x406:
     689           0 :                                 (*(int *) buffer = CS_TDS_46);
     690           0 :                                 break;
     691           0 :                         case 0x400 + 95:
     692           0 :                                 (*(int *) buffer = CS_TDS_495);
     693           0 :                                 break;
     694           4 :                         case 0x500:
     695           4 :                                 (*(int *) buffer = CS_TDS_50);
     696           4 :                                 break;
     697           0 :                         case 0x700:
     698           0 :                                 (*(int *) buffer = CS_TDS_70);
     699           0 :                                 break;
     700           8 :                         case 0x701:
     701           8 :                                 (*(int *) buffer = CS_TDS_71);
     702           8 :                                 break;
     703           0 :                         case 0x702:
     704           0 :                                 (*(int *) buffer = CS_TDS_72);
     705           0 :                                 break;
     706           4 :                         case 0x703:
     707           4 :                                 (*(int *) buffer = CS_TDS_73);
     708           4 :                                 break;
     709           0 :                         case 0x704:
     710           0 :                                 (*(int *) buffer = CS_TDS_74);
     711           0 :                                 break;
     712           0 :                         case 0x800:
     713           0 :                                 (*(int *) buffer = CS_TDS_80);
     714           0 :                                 break;
     715             :                         default:
     716             :                                 return CS_FAIL;
     717             :                         }
     718             :                         break;
     719          40 :                 case CS_PARENT_HANDLE:
     720          40 :                         *(CS_CONTEXT **) buffer = con->ctx;
     721          40 :                         break;
     722           0 :                 case CS_TIMEOUT:
     723           0 :                         *(CS_INT *) buffer = tds_login->query_timeout;
     724           0 :                         if (tds_login->query_timeout == 0)
     725           0 :                                 *(CS_INT *) buffer = CS_NO_LIMIT;
     726             :                         break;
     727           0 :                 case CS_LOGIN_TIMEOUT:
     728           0 :                         *(CS_INT *) buffer = tds_login->connect_timeout;
     729           0 :                         if (tds_login->connect_timeout == 0)
     730           0 :                                 *(CS_INT *) buffer = CS_NO_LIMIT;
     731             :                         break;
     732           0 :                 case CS_ENDPOINT:
     733           0 :                         *(CS_INT *) buffer = tds_get_s(con->tds_socket);
     734           0 :                         break;
     735           0 :                 default:
     736           0 :                         tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
     737             :                         break;
     738             :                 }
     739           0 :         }
     740             :         return CS_SUCCEED;
     741             : }
     742             : 
     743             : CS_RETCODE
     744        1080 : ct_connect(CS_CONNECTION * con, CS_CHAR * servername, CS_INT snamelen)
     745             : {
     746             :         char *server;
     747        1080 :         int needfree = 0;
     748             :         CS_CONTEXT *ctx;
     749             :         TDSLOGIN *login;
     750             :         bool copy_ret;
     751             : 
     752        1080 :         tdsdump_log(TDS_DBG_FUNC, "ct_connect(%p, %s, %d)\n", con, servername ? servername : "NULL", snamelen);
     753             : 
     754        1080 :         if (con->server_addr) {
     755             :                 server = "";
     756        1080 :         } else if (!servername || snamelen == 0 || snamelen == CS_UNUSED) {
     757             :                 server = NULL;
     758        1080 :         } else if (snamelen == CS_NULLTERM) {
     759             :                 server = (char *) servername;
     760           8 :         } else if (snamelen < 0) {
     761           8 :                 _ctclient_msg(NULL, con, "ct_connect()", 1, 1, 1, 5, "%d, %s", snamelen, "snamelen");
     762           8 :                 return CS_FAIL;
     763             :         } else {
     764           0 :                 server = tds_strndup(servername, snamelen);
     765           0 :                 needfree++;
     766             :         }
     767        1072 :         copy_ret = tds_set_server(con->tds_login, server);
     768        1072 :         if (needfree)
     769           0 :                 free(server);
     770        1072 :         if (!copy_ret)
     771             :                 return CS_FAIL;
     772        1072 :         ctx = con->ctx;
     773        1072 :         if (!(con->tds_socket = tds_alloc_socket(ctx->tds_ctx, 512)))
     774             :                 return CS_FAIL;
     775        1072 :         tds_set_parent(con->tds_socket, (void *) con);
     776        1072 :         if (!(login = tds_read_config_info(con->tds_socket, con->tds_login, ctx->tds_ctx->locale))) {
     777           0 :                 tds_free_socket(con->tds_socket);
     778           0 :                 con->tds_socket = NULL;
     779           0 :                 return CS_FAIL;
     780             :         }
     781        1072 :         if (con->server_addr) {
     782           0 :                 if (TDS_FAILED(tds_lookup_host_set(con->server_addr, &login->ip_addrs)))
     783             :                         goto Cleanup;
     784           0 :                 if (!tds_dstr_copy(&login->server_host_name, con->server_addr))
     785             :                         goto Cleanup;
     786             :         }
     787             : 
     788             :         /* Timeouts ... */
     789        1072 :         if (ctx->login_timeout > 0) {
     790           0 :             login->connect_timeout = ctx->login_timeout;
     791             :         }
     792             : 
     793        1072 :         if (ctx->query_timeout > 0) {
     794           0 :             login->query_timeout = ctx->query_timeout;
     795             :         }
     796             : 
     797             :         /* override locale settings with CS_CONNECTION settings, if any */
     798        1072 :         if (con->locale) {
     799           0 :                 if (con->locale->charset) {
     800           0 :                         if (!tds_dstr_copy(&login->server_charset, con->locale->charset))
     801             :                                 goto Cleanup;
     802             :                 }
     803           0 :                 if (con->locale->language) {
     804           0 :                         if (!tds_dstr_copy(&login->language, con->locale->language))
     805             :                                 goto Cleanup;
     806             :                 }
     807           0 :                 if (con->locale->time && tds_get_ctx(con->tds_socket)) {
     808           0 :                         TDSLOCALE *locale = tds_get_ctx(con->tds_socket)->locale;
     809           0 :                         free(locale->datetime_fmt);
     810             :                         /* TODO convert format from CTLib to libTDS */
     811           0 :                         locale->datetime_fmt = strdup(con->locale->time);
     812           0 :                         if (!locale->datetime_fmt)
     813             :                                 goto Cleanup;
     814             :                 }
     815             :                 /* TODO how to handle this?
     816             :                 if (con->locale->collate) {
     817             :                 }
     818             :                 */
     819             :         }
     820             : 
     821        1072 :         if (con->network_auth) {
     822           0 :                 tds_dstr_empty(&login->user_name);
     823           0 :                 tds_dstr_empty(&login->password);
     824             :         }
     825             : 
     826        1072 :         if (TDS_FAILED(tds_connect_and_login(con->tds_socket, login)))
     827             :                 goto Cleanup;
     828             : 
     829        1064 :         tds_free_login(login);
     830             : 
     831        1064 :         tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_SUCCEED);
     832             :         return CS_SUCCEED;
     833             : 
     834           8 : Cleanup:
     835           8 :         tds_free_socket(con->tds_socket);
     836           8 :         con->tds_socket = NULL;
     837           8 :         tds_free_login(login);
     838           8 :         tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_FAIL);
     839             :         return CS_FAIL;
     840             : }
     841             : 
     842             : CS_RETCODE
     843        1104 : ct_cmd_alloc(CS_CONNECTION * con, CS_COMMAND ** pcmd)
     844             : {
     845             :         CS_COMMAND *pcommand, *cmd;
     846             : 
     847        1104 :         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc(%p, %p)\n", con, pcmd);
     848             : 
     849        1104 :         if (!con)
     850             :                 return CS_FAIL;
     851             : 
     852        1104 :         *pcmd = cmd = tds_new0(CS_COMMAND, 1);
     853        1104 :         if (!cmd)
     854             :                 return CS_FAIL;
     855             : 
     856             :         /* so we know who we belong to */
     857        1104 :         cmd->con = con;
     858             : 
     859             :         /* initialise command state */
     860        1104 :         ct_set_command_state(cmd, _CS_COMMAND_IDLE);
     861             : 
     862        1104 :         if (!con->cmds) {
     863        1072 :                 tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc() : allocating command list to head\n");
     864        1072 :                 con->cmds = cmd;
     865             :         } else {
     866           8 :                 for (pcommand = con->cmds; pcommand->next != NULL; pcommand = pcommand->next)
     867           8 :                         continue;
     868          32 :                 pcommand->next = cmd;
     869             :         }
     870             : 
     871             :         return CS_SUCCEED;
     872             : }
     873             : 
     874             : CS_RETCODE
     875        2290 : ct_command(CS_COMMAND * cmd, CS_INT type, const CS_VOID * buffer, CS_INT buflen, CS_INT option)
     876             : {
     877             :         int query_len, current_query_len;
     878             : 
     879        2290 :         tdsdump_log(TDS_DBG_FUNC, "ct_command(%p, %d, %p, %d, %d)\n", cmd, type, buffer, buflen, option);
     880             : 
     881        2290 :         if (!cmd)
     882             :                 return CS_FAIL;
     883             : 
     884             :         /*
     885             :          * Unless we are in the process of building a CS_LANG_CMD command,
     886             :          * clear everything, ready to start anew
     887             :          */
     888        2290 :         if (cmd->command_state != _CS_COMMAND_BUILDING) {
     889        2282 :                 _ct_initialise_cmd(cmd);
     890        2282 :                 ct_set_command_state(cmd, _CS_COMMAND_IDLE);
     891             :         }
     892             : 
     893        2290 :         switch (type) {
     894        2216 :         case CS_LANG_CMD:
     895        2216 :                 switch (option) {
     896        2216 :                 case CS_MORE:   /* The text in buffer is only part of the language command to be executed. */
     897             :                 case CS_END:    /* The text in buffer is the last part of the language command to be executed. */
     898             :                 case CS_UNUSED: /* Equivalent to CS_END. */
     899        2216 :                         query_len = _ct_get_string_length(buffer, buflen);
     900        2216 :                         if (query_len < 0) {
     901          16 :                                 _ctclient_msg(NULL, cmd->con, "ct_command(LANG)", 1, 1, 1, 5, "%d, %s", buflen, "buflen");
     902          16 :                                 return CS_FAIL;
     903             :                         }
     904        2200 :                         switch (cmd->command_state) {
     905        2192 :                         case _CS_COMMAND_IDLE:
     906        2192 :                                 cmd->query = tds_strndup(buffer, query_len);
     907        2192 :                                 if (option == CS_MORE) {
     908           8 :                                         ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
     909             :                                 } else {
     910        2184 :                                         ct_set_command_state(cmd, _CS_COMMAND_READY);
     911             :                                 }
     912             :                                 break;
     913           8 :                         case _CS_COMMAND_BUILDING:
     914           8 :                                 current_query_len = strlen(cmd->query);
     915           8 :                                 if (!tds_realloc((void **) &cmd->query, current_query_len + query_len + 1))
     916             :                                         return CS_FAIL;
     917           8 :                                 strncat(cmd->query, (const char *) buffer, query_len);
     918           8 :                                 cmd->query[current_query_len + query_len] = '\0';
     919           8 :                                 if (option == CS_MORE) {
     920           0 :                                         ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
     921             :                                 } else {
     922           8 :                                         ct_set_command_state(cmd, _CS_COMMAND_READY);
     923             :                                 }
     924             :                                 break;
     925             :                         }
     926             :                         break;
     927             :                 default:
     928             :                         return CS_FAIL;
     929             :                 }
     930             :                 break;
     931             : 
     932          68 :         case CS_RPC_CMD:
     933             :                 /* Code changed for RPC functionality -SUHA */
     934             :                 /* RPC code changes starts here */
     935          68 :                 buflen = _ct_get_string_length(buffer, buflen);
     936          68 :                 if (buflen < 0) {
     937           8 :                         _ctclient_msg(NULL, cmd->con, "ct_command(RPC)", 1, 1, 1, 5, "%d, %s", buflen, "buflen");
     938           8 :                         return CS_FAIL;
     939             :                 }
     940             : 
     941          60 :                 cmd->rpc = tds_new0(CSREMOTE_PROC, 1);
     942          60 :                 if (!cmd->rpc) {
     943           0 :                         _ctclient_msg(NULL, cmd->con, "ct_command(RPC)", 1, 1, 1, 2, "");
     944           0 :                         return CS_FAIL;
     945             :                 }
     946             : 
     947          60 :                 cmd->rpc->name = tds_strndup(buffer, buflen);
     948          60 :                 if (!cmd->rpc->name) {
     949           0 :                         TDS_ZERO_FREE(cmd->rpc);
     950           0 :                         _ctclient_msg(NULL, cmd->con, "ct_command(RPC)", 1, 1, 1, 2, "");
     951           0 :                         return CS_FAIL;
     952             :                 }
     953             : 
     954          60 :                 cmd->rpc->param_list = NULL;
     955             : 
     956          60 :                 tdsdump_log(TDS_DBG_INFO1, "ct_command() added rpcname \"%s\"\n", cmd->rpc->name);
     957             : 
     958             :                 /* FIXME: I don't know the value for RECOMPILE, NORECOMPILE options. Hence assigning zero  */
     959          60 :                 switch (option) {
     960           0 :                 case CS_RECOMPILE:      /* Recompile the stored procedure before executing it. */
     961           0 :                         cmd->rpc->options = 0;
     962           0 :                         break;
     963          56 :                 case CS_NO_RECOMPILE:   /* Do not recompile the stored procedure before executing it. */
     964          56 :                         cmd->rpc->options = 0;
     965          56 :                         break;
     966           4 :                 case CS_UNUSED: /* Equivalent to CS_NO_RECOMPILE. */
     967           4 :                         cmd->rpc->options = 0;
     968           4 :                         break;
     969             :                 default:
     970             :                         return CS_FAIL;
     971             :                 }
     972          60 :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
     973          60 :                 break;
     974             :                 /* RPC code changes ends here */
     975             : 
     976           6 :         case CS_SEND_DATA_CMD:
     977           6 :                 switch (option) {
     978           6 :                 case CS_COLUMN_DATA:    /* The data will be used for a text or image column update. */
     979           6 :                         cmd->send_data_started = 0;
     980             :                         break;
     981             :                 case CS_BULK_DATA:      /* For internal Sybase use only. The data will be used for a bulk copy operation. */
     982             :                 default:
     983             :                         return CS_FAIL;
     984             :                 }
     985           6 :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
     986           6 :                 break;
     987             : 
     988             :         case CS_SEND_BULK_CMD:
     989             :                 switch (option) {
     990             :                 case CS_BULK_INIT:      /* For internal Sybase use only. Initialize a bulk copy operation. */
     991             :                 case CS_BULK_CONT:      /* For internal Sybase use only. Continue a bulk copy operation. */
     992             :                 default:
     993             :                         return CS_FAIL;
     994             :                 }
     995             :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
     996             :                 break;
     997             : 
     998             :         default:
     999             :                 return CS_FAIL;
    1000             :         }
    1001             : 
    1002        2266 :         cmd->command_type = type;
    1003             : 
    1004             : 
    1005        2266 :         return CS_SUCCEED;
    1006             : }
    1007             : 
    1008             : static void
    1009        3426 : _ct_initialise_cmd(CS_COMMAND *cmd)
    1010             : {
    1011        3426 :         free(cmd->query);
    1012        3426 :         cmd->query = NULL;
    1013             : 
    1014        3426 :         tdsdump_log(TDS_DBG_FUNC, "_ct_initialise_cmd(%p)\n", cmd);
    1015             : 
    1016        3426 :         if (cmd->input_params) {
    1017          24 :                 param_clear(cmd->input_params);
    1018          24 :                 cmd->input_params = NULL;
    1019             :         }
    1020        3426 :         ct_set_command_state(cmd, _CS_COMMAND_IDLE);
    1021             : 
    1022        3426 :         rpc_clear(cmd->rpc);
    1023        3426 :         cmd->rpc = NULL;
    1024        3426 : }
    1025             : 
    1026             : CS_RETCODE
    1027        2450 : ct_send(CS_COMMAND * cmd)
    1028             : {
    1029             :         TDSSOCKET *tds;
    1030             :         TDSPARAMINFO *pparam_info;
    1031             : 
    1032        2450 :         tdsdump_log(TDS_DBG_FUNC, "ct_send(%p)\n", cmd);
    1033             : 
    1034        2450 :         if (!cmd || !cmd->con || !cmd->con->tds_socket)
    1035             :                 return CS_FAIL;
    1036             : 
    1037        2450 :         tdsdump_log(TDS_DBG_FUNC, "ct_send() command_type = %d\n", cmd->command_type);
    1038             : 
    1039        2450 :         tds = cmd->con->tds_socket;
    1040             : 
    1041        2450 :         if (cmd->cancel_state == _CS_CANCEL_PENDING) {
    1042           0 :                 _ct_cancel_cleanup(cmd);
    1043           0 :                 return CS_CANCELED;
    1044             :         }
    1045             : 
    1046        2450 :         if (cmd->command_state == _CS_COMMAND_IDLE) {
    1047           8 :                 tdsdump_log(TDS_DBG_FUNC, "ct_send() command_state = IDLE\n");
    1048           8 :                 _ctclient_msg(NULL, cmd->con, "ct_send", 1, 1, 1, 155, "");
    1049           8 :                 return CS_FAIL;
    1050             :         }
    1051             : 
    1052        2442 :         cmd->results_state = _CS_RES_NONE;
    1053             : 
    1054        2442 :         if (cmd->command_type == CS_DYNAMIC_CMD) {
    1055          72 :                 CS_DYNAMIC *dyn = cmd->dyn;
    1056             :                 TDSDYNAMIC *tdsdyn;
    1057             : 
    1058          72 :                 if (!dyn)
    1059             :                         return CS_FAIL;
    1060             : 
    1061          64 :                 switch (cmd->dynamic_cmd) {
    1062          16 :                 case CS_PREPARE:
    1063          16 :                         if (TDS_FAILED(tds_submit_prepare(tds, dyn->stmt, dyn->id, &dyn->tdsdyn, NULL)))
    1064             :                                 return CS_FAIL;
    1065          16 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1066          16 :                         return CS_SUCCEED;
    1067             :                         break;
    1068          24 :                 case CS_EXECUTE:
    1069          24 :                         tdsdyn = dyn->tdsdyn;
    1070          24 :                         if (!tdsdyn) {
    1071           0 :                                 tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_EXECUTE) no tdsdyn!\n");
    1072             :                                 return CS_FAIL;
    1073             :                         }
    1074          24 :                         pparam_info = paraminfoalloc(tds, dyn->param_list);
    1075          24 :                         if (!pparam_info && dyn->param_list)
    1076             :                                 return CS_FAIL;
    1077          24 :                         tds_free_input_params(tdsdyn);
    1078          24 :                         tdsdyn->params = pparam_info;
    1079          24 :                         if (TDS_FAILED(tds_submit_execute(tds, tdsdyn)))
    1080             :                                 return CS_FAIL;
    1081          24 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1082          24 :                         return CS_SUCCEED;
    1083             :                         break;
    1084           8 :                 case CS_DESCRIBE_INPUT:
    1085           8 :                         tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_INPUT)\n");
    1086           8 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1087           8 :                         cmd->results_state = _CS_RES_DESCRIBE_RESULT;
    1088           8 :                         if (tds->cur_dyn)
    1089           8 :                                 tds_set_current_results(tds, tds->cur_dyn->res_info);
    1090             :                         else
    1091           0 :                                 tds_set_current_results(tds, tds->param_info);
    1092             :                         break;
    1093             : 
    1094           8 :                 case CS_DESCRIBE_OUTPUT:
    1095           8 :                         tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_OUTPUT)\n");
    1096           8 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1097           8 :                         cmd->results_state = _CS_RES_DESCRIBE_RESULT;
    1098           8 :                         tds_set_current_results(tds, tds->res_info);
    1099           8 :                         break;
    1100             : 
    1101           8 :                 case CS_DEALLOC:
    1102           8 :                         tdsdyn = dyn->tdsdyn;
    1103           8 :                         if (!tdsdyn) {
    1104           0 :                                 tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DEALLOC) no tdsdyn!\n");
    1105             :                                 return CS_FAIL;
    1106             :                         }
    1107           8 :                         if (TDS_FAILED(tds_submit_unprepare(tds, tdsdyn)))
    1108             :                                 return CS_FAIL;
    1109             : 
    1110           8 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1111           8 :                         return CS_SUCCEED;
    1112             :                         break;
    1113             : 
    1114             :                 default:
    1115             :                         return CS_FAIL;
    1116             :                 }
    1117        2370 :         }
    1118             : 
    1119        2386 :         if (cmd->command_type == CS_RPC_CMD) {
    1120          68 :                 CSREMOTE_PROC *rpc = cmd->rpc;
    1121             :                 TDSRET ret;
    1122             : 
    1123             :                 /* sanity */
    1124          68 :                 if (!cmd->rpc        /* ct_command should allocate pointer */
    1125          68 :                     || !rpc->name) { /* can't be ready without a name      */
    1126             :                         return CS_FAIL;
    1127             :                 }
    1128             : 
    1129          68 :                 pparam_info = paraminfoalloc(tds, rpc->param_list);
    1130          68 :                 ret = tds_submit_rpc(tds, rpc->name, pparam_info, NULL);
    1131             : 
    1132          68 :                 tds_free_param_results(pparam_info);
    1133             : 
    1134          68 :                 ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1135             : 
    1136          68 :                 if (TDS_FAILED(ret))
    1137             :                         return CS_FAIL;
    1138             : 
    1139          68 :                 return CS_SUCCEED;
    1140             :         }
    1141             : 
    1142             :         /* RPC Code changes ends here */
    1143             : 
    1144        2318 :         if (cmd->command_type == CS_LANG_CMD) {
    1145             :                 TDSRET ret;
    1146             : 
    1147        2192 :                 if (cmd->input_params) {
    1148          24 :                         pparam_info = paraminfoalloc(tds, cmd->input_params);
    1149          24 :                         ret = tds_submit_query_params(tds, cmd->query, pparam_info, NULL);
    1150          24 :                         tds_free_param_results(pparam_info);
    1151             :                 } else {
    1152        2168 :                         ret = tds_submit_query(tds, cmd->query);
    1153             :                 }
    1154             : 
    1155        2192 :                 ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1156             : 
    1157        2192 :                 if (TDS_FAILED(ret)) {
    1158           2 :                         tdsdump_log(TDS_DBG_WARN, "ct_send() failed\n");
    1159             :                         return CS_FAIL;
    1160             :                 }
    1161        2190 :                 tdsdump_log(TDS_DBG_INFO2, "ct_send() succeeded\n");
    1162             :                 return CS_SUCCEED;
    1163             :         }
    1164             : 
    1165             :         /* Code added for CURSOR support */
    1166             : 
    1167         126 :         if (cmd->command_type == CS_CUR_CMD) {
    1168             :                 TDSCURSOR *cursor;
    1169         104 :                 TDSRET ret = TDS_SUCCESS;
    1170             : 
    1171             :                 /* sanity */
    1172             :                 /*
    1173             :                  * ct_cursor declare should allocate cursor pointer
    1174             :                  * cursor stmt cannot be NULL
    1175             :                  * cursor name cannot be NULL
    1176             :                  */
    1177             : 
    1178         104 :                 bool something_to_send = false;
    1179             : 
    1180         104 :                 tdsdump_log(TDS_DBG_FUNC, "ct_send() : CS_CUR_CMD\n");
    1181             : 
    1182         104 :                 cursor = cmd->cursor;
    1183         104 :                 if (!cursor) {
    1184           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor not present\n");
    1185             :                         return CS_FAIL;
    1186             :                 }
    1187             : 
    1188         104 :                 if (!cursor->query) {
    1189           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->query is null\n");
    1190             :                         return CS_FAIL;
    1191             :                 }
    1192         104 :                 if (!cursor->cursor_name) {
    1193           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->name is null\n");
    1194             :                         return CS_FAIL;
    1195             :                 }
    1196             : 
    1197         104 :                 if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED) {
    1198          32 :                         TDSRET ret =  tds_cursor_declare(tds, cursor, &something_to_send);
    1199          32 :                         if (TDS_FAILED(ret)){
    1200           0 :                                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor declare failed \n");
    1201             :                                 return CS_FAIL;
    1202             :                         }
    1203          32 :                         cursor->status.declare = TDS_CURSOR_STATE_SENT; /* Cursor is declared */
    1204          32 :                         if (!something_to_send) {
    1205          24 :                                 cmd->results_state = _CS_RES_END_RESULTS;
    1206             :                         }
    1207             :                 }
    1208             : 
    1209         136 :                 if (cursor->status.cursor_row == _CS_CURS_TYPE_REQUESTED &&
    1210          32 :                         cursor->status.declare == _CS_CURS_TYPE_SENT) {
    1211             : 
    1212          32 :                         TDSRET ret = tds_cursor_setrows(tds, cursor, &something_to_send);
    1213          32 :                         if (TDS_FAILED(ret)){
    1214           0 :                                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor set rows failed\n");
    1215             :                                 return CS_FAIL;
    1216             :                         }
    1217          32 :                         cursor->status.cursor_row = TDS_CURSOR_STATE_SENT; /* Cursor rows set */
    1218          32 :                         if (!something_to_send) {
    1219          24 :                                 cmd->results_state = _CS_RES_END_RESULTS;
    1220             :                         }
    1221             :                 }
    1222             : 
    1223         136 :                 if (cursor->status.open == _CS_CURS_TYPE_REQUESTED &&
    1224          32 :                         cursor->status.declare == _CS_CURS_TYPE_SENT) {
    1225             : 
    1226          32 :                         TDSRET ret = tds_cursor_open(tds, cursor, NULL, &something_to_send);
    1227          32 :                         if (TDS_FAILED(ret)){
    1228           0 :                                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor open failed\n");
    1229             :                                 return CS_FAIL;
    1230             :                         }
    1231          32 :                         cursor->status.open = TDS_CURSOR_STATE_SENT;
    1232          32 :                         cmd->results_state = _CS_RES_INIT;
    1233             :                 }
    1234             : 
    1235         104 :                 if (something_to_send) {
    1236          36 :                         tdsdump_log(TDS_DBG_WARN, "ct_send(): sending cursor commands\n");
    1237          36 :                         tds_flush_packet(tds);
    1238          36 :                         tds_set_state(tds, TDS_PENDING);
    1239          36 :                         something_to_send = false;
    1240             : 
    1241          36 :                         ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1242             : 
    1243          36 :                         return CS_SUCCEED;
    1244             :                 }
    1245             : 
    1246          68 :                 if (cursor->status.close == _CS_CURS_TYPE_REQUESTED){
    1247          32 :                         if (cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
    1248             :                                 /* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
    1249           8 :                                 ret = tds_cursor_close(tds, cursor);
    1250           8 :                                 tds_release_cursor(&cmd->cursor);
    1251           8 :                                 cursor = NULL;
    1252             :                         } else {
    1253          24 :                                 ret = tds_cursor_close(tds, cursor);
    1254          24 :                                 cursor->status.close = TDS_CURSOR_STATE_SENT;
    1255             :                         }
    1256             :                 }
    1257             : 
    1258          60 :                 if (cursor && cursor->status.dealloc == _CS_CURS_TYPE_REQUESTED) {
    1259             :                         /* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
    1260          24 :                         ret = tds_cursor_dealloc(tds, cursor);
    1261          24 :                         tds_release_cursor(&cmd->cursor);
    1262          24 :                         tds_free_all_results(tds);
    1263             :                 }
    1264             : 
    1265          68 :                 if (TDS_SUCCEED(ret))
    1266          68 :                         cmd->results_state = _CS_RES_INIT;
    1267             : 
    1268          68 :                 ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1269          68 :                 return CS_SUCCEED;
    1270             :         }
    1271             : 
    1272          22 :         if (cmd->command_type == CS_SEND_DATA_CMD) {
    1273           6 :                 tds_writetext_end(tds);
    1274           6 :                 ct_set_command_state(cmd, _CS_COMMAND_SENT);
    1275             :         }
    1276             : 
    1277             :         return CS_SUCCEED;
    1278             : }
    1279             : 
    1280             : 
    1281             : CS_RETCODE
    1282        7532 : ct_results(CS_COMMAND * cmd, CS_INT * result_type)
    1283             : {
    1284             :         TDSSOCKET *tds;
    1285             :         CS_CONTEXT *context;
    1286             :         TDSRET tdsret;
    1287             :         CS_INT res_type;
    1288             :         CS_INT done_flags;
    1289             :         TDS_INT8 rows_affected;
    1290             :         unsigned process_flags;
    1291             : 
    1292        7532 :         tdsdump_log(TDS_DBG_FUNC, "ct_results(%p, %p)\n", cmd, result_type);
    1293             : 
    1294        7532 :         if (cmd->cancel_state == _CS_CANCEL_PENDING) {
    1295           0 :                 _ct_cancel_cleanup(cmd);
    1296           0 :                 return CS_CANCELED;
    1297             :         }
    1298             : 
    1299        7532 :         if (!cmd->con || !cmd->con->tds_socket)
    1300             :                 return CS_FAIL;
    1301             : 
    1302        7532 :         cmd->bind_count = CS_UNUSED;
    1303             : 
    1304        7532 :         context = cmd->con->ctx;
    1305             : 
    1306        7532 :         tds = cmd->con->tds_socket;
    1307        7532 :         cmd->row_prefetched = 0;
    1308             : 
    1309             :         /*
    1310             :          * depending on the current results state, we may
    1311             :          * not need to call tds_process_tokens...
    1312             :          */
    1313             : 
    1314        7532 :         switch (cmd->results_state) {
    1315          16 :         case _CS_RES_CMD_SUCCEED:
    1316          16 :                 *result_type = CS_CMD_SUCCEED;
    1317          16 :                 cmd->results_state = _CS_RES_CMD_DONE;
    1318          16 :                 return CS_SUCCEED;
    1319        2270 :         case _CS_RES_CMD_DONE:
    1320        2270 :                 *result_type = CS_CMD_DONE;
    1321        2270 :                 cmd->results_state = _CS_RES_INIT;
    1322        2270 :                 return CS_SUCCEED;
    1323           0 :         case _CS_RES_END_RESULTS:
    1324           0 :                 *result_type = CS_CMD_DONE;
    1325           0 :                 cmd->results_state = _CS_RES_INIT;
    1326           0 :                 return CS_END_RESULTS;
    1327          16 :         case _CS_RES_DESCRIBE_RESULT:
    1328          16 :                 *result_type = CS_DESCRIBE_RESULT;
    1329          16 :                 cmd->results_state = _CS_RES_CMD_DONE;
    1330          16 :                 return CS_SUCCEED;
    1331        2316 :         case _CS_RES_NONE:                              /* first time in after ct_send */
    1332        2316 :                 cmd->results_state = _CS_RES_INIT;
    1333        2316 :                 tds->rows_affected = TDS_NO_COUNT;
    1334        2316 :                 break;
    1335        2582 :         case _CS_RES_INIT:
    1336        2582 :                 tds->rows_affected = TDS_NO_COUNT;
    1337        2582 :                 break;
    1338             :         default:
    1339             :                 break;
    1340             :         }
    1341             : 
    1342        5230 :         rows_affected = tds->rows_affected;
    1343             : 
    1344             :         /*
    1345             :          * see what "result" tokens we have. a "result" in ct-lib terms also
    1346             :          * includes row data. Some result types always get reported back  to
    1347             :          * the calling program, others are only reported back if the relevant
    1348             :          * config flag is set.
    1349             :          */
    1350             : 
    1351        5230 :         process_flags = TDS_TOKEN_RESULTS;
    1352             :         for (;;) {
    1353             : 
    1354        6530 :                 tdsret = tds_process_tokens(tds, &res_type, &done_flags, process_flags);
    1355             : 
    1356        6530 :                 tdsdump_log(TDS_DBG_FUNC, "ct_results() process_result_tokens returned %d (type %d) \n",
    1357             :                             tdsret, res_type);
    1358             : 
    1359        6530 :                 switch (tdsret) {
    1360             : 
    1361        4106 :                 case TDS_SUCCESS:
    1362             : 
    1363        4106 :                         cmd->curr_result_type = res_type;
    1364             : 
    1365        4106 :                         switch (res_type) {
    1366             : 
    1367          16 :                         case CS_COMPUTEFMT_RESULT:
    1368             : 
    1369             :                                 /*
    1370             :                                  * set results state to indicate that we
    1371             :                                  * have a result set (empty for the moment)
    1372             :                                  * If the CS_EXPOSE_FMTS  property has been
    1373             :                                  * set in ct_config(), we need to return an
    1374             :                                  * appropraite format result, otherwise just
    1375             :                                  * carry on and get the next token.....
    1376             :                                  */
    1377             : 
    1378          16 :                                 cmd->results_state = _CS_RES_RESULTSET_EMPTY;
    1379             : 
    1380          16 :                                 if (context->config.cs_expose_formats) {
    1381           0 :                                         *result_type = res_type;
    1382           0 :                                         return CS_SUCCEED;
    1383             :                                 }
    1384             :                                 break;
    1385             : 
    1386         262 :                         case CS_ROWFMT_RESULT:
    1387         262 :                                 cmd->curr_result_type = CS_ROW_RESULT;
    1388         262 :                                 cmd->results_state = _CS_RES_RESULTSET_EMPTY;
    1389         262 :                                 rows_affected = tds->rows_affected = TDS_NO_COUNT;
    1390             : 
    1391         262 :                                 if (cmd->command_type == CS_CUR_CMD ||
    1392             :                                     cmd->command_type == CS_DYNAMIC_CMD)
    1393             :                                         break;
    1394             : 
    1395             :                                 /* don't process DONE tokens */
    1396         198 :                                 process_flags = TDS_RETURN_ROWFMT|TDS_RETURN_COMPUTEFMT|TDS_STOPAT_DONE|TDS_STOPAT_ROW|
    1397             :                                                 TDS_STOPAT_COMPUTE|TDS_RETURN_PROC;
    1398         198 :                                 break;
    1399             : 
    1400         204 :                         case CS_ROW_RESULT:
    1401             : 
    1402             :                                 /*
    1403             :                                  * we've hit a data row. pass back that fact
    1404             :                                  * to the calling program. set results state
    1405             :                                  * to show that the result set has rows...
    1406             :                                  */
    1407             : 
    1408         204 :                                 cmd->results_state = _CS_RES_RESULTSET_ROWS;
    1409         204 :                                 if (cmd->command_type == CS_CUR_CMD) {
    1410           0 :                                         *result_type = CS_CURSOR_RESULT;
    1411             :                                 } else {
    1412         204 :                                         *result_type = CS_ROW_RESULT;
    1413             :                                 }
    1414             :                                 return CS_SUCCEED;
    1415             :                                 break;
    1416             : 
    1417          24 :                         case CS_COMPUTE_RESULT:
    1418             : 
    1419             :                                 /*
    1420             :                                  * we've hit a compute data row. We have to get hold of this
    1421             :                                  * data now, as it's necessary  to tie this data back to its
    1422             :                                  * result format...the user may call ct_res_info() & friends
    1423             :                                  * after getting back a compute "result".
    1424             :                                  *
    1425             :                                  * but first, if we've hit this compute row without having
    1426             :                                  * hit a data row first, we need to return a  CS_ROW_RESULT
    1427             :                                  * before letting them have the compute row...
    1428             :                                  */
    1429             : 
    1430          24 :                                 if (cmd->results_state == _CS_RES_RESULTSET_EMPTY) {
    1431           0 :                                         *result_type = CS_ROW_RESULT;
    1432           0 :                                         tds_set_current_results(tds, tds->res_info);
    1433           0 :                                         cmd->results_state = _CS_RES_RESULTSET_ROWS;
    1434           0 :                                         return CS_SUCCEED;
    1435             :                                 }
    1436             : 
    1437          24 :                                 tdsret = tds_process_tokens(tds, &res_type, NULL,
    1438             :                                                          TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
    1439             : 
    1440             :                                 /* set results state to show that the result set has rows... */
    1441             : 
    1442          24 :                                 cmd->results_state = _CS_RES_RESULTSET_ROWS;
    1443             : 
    1444          24 :                                 *result_type = res_type;
    1445          24 :                                 if (tdsret == TDS_SUCCESS && (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT)) {
    1446          24 :                                         if (res_type == TDS_COMPUTE_RESULT) {
    1447          24 :                                                 cmd->row_prefetched = 1;
    1448          24 :                                                 return CS_SUCCEED;
    1449             :                                         } else {
    1450             :                                                 /* this couldn't really happen, but... */
    1451             :                                                 return CS_FAIL;
    1452             :                                         }
    1453             :                                 } else
    1454             :                                         return CS_FAIL;
    1455             :                                 break;
    1456             : 
    1457        2318 :                         case TDS_DONE_RESULT:
    1458             : 
    1459             :                                 /*
    1460             :                                  * A done token signifies the end of a logical
    1461             :                                  * command. There are three possibilities...
    1462             :                                  * 1. Simple command with no result set, i.e.
    1463             :                                  *    update, delete, insert
    1464             :                                  * 2. Command with result set but no rows
    1465             :                                  * 3. Command with result set and rows
    1466             :                                  * in these cases we need to:
    1467             :                                  * 1. return CS_CMD_FAIL/SUCCED depending on
    1468             :                                  *    the status returned in done_flags
    1469             :                                  * 2. "manufacture" a CS_ROW_RESULT return,
    1470             :                                  *    and set the results state to DONE
    1471             :                                  * 3. return with CS_CMD_DONE and reset the
    1472             :                                  *    results_state
    1473             :                                  */
    1474             : 
    1475        2318 :                                 tdsdump_log(TDS_DBG_FUNC, "ct_results() results state = %d\n",cmd->results_state);
    1476        2318 :                                 tdsdump_log(TDS_DBG_FUNC, "ct_results() command type  = %d\n",cmd->command_type);
    1477        2318 :                                 tdsdump_log(TDS_DBG_FUNC, "ct_results() dynamic cmd   = %d\n",cmd->dynamic_cmd);
    1478             : 
    1479        2324 :                                 if ((cmd->command_type == CS_DYNAMIC_CMD) &&
    1480           6 :                                         (cmd->dynamic_cmd == CS_PREPARE || cmd->dynamic_cmd == CS_DEALLOC)) {
    1481           6 :                                         *result_type = CS_CMD_SUCCEED;
    1482           6 :                                         cmd->results_state = _CS_RES_CMD_DONE;
    1483           6 :                                         return CS_SUCCEED;
    1484             :                                 }
    1485             : 
    1486        2312 :                                 if (tds->rows_affected != TDS_NO_COUNT)
    1487         642 :                                         rows_affected = tds->rows_affected;
    1488        2312 :                                 tds->rows_affected = rows_affected;
    1489             : 
    1490        2312 :                                 switch (cmd->results_state) {
    1491             : 
    1492        2144 :                                 case _CS_RES_INIT:
    1493             :                                 case _CS_RES_STATUS:
    1494        2144 :                                         if (done_flags & TDS_DONE_ERROR)
    1495          66 :                                                 *result_type = CS_CMD_FAIL;
    1496             :                                         else
    1497        2078 :                                                 *result_type = CS_CMD_SUCCEED;
    1498        2144 :                                         cmd->results_state = _CS_RES_CMD_DONE;
    1499        2144 :                                         break;
    1500             : 
    1501          34 :                                 case _CS_RES_RESULTSET_EMPTY:
    1502          34 :                                         if (cmd->command_type == CS_CUR_CMD) {
    1503          32 :                                                 *result_type = CS_CURSOR_RESULT;
    1504             :                                         } else {
    1505           2 :                                                 *result_type = CS_ROW_RESULT;
    1506             :                                         }
    1507          34 :                                         cmd->results_state = _CS_RES_RESULTSET_ROWS;
    1508          34 :                                         break;
    1509             : 
    1510         134 :                                 case _CS_RES_RESULTSET_ROWS:
    1511         134 :                                         *result_type = CS_CMD_DONE;
    1512         134 :                                         cmd->results_state = _CS_RES_INIT;
    1513         134 :                                         break;
    1514             : 
    1515             :                                 }
    1516             :                                 return CS_SUCCEED;
    1517             :                                 break;
    1518             : 
    1519        1110 :                         case TDS_DONEINPROC_RESULT:
    1520             : 
    1521             :                                 /*
    1522             :                                  * A doneinproc token may signify the end of a
    1523             :                                  * logical command if the command had a result
    1524             :                                  * set. Otherwise it is ignored....
    1525             :                                  */
    1526             : 
    1527        1110 :                                 if (tds->rows_affected != TDS_NO_COUNT)
    1528         710 :                                         rows_affected = tds->rows_affected;
    1529        1110 :                                 tds->rows_affected = rows_affected;
    1530             : 
    1531        1110 :                                 switch (cmd->results_state) {
    1532             :                                 case _CS_RES_INIT:   /* command had no result set */
    1533             :                                         break;
    1534          16 :                                 case _CS_RES_RESULTSET_EMPTY:
    1535          16 :                                         if (cmd->command_type == CS_CUR_CMD) {
    1536           0 :                                                 *result_type = CS_CURSOR_RESULT;
    1537           0 :                                                 cmd->results_state = _CS_RES_CMD_DONE;
    1538             :                                         } else {
    1539          16 :                                                 *result_type = CS_ROW_RESULT;
    1540          16 :                                                 cmd->results_state = _CS_RES_RESULTSET_ROWS;
    1541             :                                         }
    1542             :                                         return CS_SUCCEED;
    1543             :                                         break;
    1544          72 :                                 case _CS_RES_RESULTSET_ROWS:
    1545          72 :                                         *result_type = CS_CMD_DONE;
    1546          72 :                                         cmd->results_state = _CS_RES_INIT;
    1547          72 :                                         return CS_SUCCEED;
    1548             :                                         break;
    1549             :                                 }
    1550             :                                 break;
    1551             : 
    1552          98 :                         case TDS_DONEPROC_RESULT:
    1553             : 
    1554             :                                 /*
    1555             :                                  * A DONEPROC result means the end of a logical
    1556             :                                  * command only if it was one of the commands
    1557             :                                  * directly sent from ct_send, not as a result
    1558             :                                  * of a nested stored procedure call. We know
    1559             :                                  * if this is the case if a STATUS_RESULT was
    1560             :                                  * received immediately prior to the DONE_PROC
    1561             :                                  */
    1562             : 
    1563          98 :                                 if (tds->rows_affected != TDS_NO_COUNT)
    1564          56 :                                         rows_affected = tds->rows_affected;
    1565          98 :                                 tds->rows_affected = rows_affected;
    1566             : 
    1567          98 :                                 if (done_flags & TDS_DONE_ERROR)
    1568           6 :                                         *result_type = CS_CMD_FAIL;
    1569             :                                 else
    1570          92 :                                         *result_type = CS_CMD_SUCCEED;
    1571          98 :                                 cmd->results_state = _CS_RES_CMD_DONE;
    1572          98 :                                 return CS_SUCCEED;
    1573             :                                 break;
    1574             : 
    1575          16 :                         case TDS_PARAM_RESULT:
    1576          16 :                                 cmd->row_prefetched = 1;
    1577          16 :                                 *result_type = res_type;
    1578          16 :                                 return CS_SUCCEED;
    1579             :                                 break;
    1580             : 
    1581          58 :                         case TDS_STATUS_RESULT:
    1582          58 :                                 _ct_process_return_status(tds);
    1583          58 :                                 cmd->row_prefetched = 1;
    1584          58 :                                 *result_type = res_type;
    1585          58 :                                 cmd->results_state = _CS_RES_STATUS;
    1586          58 :                                 return CS_SUCCEED;
    1587             :                                 break;
    1588             : 
    1589           0 :                         case TDS_DESCRIBE_RESULT:
    1590           0 :                                 if (cmd->dynamic_cmd == CS_DESCRIBE_INPUT ||
    1591             :                                         cmd->dynamic_cmd == CS_DESCRIBE_OUTPUT) {
    1592           0 :                                         *result_type = res_type;
    1593           0 :                                         return CS_SUCCEED;
    1594             :                                 }
    1595             :                                 break;
    1596           0 :                         default:
    1597           0 :                                 *result_type = res_type;
    1598           0 :                                 return CS_SUCCEED;
    1599             :                                 break;
    1600             :                         }
    1601             : 
    1602          64 :                         break;
    1603             : 
    1604        2414 :                 case TDS_NO_MORE_RESULTS:
    1605             : 
    1606             :                         /* some commands can be re-sent once completed */
    1607             :                         /* so mark the command state as 'ready'...     */
    1608             : 
    1609        4828 :                         if (cmd->command_type == CS_LANG_CMD ||
    1610        2414 :                                 cmd->command_type == CS_RPC_CMD ||
    1611          70 :                                 cmd->command_type == CS_CUR_CMD ||
    1612             :                                 cmd->command_type == CS_DYNAMIC_CMD) {
    1613        2408 :                                 ct_set_command_state(cmd, _CS_COMMAND_READY);
    1614             :                         }
    1615             :                         /* if we have just completed processing a dynamic deallocate */
    1616             :                         /* get rid of our dynamic statement structure...             */
    1617             : 
    1618        2478 :                         if (cmd->command_type == CS_DYNAMIC_CMD &&
    1619          64 :                                 cmd->dynamic_cmd  == CS_DEALLOC) {
    1620           8 :                                 _ct_deallocate_dynamic(cmd->con, cmd->dyn);
    1621           8 :                                 cmd->dyn = NULL;
    1622             :                         }
    1623             :                         return CS_END_RESULTS;
    1624             :                         break;
    1625             : 
    1626           0 :                 case TDS_CANCELLED:
    1627           0 :                         cmd->cancel_state = _CS_CANCEL_NOCANCEL;
    1628           0 :                         return CS_CANCELED;
    1629             :                         break;
    1630             : 
    1631             :                 default:
    1632             :                         return CS_FAIL;
    1633             :                         break;
    1634             : 
    1635             :                 }  /* switch (tdsret) */
    1636             :         }      /* for (;;)        */
    1637             : }
    1638             : 
    1639             : CS_RETCODE
    1640         554 : ct_bind(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt_arg, CS_VOID * buffer, CS_INT * copied, CS_SMALLINT * indicator)
    1641             : {
    1642             :         TDSCOLUMN *colinfo;
    1643             :         TDSRESULTINFO *resinfo;
    1644             :         TDSSOCKET *tds;
    1645         554 :         CS_CONNECTION *con = cmd->con;
    1646             :         const CS_DATAFMT_COMMON * datafmt;
    1647             :         CS_INT bind_count;
    1648             : 
    1649         554 :         tdsdump_log(TDS_DBG_FUNC, "ct_bind(%p, %d, %p, %p, %p, %p)\n", cmd, item, datafmt_arg, buffer, copied, indicator);
    1650             : 
    1651         554 :         if (!con || !con->tds_socket)
    1652             :                 return CS_FAIL;
    1653             : 
    1654         554 :         datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
    1655             : 
    1656         554 :         bind_count = datafmt->count;
    1657             : 
    1658         554 :         tdsdump_log(TDS_DBG_FUNC, "ct_bind() datafmt count = %d column_number = %d\n", bind_count, item);
    1659             : 
    1660         554 :         tds = con->tds_socket;
    1661         554 :         resinfo = tds->current_results;
    1662             : 
    1663             :         /* check item value */
    1664         554 :         if (!resinfo || item <= 0 || item > resinfo->num_cols)
    1665             :                 return CS_FAIL;
    1666             : 
    1667             :         /*
    1668             :          * Check whether the request is for array binding, and ensure that the user
    1669             :          * supplies the same datafmt->count to the subsequent ct_bind calls
    1670             :          */
    1671             : 
    1672         554 :         bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
    1673             : 
    1674             :         /* first bind for this result set */
    1675             : 
    1676         554 :         if (cmd->bind_count == CS_UNUSED) {
    1677         246 :                 cmd->bind_count = bind_count;
    1678             :         } else {
    1679             :                 /* all subsequent binds for this result set - the bind counts must be the same */
    1680         308 :                 if (cmd->bind_count != bind_count) {
    1681          16 :                         _ctclient_msg(NULL, con, "ct_bind", 1, 1, 1, 137, "%d, %d", bind_count, cmd->bind_count);
    1682          16 :                         return CS_FAIL;
    1683             :                 }
    1684             :         }
    1685             : 
    1686             :         /* bind the column_varaddr to the address of the buffer */
    1687             : 
    1688         538 :         colinfo = resinfo->columns[item - 1];
    1689         538 :         colinfo->column_varaddr = (char *) buffer;
    1690         538 :         colinfo->column_bindtype = datafmt->datatype;
    1691         538 :         colinfo->column_bindfmt = datafmt->format;
    1692         538 :         colinfo->column_bindlen = datafmt->maxlength;
    1693         538 :         if (indicator) {
    1694         538 :                 colinfo->column_nullbind = indicator;
    1695             :         }
    1696         538 :         if (copied) {
    1697         538 :                 colinfo->column_lenbind = copied;
    1698             :         }
    1699             :         return CS_SUCCEED;
    1700             : }
    1701             : 
    1702             : CS_RETCODE
    1703       14268 : ct_fetch(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * prows_read)
    1704             : {
    1705             :         TDS_INT ret_type;
    1706             :         TDSRET ret;
    1707             :         TDS_INT marker;
    1708             :         TDS_INT temp_count;
    1709             :         TDSSOCKET *tds;
    1710             :         CS_INT rows_read_dummy;
    1711             : 
    1712       14268 :         tdsdump_log(TDS_DBG_FUNC, "ct_fetch(%p, %d, %d, %d, %p)\n", cmd, type, offset, option, prows_read);
    1713             : 
    1714       14268 :         if (!cmd->con || !cmd->con->tds_socket)
    1715             :                 return CS_FAIL;
    1716             : 
    1717       14268 :         if (cmd->command_state == _CS_COMMAND_IDLE) {
    1718           0 :                 _ctclient_msg(NULL, cmd->con, "ct_fetch", 1, 1, 1, 155, "");
    1719           0 :                 return CS_FAIL;
    1720             :         }
    1721             : 
    1722       14268 :         if (cmd->cancel_state == _CS_CANCEL_PENDING) {
    1723           0 :                 _ct_cancel_cleanup(cmd);
    1724           0 :                 return CS_CANCELED;
    1725             :         }
    1726             : 
    1727       14268 :         if (!prows_read)
    1728           0 :                 prows_read = &rows_read_dummy;
    1729             : 
    1730       14268 :         tds = cmd->con->tds_socket;
    1731             : 
    1732             :         /*
    1733             :          * Call a special function for fetches from a cursor because
    1734             :          * the processing is too incompatible to patch into a single function
    1735             :          */
    1736       14268 :         if (cmd->command_type == CS_CUR_CMD) {
    1737         120 :                 return _ct_fetch_cursor(cmd, type, offset, option, prows_read);
    1738             :         }
    1739             : 
    1740       14148 :         *prows_read = 0;
    1741             : 
    1742       14148 :         if ( cmd->bind_count == CS_UNUSED )
    1743          98 :                 cmd->bind_count = 1;
    1744             : 
    1745             :         /* compute rows and parameter results have been pre-fetched by ct_results() */
    1746             : 
    1747       14148 :         if (cmd->row_prefetched) {
    1748          90 :                 cmd->row_prefetched = 0;
    1749          90 :                 cmd->get_data_item = 0;
    1750          90 :                 cmd->get_data_bytes_returned = 0;
    1751          90 :                 if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, 0))
    1752             :                         return CS_ROW_FAIL;
    1753          90 :                 *prows_read = 1;
    1754          90 :                 return CS_SUCCEED;
    1755             :         }
    1756             : 
    1757       14058 :         if (cmd->results_state == _CS_RES_CMD_DONE)
    1758             :                 return CS_END_DATA;
    1759       14058 :         if (cmd->curr_result_type == CS_COMPUTE_RESULT)
    1760             :                 return CS_END_DATA;
    1761       14034 :         if (cmd->curr_result_type == CS_CMD_FAIL)
    1762             :                 return CS_CMD_FAIL;
    1763             : 
    1764             : 
    1765       14034 :         marker = tds_peek(tds);
    1766       14034 :         if ((cmd->curr_result_type == CS_ROW_RESULT    && marker != TDS_ROW_TOKEN && marker != TDS_NBC_ROW_TOKEN)
    1767       13842 :         ||  (cmd->curr_result_type == CS_STATUS_RESULT && marker != TDS_RETURNSTATUS_TOKEN) )
    1768             :                 return CS_END_DATA;
    1769             : 
    1770             :         /* Array Binding Code changes start here */
    1771             : 
    1772       13586 :         for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
    1773             : 
    1774       13820 :                 ret = tds_process_tokens(tds, &ret_type, NULL,
    1775             :                                          TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
    1776             : 
    1777       13820 :                 tdsdump_log(TDS_DBG_FUNC, "inside ct_fetch() process_row_tokens returned %d\n", ret);
    1778             : 
    1779       13820 :                 switch (ret) {
    1780       13812 :                         case TDS_SUCCESS:
    1781       13812 :                                 if (ret_type == TDS_ROW_RESULT || ret_type == TDS_COMPUTE_RESULT) {
    1782       13782 :                                         cmd->get_data_item = 0;
    1783       13782 :                                         cmd->get_data_bytes_returned = 0;
    1784       13782 :                                         if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, temp_count))
    1785             :                                                 return CS_ROW_FAIL;
    1786       13782 :                                         (*prows_read)++;
    1787             :                                         break;
    1788             :                                 }
    1789             :                         case TDS_NO_MORE_RESULTS:
    1790             :                                 return CS_END_DATA;
    1791             :                                 break;
    1792             : 
    1793           8 :                         case TDS_CANCELLED:
    1794           8 :                                 cmd->cancel_state = _CS_CANCEL_NOCANCEL;
    1795           8 :                                 return CS_CANCELED;
    1796             :                                 break;
    1797             : 
    1798           0 :                         default:
    1799           0 :                                 return CS_FAIL;
    1800             :                                 break;
    1801             :                 }
    1802             : 
    1803             :                 /* have we reached the end of the rows ? */
    1804             : 
    1805       13782 :                 marker = tds_peek(tds);
    1806             : 
    1807       27564 :                 if (cmd->curr_result_type == CS_ROW_RESULT && marker != TDS_ROW_TOKEN && marker != TDS_NBC_ROW_TOKEN)
    1808             :                         break;
    1809             : 
    1810             :         }
    1811             : 
    1812             :         /* Array Binding Code changes end here */
    1813             : 
    1814             :         return CS_SUCCEED;
    1815             : }
    1816             : 
    1817             : static CS_RETCODE
    1818         120 : _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read)
    1819             : {
    1820             :         TDSSOCKET * tds;
    1821             :         TDSCURSOR *cursor;
    1822             :         TDS_INT restype;
    1823             :         TDSRET ret;
    1824             :         TDS_INT temp_count;
    1825             :         TDS_INT done_flags;
    1826         120 :         TDS_INT rows_this_fetch = 0;
    1827             : 
    1828         120 :         tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor(%p, %d, %d, %d, %p)\n", cmd, type, offset, option, rows_read);
    1829             : 
    1830         120 :         if (!cmd->con || !cmd->con->tds_socket)
    1831             :                 return CS_FAIL;
    1832             : 
    1833         120 :         tds = cmd->con->tds_socket;
    1834             : 
    1835         120 :         if (rows_read)
    1836         120 :                 *rows_read = 0;
    1837             : 
    1838             :         /* taking a copy of the cmd->bind_count value. */
    1839         120 :         temp_count = cmd->bind_count;
    1840             : 
    1841         120 :         if ( cmd->bind_count == CS_UNUSED )
    1842          16 :                 cmd->bind_count = 1;
    1843             : 
    1844         120 :         cursor = cmd->cursor;
    1845         120 :         if (!cursor) {
    1846           0 :                 tdsdump_log(TDS_DBG_FUNC, "ct_fetch_cursor() : cursor not present\n");
    1847             :                 return CS_FAIL;
    1848             :         }
    1849             : 
    1850             :         /* currently we are placing this restriction on cursor fetches.  */
    1851             :         /* the alternatives are too awful to contemplate at the moment   */
    1852             :         /* i.e. buffering all the rows from the fetch internally...      */
    1853             : 
    1854         120 :         if (cmd->bind_count < cursor->cursor_rows) {
    1855           0 :                 tdsdump_log(TDS_DBG_WARN, "_ct_fetch_cursor(): bind count must equal cursor rows \n");
    1856             :                 return CS_FAIL;
    1857             :         }
    1858             : 
    1859         120 :         if (TDS_FAILED(tds_cursor_fetch(tds, cursor, TDS_CURSOR_FETCH_NEXT, 0))) {
    1860           0 :                 tdsdump_log(TDS_DBG_WARN, "ct_fetch(): cursor fetch failed\n");
    1861             :                 return CS_FAIL;
    1862             :         }
    1863         120 :         cursor->status.fetch = TDS_CURSOR_STATE_SENT;
    1864             : 
    1865         366 :         while ((tds_process_tokens(tds, &restype, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
    1866         126 :                 switch (restype) {
    1867             :                         case CS_ROWFMT_RESULT:
    1868             :                                 break;
    1869             :                         case CS_ROW_RESULT:
    1870          96 :                                 for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
    1871             : 
    1872          96 :                                         ret = tds_process_tokens(tds, &restype, NULL,
    1873             :                                                          TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
    1874             : 
    1875          96 :                                         tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor() tds_process_tokens returned %d\n", ret);
    1876             : 
    1877          96 :                                         if (ret == TDS_SUCCESS && (restype == TDS_ROW_RESULT || restype == TDS_COMPUTE_RESULT)) {
    1878          96 :                                                 cmd->get_data_item = 0;
    1879          96 :                                                 cmd->get_data_bytes_returned = 0;
    1880          96 :                                                 if (restype == TDS_ROW_RESULT) {
    1881          96 :                                                         if (_ct_bind_data(cmd->con->ctx, tds->current_results,
    1882             :                                                                           tds->current_results, temp_count))
    1883             :                                                                 return CS_ROW_FAIL;
    1884          96 :                                                         if (rows_read)
    1885          96 :                                                                 *rows_read = *rows_read + 1;
    1886          96 :                                                         rows_this_fetch++;
    1887             :                                                 }
    1888             :                                         } else {
    1889           0 :                                                 if (TDS_FAILED(ret))
    1890             :                                                         return CS_FAIL;
    1891             :                                                 break;
    1892             :                                         }
    1893             :                                 }
    1894             :                                 break;
    1895             :                         case TDS_DONE_RESULT:
    1896             :                                 break;
    1897             :                 }
    1898             :         }
    1899         120 :         if (rows_this_fetch)
    1900             :                 return CS_SUCCEED;
    1901             : 
    1902          24 :         cmd->results_state = _CS_RES_CMD_SUCCEED;
    1903          24 :         return CS_END_DATA;
    1904             : }
    1905             : 
    1906             : 
    1907             : int
    1908       14976 : _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset)
    1909             : {
    1910             :         TDSCOLUMN *curcol, *bindcol;
    1911             :         unsigned char *src, *dest;
    1912       14976 :         int i, result = 0;
    1913             :         CS_DATAFMT_COMMON srcfmt, destfmt;
    1914             :         TDS_INT datalen_dummy, *pdatalen;
    1915             :         TDS_SMALLINT nullind_dummy, *nullind;
    1916             : 
    1917       14976 :         tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data(%p, %p, %p, %d)\n", ctx, resinfo, bindinfo, offset);
    1918             : 
    1919       93733 :         for (i = 0; i < resinfo->num_cols; i++) {
    1920             : 
    1921             :                 CS_RETCODE ret;
    1922             :                 CONV_RESULT convert_buffer;
    1923             :                 CS_INT srctype;
    1924             : 
    1925       93733 :                 curcol = resinfo->columns[i];
    1926       93733 :                 bindcol = bindinfo->columns[i];
    1927             : 
    1928       93733 :                 tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data(): column %d is type %d and has length %d\n",
    1929           0 :                                                 i, curcol->column_type, curcol->column_cur_size);
    1930             : 
    1931       93733 :                 if (curcol->column_hidden)
    1932       90664 :                         continue;
    1933             : 
    1934             :                 /*
    1935             :                  * Retrieve the initial bound column_varaddress and increment it if offset specified
    1936             :                  */
    1937             : 
    1938       93661 :                 dest = (unsigned char *) bindcol->column_varaddr;
    1939       93661 :                 if (dest)
    1940        3269 :                         dest += offset * bindcol->column_bindlen;
    1941             : 
    1942       93661 :                 nullind = &nullind_dummy;
    1943       93661 :                 if (bindcol->column_nullbind) {
    1944        2301 :                         nullind = bindcol->column_nullbind;
    1945             :                         assert(nullind);
    1946        2301 :                         nullind += offset;
    1947             :                 }
    1948       93661 :                 pdatalen = &datalen_dummy;
    1949       93661 :                 if (bindcol->column_lenbind) {
    1950        3269 :                         pdatalen = bindcol->column_lenbind;
    1951             :                         assert(pdatalen);
    1952        3269 :                         pdatalen += offset;
    1953             :                 }
    1954             : 
    1955             :                 /* no destination specified */
    1956       93661 :                 if (!dest) {
    1957       90392 :                         *pdatalen = 0;
    1958       90392 :                         continue;
    1959             :                 }
    1960             : 
    1961             :                 /* NULL column */
    1962        3269 :                 if (curcol->column_cur_size < 0) {
    1963         128 :                         *nullind = -1;
    1964         128 :                         *pdatalen = 0;
    1965         128 :                         continue;
    1966             :                 }
    1967             : 
    1968        3141 :                 src = curcol->column_data;
    1969        3141 :                 if (is_blob_col(curcol))
    1970         452 :                         src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
    1971             : 
    1972        3141 :                 srctype = _cs_convert_not_client(ctx, curcol, &convert_buffer, &src);
    1973        3141 :                 if (srctype == CS_ILLEGAL_TYPE)
    1974        3077 :                         srctype = _ct_get_client_type(curcol, false);
    1975        3141 :                 if (srctype == CS_ILLEGAL_TYPE) {
    1976           0 :                         result = 1;
    1977           0 :                         continue;
    1978             :                 }
    1979             : 
    1980        3141 :                 srcfmt.datatype  = srctype;
    1981        3141 :                 srcfmt.maxlength = curcol->column_cur_size;
    1982             : 
    1983        3141 :                 destfmt.datatype = bindcol->column_bindtype;
    1984        3141 :                 destfmt.maxlength = bindcol->column_bindlen;
    1985        3141 :                 destfmt.format = bindcol->column_bindfmt;
    1986             : 
    1987             :                 /* if convert return FAIL mark error but process other columns */
    1988        3141 :                 ret = _cs_convert(ctx, &srcfmt, src, &destfmt, dest, pdatalen);
    1989        3141 :                 if (ret != CS_SUCCEED) {
    1990           0 :                         tdsdump_log(TDS_DBG_FUNC, "cs_convert-result = %d\n", ret);
    1991           0 :                         result = 1;
    1992           0 :                         tdsdump_log(TDS_DBG_INFO1, "error: converted only %d bytes for type %d \n",
    1993             :                                                         *pdatalen, srctype);
    1994             :                 }
    1995             : 
    1996        3141 :                 *nullind = 0;
    1997             :         }
    1998       14976 :         return result;
    1999             : }
    2000             : 
    2001             : CS_RETCODE
    2002        1104 : ct_cmd_drop(CS_COMMAND * cmd)
    2003             : {
    2004             :         CS_CONNECTION *con;
    2005             : 
    2006        1104 :         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop(%p)\n", cmd);
    2007             : 
    2008        1104 :         if (cmd) {
    2009        1104 :                 free(cmd->query);
    2010        1104 :                 if (cmd->input_params)
    2011           0 :                         param_clear(cmd->input_params);
    2012        1104 :                 free(cmd->userdata);
    2013        1104 :                 if (cmd->rpc) {
    2014           0 :                         if (cmd->rpc->param_list)
    2015           0 :                                 param_clear(cmd->rpc->param_list);
    2016           0 :                         free(cmd->rpc->name);
    2017           0 :                         free(cmd->rpc);
    2018             :                 }
    2019        1104 :                 free(cmd->iodesc);
    2020             : 
    2021             :                 /* now remove this command from the list of commands in the connection */
    2022        1104 :                 con = cmd->con;
    2023        1104 :                 if (con) {
    2024             :                         CS_COMMAND **pvictim;
    2025             : 
    2026        2240 :                         for (pvictim = &con->cmds; *pvictim != cmd; ) {
    2027          32 :                                 if (!*pvictim) {
    2028           0 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : cannot find command entry in list \n");
    2029             :                                         return CS_FAIL;
    2030             :                                 }
    2031          32 :                                 pvictim = &(*pvictim)->next;
    2032             :                         }
    2033             :                         /* remove from list */
    2034        1104 :                         *pvictim = cmd->next;
    2035             :                         cmd->next = NULL;
    2036             :                 }
    2037             : 
    2038        1104 :                 free(cmd);
    2039             :         }
    2040             :         return CS_SUCCEED;
    2041             : }
    2042             : 
    2043             : CS_RETCODE
    2044        1072 : ct_close(CS_CONNECTION * con, CS_INT option)
    2045             : {
    2046        1072 :         tdsdump_log(TDS_DBG_FUNC, "ct_close(%p, %d)\n", con, option);
    2047             : 
    2048        1072 :         tds_close_socket(con->tds_socket);
    2049        1072 :         tds_free_socket(con->tds_socket);
    2050        1072 :         con->tds_socket = NULL;
    2051        1072 :         return CS_SUCCEED;
    2052             : }
    2053             : 
    2054             : CS_RETCODE
    2055        1088 : ct_con_drop(CS_CONNECTION * con)
    2056             : {
    2057             :         CS_COMMAND *cmd, *next_cmd;
    2058             : 
    2059        1088 :         tdsdump_log(TDS_DBG_FUNC, "ct_con_drop(%p)\n", con);
    2060             : 
    2061        1088 :         if (con) {
    2062        1088 :                 free(con->userdata);
    2063        1088 :                 if (con->tds_login)
    2064        1088 :                         tds_free_login(con->tds_login);
    2065        1088 :                 while ((cmd = con->cmds) != NULL) {
    2066           0 :                         next_cmd  = cmd->next;
    2067           0 :                         cmd->con  = NULL;
    2068           0 :                         cmd->dyn  = NULL;
    2069           0 :                         cmd->next = NULL;
    2070           0 :                         con->cmds = next_cmd;
    2071             :                 }
    2072        1104 :                 while (con->dynlist)
    2073          16 :                         _ct_deallocate_dynamic(con, con->dynlist);
    2074        1088 :                 if (con->locale)
    2075           0 :                         _cs_locale_free(con->locale);
    2076        1088 :                 tds_free_socket(con->tds_socket);
    2077             :                 con->tds_socket = NULL;
    2078        1088 :                 free(con->server_addr);
    2079        1088 :                 free(con);
    2080             :         }
    2081        1088 :         return CS_SUCCEED;
    2082             : }
    2083             : 
    2084             : int
    2085        5979 : _ct_get_client_type(const TDSCOLUMN *col, bool describe)
    2086             : {
    2087        5979 :         TDS_SERVER_TYPE type = col->column_type;
    2088        5979 :         TDS_INT size = col->column_size;
    2089             : 
    2090        5979 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_client_type(type %d, user %d, size %d)\n", type, col->column_usertype, size);
    2091             : 
    2092        5979 :         if (type == SYBVARIANT && describe)
    2093             :                 return CS_CHAR_TYPE;
    2094             : 
    2095        5973 :         if (type == SYBVARIANT) {
    2096         770 :                 type = ((const TDSVARIANT *) col->column_data)->type;
    2097         770 :                 size = ((const TDSVARIANT *) col->column_data)->size;
    2098             :         }
    2099             : 
    2100        5973 :         switch (tds_get_conversion_type(type, size)) {
    2101             :         case SYBBIT:
    2102             :                 return CS_BIT_TYPE;
    2103             :                 break;
    2104        1844 :         case SYBCHAR:
    2105             :         case SYBVARCHAR:
    2106        1844 :                 return CS_CHAR_TYPE;
    2107             :                 break;
    2108         164 :         case SYBINT8:
    2109         164 :                 return CS_BIGINT_TYPE;
    2110             :                 break;
    2111         635 :         case SYBINT4:
    2112         635 :                 return CS_INT_TYPE;
    2113             :                 break;
    2114         590 :         case SYBINT2:
    2115         590 :                 return CS_SMALLINT_TYPE;
    2116             :                 break;
    2117         192 :         case SYBINT1:
    2118         192 :                 return CS_TINYINT_TYPE;
    2119             :                 break;
    2120         192 :         case SYBREAL:
    2121         192 :                 return CS_REAL_TYPE;
    2122             :                 break;
    2123         240 :         case SYBFLT8:
    2124         240 :                 return CS_FLOAT_TYPE;
    2125             :                 break;
    2126         240 :         case SYBMONEY:
    2127         240 :                 return CS_MONEY_TYPE;
    2128             :                 break;
    2129         192 :         case SYBMONEY4:
    2130         192 :                 return CS_MONEY4_TYPE;
    2131             :                 break;
    2132         372 :         case SYBDATETIME:
    2133         372 :                 return CS_DATETIME_TYPE;
    2134             :                 break;
    2135         216 :         case SYBDATETIME4:
    2136         216 :                 return CS_DATETIME4_TYPE;
    2137             :                 break;
    2138         150 :         case SYBNUMERIC:
    2139         150 :                 return CS_NUMERIC_TYPE;
    2140             :                 break;
    2141         128 :         case SYBDECIMAL:
    2142         128 :                 return CS_DECIMAL_TYPE;
    2143             :                 break;
    2144         160 :         case SYBBINARY:
    2145             :         case SYBVARBINARY:
    2146         160 :                 return CS_BINARY_TYPE;
    2147             :                 break;
    2148          16 :         case SYBIMAGE:
    2149          16 :                 return CS_IMAGE_TYPE;
    2150             :                 break;
    2151          38 :         case SYBTEXT:
    2152          38 :                 return CS_TEXT_TYPE;
    2153             :                 break;
    2154          32 :         case SYBUNIQUE:
    2155          32 :                 return CS_UNIQUE_TYPE;
    2156             :                 break;
    2157           4 :         case SYBLONGCHAR:
    2158           4 :                 return CS_LONGCHAR_TYPE;
    2159             :                 break;
    2160          32 :         case SYBLONGBINARY:
    2161          32 :                 if (col->column_usertype == USER_UNICHAR_TYPE || col->column_usertype == USER_UNIVARCHAR_TYPE)
    2162             :                         return CS_UNICHAR_TYPE;
    2163          32 :                 return CS_LONGBINARY_TYPE;
    2164             :                 break;
    2165          48 :         case SYBUINT1:
    2166          48 :                 return CS_TINYINT_TYPE;
    2167             :                 break;
    2168          48 :         case SYBUINT2:
    2169          48 :                 return CS_USMALLINT_TYPE;
    2170             :                 break;
    2171          48 :         case SYBUINT4:
    2172          48 :                 return CS_UINT_TYPE;
    2173             :                 break;
    2174          48 :         case SYBUINT8:
    2175          48 :                 return CS_UBIGINT_TYPE;
    2176             :                 break;
    2177          48 :         case SYBDATE:
    2178          48 :                 return CS_DATE_TYPE;
    2179             :                 break;
    2180          48 :         case SYBTIME:
    2181          48 :                 return CS_TIME_TYPE;
    2182             :                 break;
    2183          16 :         case SYB5BIGTIME:
    2184          16 :                 return CS_BIGTIME_TYPE;
    2185             :                 break;
    2186          16 :         case SYB5BIGDATETIME:
    2187          16 :                 return CS_BIGDATETIME_TYPE;
    2188             :                 break;
    2189           0 :         case SYBVARIANT:
    2190           0 :                 return CS_CHAR_TYPE;
    2191             :                 break;
    2192             :         /* handled by _cs_convert_not_client */
    2193             :         case SYBMSDATE:
    2194             :         case SYBMSTIME:
    2195             :         case SYBMSDATETIME2:
    2196             :         case SYBMSDATETIMEOFFSET:
    2197             :                 break;
    2198             : 
    2199             :         /* nullable types should not occur here... */
    2200             :         case SYBBITN:
    2201             :         case SYBINTN:
    2202             :         case SYBDATETIMN:
    2203             :         case SYBFLTN:
    2204             :         case SYBMONEYN:
    2205             :         case SYBUINTN:
    2206             :         case SYBTIMEN:
    2207             :         case SYBDATEN:
    2208             : 
    2209             :         /* handled by tds_get_conversion_type */
    2210             :         case SYB5INT8:
    2211           0 :                 assert(0);
    2212             : 
    2213             :         /* TODO... */
    2214             :         case SYBVOID:
    2215             :         case SYBNVARCHAR:
    2216             :         case XSYBVARCHAR:
    2217             :         case XSYBNVARCHAR:
    2218             :         case XSYBNCHAR:
    2219             :         case XSYBVARBINARY:
    2220             :         case XSYBBINARY:
    2221             :         case SYBMSUDT:
    2222             :         case SYBMSXML:
    2223             :         case SYBMSTABLE:
    2224             :         case SYBINTERVAL:
    2225             :         case SYBSINT1:
    2226             :         case SYBUNITEXT:
    2227             :         case SYBXML:
    2228             :         case SYBNTEXT:
    2229             :                 break;
    2230             :         }
    2231             : 
    2232          64 :         return _cs_convert_not_client(NULL, col, NULL, NULL);
    2233             : }
    2234             : 
    2235             : TDS_SERVER_TYPE
    2236     1506938 : _ct_get_server_type(TDSSOCKET *tds, int datatype)
    2237             : {
    2238     1506938 :         tdsdump_log(TDS_DBG_FUNC, "_ct_get_server_type(%d)\n", datatype);
    2239             : 
    2240     1506938 :         switch (datatype) {
    2241             :         case CS_IMAGE_TYPE:             return SYBIMAGE;
    2242         840 :         case CS_BINARY_TYPE:            return SYBBINARY;
    2243         832 :         case CS_BIT_TYPE:               return SYBBIT;
    2244        6557 :         case CS_CHAR_TYPE:              return SYBCHAR;
    2245         760 :         case CS_VARCHAR_TYPE:           return SYBVARCHAR;
    2246          24 :         case CS_LONG_TYPE:
    2247             :         case CS_UBIGINT_TYPE:
    2248          24 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT8))
    2249             :                         return SYBUINT8;
    2250             :                 return SYBINT8;
    2251          24 :         case CS_UINT_TYPE:
    2252          24 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT4))
    2253             :                         return SYBUINT4;
    2254             :                 return SYBINT4;
    2255          24 :         case CS_USMALLINT_TYPE:
    2256          24 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT2))
    2257             :                         return SYBUINT2;
    2258             :                 return SYBINT2;
    2259          84 :         case CS_BIGINT_TYPE:            return SYBINT8;
    2260        2135 :         case CS_INT_TYPE:               return SYBINT4;
    2261        1340 :         case CS_SMALLINT_TYPE:          return SYBINT2;
    2262         952 :         case CS_TINYINT_TYPE:           return SYBINT1;
    2263         912 :         case CS_REAL_TYPE:              return SYBREAL;
    2264        1024 :         case CS_FLOAT_TYPE:             return SYBFLT8;
    2265        1048 :         case CS_MONEY_TYPE:             return SYBMONEY;
    2266         984 :         case CS_MONEY4_TYPE:            return SYBMONEY4;
    2267        1032 :         case CS_DATETIME_TYPE:          return SYBDATETIME;
    2268         884 :         case CS_DATETIME4_TYPE:         return SYBDATETIME4;
    2269         822 :         case CS_NUMERIC_TYPE:           return SYBNUMERIC;
    2270         800 :         case CS_DECIMAL_TYPE:           return SYBDECIMAL;
    2271         704 :         case CS_VARBINARY_TYPE:         return SYBVARBINARY;
    2272         696 :         case CS_TEXT_TYPE:              return SYBTEXT;
    2273          16 :         case CS_UNIQUE_TYPE:            return SYBUNIQUE;
    2274         664 :         case CS_LONGBINARY_TYPE:        return SYBLONGBINARY;
    2275         384 :         case CS_UNICHAR_TYPE:           return SYBVARCHAR;
    2276         740 :         case CS_LONGCHAR_TYPE:
    2277         740 :                 if (!tds || IS_TDS7_PLUS(tds->conn))
    2278             :                         return SYBVARCHAR;
    2279           0 :                 return SYBLONGCHAR;
    2280         680 :         case CS_DATE_TYPE:
    2281         680 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_DATE))
    2282             :                         return SYBDATE;
    2283             :                 return SYBDATETIME;
    2284         664 :         case CS_TIME_TYPE:
    2285         664 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_TIME))
    2286             :                         return SYBTIME;
    2287             :                 return SYBDATETIME;
    2288          40 :         case CS_BIGDATETIME_TYPE:
    2289          40 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_BIGDATETIME))
    2290             :                         return SYB5BIGDATETIME;
    2291             :                 return SYBDATETIME;
    2292          24 :         case CS_BIGTIME_TYPE:
    2293          24 :                 if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_BIGTIME))
    2294             :                         return SYB5BIGTIME;
    2295             :                 return SYBDATETIME;
    2296             : 
    2297             :         /* TODO */
    2298     1480496 :         case CS_SENSITIVITY_TYPE:
    2299             :         case CS_BOUNDARY_TYPE:
    2300             :         case CS_VOID_TYPE:
    2301             :         case CS_USHORT_TYPE:
    2302             :         case CS_BLOB_TYPE:
    2303             :         case CS_UNITEXT_TYPE:
    2304             :         case CS_XML_TYPE:
    2305             :         case CS_TEXTLOCATOR_TYPE:
    2306             :         case CS_IMAGELOCATOR_TYPE:
    2307             :         case CS_UNITEXTLOCATOR_TYPE:
    2308             :         default:
    2309     1480496 :                 return TDS_INVALID_TYPE;
    2310             :                 break;
    2311             :         }
    2312             : }
    2313             : 
    2314             : CS_RETCODE
    2315        1201 : ct_cancel(CS_CONNECTION * conn, CS_COMMAND * cmd, CS_INT type)
    2316             : {
    2317             :         CS_RETCODE ret;
    2318             :         CS_COMMAND *cmds;
    2319             :         CS_COMMAND *conn_cmd;
    2320             :         CS_CONNECTION *cmd_conn;
    2321             : 
    2322        1201 :         tdsdump_log(TDS_DBG_FUNC, "ct_cancel(%p, %p, %d)\n", conn, cmd, type);
    2323             : 
    2324             :         /*
    2325             :          * Comments taken from Sybase ct-library reference manual
    2326             :          * ------------------------------------------------------
    2327             :          *
    2328             :          * "To cancel current results, an application calls ct_cancel
    2329             :          *  with type as CT_CANCEL CURRENT. This is equivalent to
    2330             :          *  calling ct_fetch until it returns CS_END_DATA"
    2331             :          *
    2332             :          * "For CS_CANCEL_CURRENT cancels, cmd must be supplied"
    2333             :          * "For CS_CANCEL_CURRENT cancels, connection must be NULL"
    2334             :          */
    2335             : 
    2336        1201 :         if (type == CS_CANCEL_CURRENT) {
    2337             : 
    2338             : 
    2339           0 :                 tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_CURRENT\n");
    2340           0 :                 if (conn || !cmd)
    2341             :                         return CS_FAIL;
    2342             : 
    2343             : 
    2344           0 :                 if (!_ct_fetchable_results(cmd)) {
    2345           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() no fetchable results - return()\n");
    2346             :                         return CS_SUCCEED;
    2347             :                 }
    2348             : 
    2349           0 :                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() - fetching results()\n");
    2350             :                 do {
    2351           0 :                         ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL);
    2352           0 :                 } while ((ret == CS_SUCCEED) || (ret == CS_ROW_FAIL));
    2353             : 
    2354           0 :                 if (cmd->con && cmd->con->tds_socket)
    2355           0 :                         tds_free_all_results(cmd->con->tds_socket);
    2356             : 
    2357           0 :                 if (ret == CS_END_DATA) {
    2358             :                         return CS_SUCCEED;
    2359             :                 }
    2360           0 :                 return CS_FAIL;
    2361             :         }
    2362             : 
    2363             :         /*
    2364             :          * Comments taken from Sybase ct-library reference manual
    2365             :          * ------------------------------------------------------
    2366             :          *
    2367             :          * "To cancel the current command and all results generated
    2368             :          *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
    2369             :          *  CS_CANCEL_ALL. Both of these calls tell client library
    2370             :          *  to :
    2371             :          *  * Send an attention to the server
    2372             :          *  * discard any results already generated by the command
    2373             :          *  Both types of cancel return CS_SUCCEED immediately, w/o
    2374             :          *  sending an attention, if no command is in progress.
    2375             :          *  If an application has not yet called ct_send to send an
    2376             :          *  initiated command, a CS_CANCEL_ATTN has no effect.
    2377             :          *
    2378             :          *  If a command has been sent and ct_results has not been
    2379             :          *  called, a ct_cancel (CS_CANCEL_ATTN) has no effect."
    2380             :          *
    2381             :          * "For CS_CANCEL_ATTN cancels, one of connection or cmd
    2382             :          *  must be NULL. if cmd is supplied and connection is NULL
    2383             :          *  the cancel operation applies only to the command pend-
    2384             :          *  ing for this command structure. If cmd is NULL and
    2385             :          *  connection is supplied, the cancel operation applies to
    2386             :          *  all commands pending for this connection.
    2387             :          */
    2388             : 
    2389        1201 :         if (type == CS_CANCEL_ATTN) {
    2390          49 :                 if ((conn && cmd) || (!conn && !cmd)) {
    2391             :                         return CS_FAIL;
    2392             :                 }
    2393          49 :                 if (cmd) {
    2394          49 :                         tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with cmd\n");
    2395          49 :                         cmd_conn = cmd->con;
    2396          49 :                         switch (cmd->command_state) {
    2397           0 :                                 case _CS_COMMAND_IDLE:
    2398             :                                 case _CS_COMMAND_READY:
    2399           0 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
    2400             :                                         break;
    2401          49 :                                 case _CS_COMMAND_SENT:
    2402          49 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT results_state %d\n",
    2403             :                                                                    cmd->results_state);
    2404          49 :                                         if (cmd->results_state != _CS_RES_NONE) {
    2405          49 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
    2406          49 :                                                 tds_send_cancel(cmd_conn->tds_socket);
    2407          49 :                                                 cmd->cancel_state = _CS_CANCEL_PENDING;
    2408             :                                         }
    2409             :                                         break;
    2410             :                         }
    2411             :                 }
    2412          49 :                 if (conn) {
    2413           0 :                         tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with connection\n");
    2414           0 :                         for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
    2415           0 :                                 conn_cmd = cmds;
    2416           0 :                                 switch (conn_cmd->command_state) {
    2417           0 :                                         case _CS_COMMAND_IDLE:
    2418             :                                         case _CS_COMMAND_READY:
    2419           0 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
    2420             :                                                 break;
    2421           0 :                                         case _CS_COMMAND_SENT:
    2422           0 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
    2423           0 :                                                 if (conn_cmd->results_state != _CS_RES_NONE) {
    2424           0 :                                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
    2425           0 :                                                         tds_send_cancel(conn->tds_socket);
    2426           0 :                                                         conn_cmd->cancel_state = _CS_CANCEL_PENDING;
    2427             :                                                 }
    2428             :                                         break;
    2429             :                                 }
    2430             :                         }
    2431             :                 }
    2432             : 
    2433             :                 return CS_SUCCEED;
    2434             :         }
    2435             : 
    2436             :         /*
    2437             :          * Comments taken from Sybase ct-library reference manual
    2438             :          * ------------------------------------------------------
    2439             :          *
    2440             :          * "To cancel the current command and all results generated
    2441             :          *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
    2442             :          *  CS_CANCEL_ALL. Both of these calls tell client library
    2443             :          *  to :
    2444             :          *  * Send an attention to the server
    2445             :          *  * discard any results already generated by the command
    2446             :          *  Both types of cancel return CS_SUCCEED immediately, w/o
    2447             :          *  sending an attention, if no command is in progress.
    2448             :          *
    2449             :          *  If an application has not yet called ct_send to send an
    2450             :          *  initiated command, a CS_CANCEL_ALL cancel discards the
    2451             :          *  initiated command without sending an attention to the
    2452             :          *  server.
    2453             :          *
    2454             :          *  CS_CANCEL_ALL leaves the command structure in a 'clean'
    2455             :          *  state, available for use in another operation.
    2456             :          *
    2457             :          * "For CS_CANCEL_ALL cancels, one of connection or cmd
    2458             :          *  must be NULL. if cmd is supplied and connection is NULL
    2459             :          *  the cancel operation applies only to the command pend-
    2460             :          *  ing for this command structure. If cmd is NULL and
    2461             :          *  connection is supplied, the cancel operation applies to
    2462             :          *  all commands pending for this connection.
    2463             :          */
    2464             : 
    2465        1152 :         if (type == CS_CANCEL_ALL) {
    2466             : 
    2467        1152 :                 if ((conn && cmd) || (!conn && !cmd)) {
    2468             :                         return CS_FAIL;
    2469             :                 }
    2470        1152 :                 if (cmd) {
    2471           0 :                         tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with cmd\n");
    2472           0 :                         cmd_conn = cmd->con;
    2473           0 :                         switch (cmd->command_state) {
    2474           0 :                                 case _CS_COMMAND_IDLE:
    2475             :                                 case _CS_COMMAND_BUILDING:
    2476             :                                 case _CS_COMMAND_READY:
    2477           0 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
    2478           0 :                                         _ct_initialise_cmd(cmd);
    2479           0 :                                         break;
    2480           0 :                                 case _CS_COMMAND_SENT:
    2481           0 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
    2482           0 :                                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
    2483           0 :                                         tds_send_cancel(cmd_conn->tds_socket);
    2484           0 :                                         tds_process_cancel(cmd_conn->tds_socket);
    2485           0 :                                         _ct_initialise_cmd(cmd);
    2486           0 :                                         cmd->cancel_state = _CS_CANCEL_PENDING;
    2487           0 :                                         break;
    2488             :                         }
    2489             :                 }
    2490        1152 :                 if (conn) {
    2491        1152 :                         tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with connection\n");
    2492        2296 :                         for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
    2493        1144 :                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() cancelling a command for a connection\n");
    2494        1144 :                                 conn_cmd = cmds;
    2495        1144 :                                 switch (conn_cmd->command_state) {
    2496        1124 :                                         case _CS_COMMAND_IDLE:
    2497             :                                         case _CS_COMMAND_BUILDING:
    2498             :                                         case _CS_COMMAND_READY:
    2499        1124 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
    2500        1124 :                                                 _ct_initialise_cmd(conn_cmd);
    2501        1124 :                                                 break;
    2502          20 :                                         case _CS_COMMAND_SENT:
    2503          20 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
    2504          20 :                                                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
    2505          20 :                                                 tds_send_cancel(conn->tds_socket);
    2506          20 :                                                 tds_process_cancel(conn->tds_socket);
    2507          20 :                                                 _ct_initialise_cmd(conn_cmd);
    2508          20 :                                                 conn_cmd->cancel_state = _CS_CANCEL_PENDING;
    2509          20 :                                         break;
    2510             :                                 }
    2511             :                         }
    2512             :                 }
    2513             : 
    2514             :                 return CS_SUCCEED;
    2515             :         }
    2516             :         return CS_FAIL;
    2517             : }
    2518             : 
    2519             : static CS_RETCODE
    2520           0 : _ct_cancel_cleanup(CS_COMMAND * cmd)
    2521             : {
    2522             :         CS_CONNECTION * con;
    2523             : 
    2524           0 :         tdsdump_log(TDS_DBG_FUNC, "_ct_cancel_cleanup(%p)\n", cmd);
    2525             : 
    2526           0 :         con = cmd->con;
    2527             : 
    2528           0 :         if (con && !IS_TDSDEAD(con->tds_socket))
    2529           0 :                 tds_process_cancel(con->tds_socket);
    2530             : 
    2531           0 :         cmd->cancel_state = _CS_CANCEL_NOCANCEL;
    2532             : 
    2533           0 :         return CS_SUCCEED;
    2534             : 
    2535             : }
    2536             : 
    2537             : CS_RETCODE
    2538         488 : ct_describe(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt_arg)
    2539             : {
    2540             :         TDSSOCKET *tds;
    2541             :         TDSRESULTINFO *resinfo;
    2542             :         TDSCOLUMN *curcol;
    2543             :         CS_DATAFMT_LARGE *datafmt;
    2544             :         CS_DATAFMT_LARGE datafmt_buf;
    2545             :         CS_INT status;
    2546             : 
    2547         488 :         tdsdump_log(TDS_DBG_FUNC, "ct_describe(%p, %d, %p)\n", cmd, item, datafmt_arg);
    2548             : 
    2549         488 :         if (!cmd->con || !cmd->con->tds_socket)
    2550             :                 return CS_FAIL;
    2551             : 
    2552         488 :         datafmt = _ct_datafmt_conv_prepare(cmd->con->ctx, datafmt_arg, &datafmt_buf);
    2553         488 :         tds = cmd->con->tds_socket;
    2554         488 :         resinfo = tds->current_results;;
    2555             : 
    2556         488 :         if (item < 1 || item > resinfo->num_cols)
    2557             :                 return CS_FAIL;
    2558             : 
    2559         488 :         curcol = resinfo->columns[item - 1];
    2560             :         /* name is always null terminated */
    2561         976 :         strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
    2562         488 :         datafmt->namelen = strlen(datafmt->name);
    2563             :         /* need to turn the SYBxxx into a CS_xxx_TYPE */
    2564         488 :         datafmt->datatype = _ct_get_client_type(curcol, true);
    2565         488 :         if (datafmt->datatype == CS_ILLEGAL_TYPE) {
    2566           0 :                 _ctclient_msg(NULL, cmd->con, "ct_describe", 1, 1, 1, 4,
    2567           0 :                               "%s, %s", "column type", tds_prtype(curcol->column_type));
    2568           0 :                 return CS_FAIL;
    2569             :         }
    2570         488 :         tdsdump_log(TDS_DBG_INFO1, "ct_describe() datafmt->datatype = %d server type %d\n", datafmt->datatype,
    2571           0 :                     curcol->column_type);
    2572         488 :         if (is_numeric_type(curcol->column_type))
    2573           8 :                 datafmt->maxlength = sizeof(CS_NUMERIC);
    2574             :         else
    2575         480 :                 datafmt->maxlength = curcol->column_size;
    2576         488 :         datafmt->usertype = curcol->column_usertype;
    2577         488 :         if (datafmt->usertype == 0 && datafmt->datatype == CS_BIGDATETIME_TYPE)
    2578           0 :                 datafmt->usertype = curcol->column_type;
    2579         488 :         datafmt->precision = curcol->column_prec;
    2580         488 :         datafmt->scale = curcol->column_scale;
    2581         488 :         datafmt->format = curcol->column_bindfmt;
    2582             : 
    2583             :         /*
    2584             :          * There are other options that can be returned, but these are the
    2585             :          * only two being noted via the TDS layer.
    2586             :          */
    2587         488 :         status = 0;
    2588         488 :         if (curcol->column_nullable)
    2589         210 :                 status |= CS_CANBENULL;
    2590         488 :         if (curcol->column_identity)
    2591           0 :                 status |= CS_IDENTITY;
    2592         488 :         if (curcol->column_writeable)
    2593         268 :                 status |= CS_UPDATABLE;
    2594         488 :         if (curcol->column_key)
    2595           0 :                 status |= CS_KEY;
    2596         488 :         if (curcol->column_hidden)
    2597           0 :                 status |= CS_HIDDEN;
    2598         488 :         if (curcol->column_timestamp)
    2599           0 :                 status |= CS_TIMESTAMP;
    2600         488 :         datafmt->status = status;
    2601             : 
    2602         488 :         datafmt->count = 1;
    2603         488 :         datafmt->locale = NULL;
    2604             : 
    2605         488 :         _ct_datafmt_conv_back(datafmt_arg, datafmt);
    2606         488 :         return CS_SUCCEED;
    2607             : }
    2608             : 
    2609             : CS_RETCODE
    2610         482 : ct_res_info(CS_COMMAND * cmd, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
    2611             : {
    2612             :         TDSSOCKET *tds;
    2613             :         TDSRESULTINFO *resinfo;
    2614             :         TDSCOLUMN *curcol;
    2615             :         CS_INT int_val;
    2616             :         int i;
    2617             : 
    2618         482 :         tdsdump_log(TDS_DBG_FUNC, "ct_res_info(%p, %d, %p, %d, %p)\n", cmd, type, buffer, buflen, out_len);
    2619             : 
    2620         482 :         if (!cmd->con || !cmd->con->tds_socket)
    2621             :                 return CS_FAIL;
    2622             : 
    2623         482 :         tds = cmd->con->tds_socket;
    2624         482 :         resinfo = tds->current_results;
    2625             : 
    2626         482 :         switch (type) {
    2627         266 :         case CS_NUMDATA:
    2628         266 :                 int_val = 0;
    2629         266 :                 if (resinfo) {
    2630         582 :                         for (i = 0; i < resinfo->num_cols; i++) {
    2631         582 :                                 curcol = resinfo->columns[i];
    2632         582 :                                 if (!curcol->column_hidden) {
    2633         558 :                                         int_val++;
    2634             :                                 }
    2635             :                         }
    2636             :                 }
    2637         266 :                 tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of columns is %d\n", int_val);
    2638         266 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2639         266 :                 break;
    2640         208 :         case CS_ROW_COUNT:
    2641         208 :                 if (cmd->results_state == _CS_RES_STATUS)
    2642             :                         return CS_FAIL;
    2643             :                 /* 64 -> 32 bit conversion saturate to the maximum */
    2644         176 :                 int_val = tds->rows_affected > 0x7fffffff ? 0x7fffffff : (CS_INT) tds->rows_affected;
    2645         176 :                 tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of rows is %d\n", int_val);
    2646         176 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2647         176 :                 break;
    2648           8 :         default:
    2649           8 :                 _ctclient_msg(NULL, cmd->con, "ct_res_info", 1, 1, 1, 5, "%d, %s", type, "operation");
    2650           8 :                 return CS_FAIL;
    2651             :                 break;
    2652             :         }
    2653             :         return CS_SUCCEED;
    2654             : 
    2655             : }
    2656             : 
    2657             : static CS_RETCODE
    2658           0 : config_bool(CS_INT action, CS_INT *buf, bool *variable)
    2659             : {
    2660           0 :         switch (action) {
    2661           0 :         case CS_SUPPORTED:
    2662           0 :                 if (buf) {
    2663           0 :                         *buf = CS_TRUE;
    2664           0 :                         return CS_SUCCEED;
    2665             :                 }
    2666             :                 break;
    2667           0 :         case CS_SET:
    2668           0 :                 if (buf && (*buf == CS_TRUE || *buf == CS_FALSE)) {
    2669           0 :                         *variable = (*buf != CS_FALSE);
    2670           0 :                         return CS_SUCCEED;
    2671             :                 }
    2672             :                 break;
    2673           0 :         case CS_GET:
    2674           0 :                 if (buf) {
    2675           0 :                         *buf = (*variable ? CS_TRUE : CS_FALSE);
    2676           0 :                         return CS_SUCCEED;
    2677             :                 }
    2678             :                 break;
    2679           0 :         case CS_CLEAR:
    2680           0 :                 *variable = false;
    2681           0 :                 return CS_SUCCEED;
    2682             :         default:
    2683             :                 break;
    2684             :         }
    2685             :         return CS_FAIL;
    2686             : }
    2687             : 
    2688             : CS_RETCODE
    2689           0 : ct_config(CS_CONTEXT * ctx, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
    2690             : {
    2691           0 :         CS_RETCODE ret = CS_SUCCEED;
    2692           0 :         CS_INT *buf = (CS_INT *) buffer;
    2693             : 
    2694           0 :         tdsdump_log(TDS_DBG_FUNC, "ct_config(%p, %d, %d, %p, %d, %p)\n", ctx, action, property, buffer, buflen, outlen);
    2695             : 
    2696           0 :         tdsdump_log(TDS_DBG_FUNC, "ct_config() action = %s property = %d\n",
    2697             :                     CS_GET ? "CS_GET" : CS_SET ? "CS_SET" : CS_SUPPORTED ? "CS_SUPPORTED" : "CS_CLEAR", property);
    2698             : 
    2699           0 :         switch (property) {
    2700           0 :         case CS_EXPOSE_FMTS:
    2701           0 :                 ret = config_bool(action, buf, &ctx->config.cs_expose_formats);
    2702           0 :                 break;
    2703           0 :         case CS_VER_STRING: {
    2704           0 :                 ret = CS_FAIL;
    2705           0 :                 switch (action) {
    2706           0 :                         case CS_GET: {
    2707           0 :                                 if (buffer && buflen > 0 && outlen) {
    2708           0 :                                         const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
    2709           0 :                                         *outlen= snprintf((char*)buffer, buflen, "%s (%s, default tds version=%s)",
    2710             :                                                 settings->freetds_version,
    2711           0 :                                                 (settings->threadsafe ? "threadsafe" : "non-threadsafe"),
    2712             :                                                 settings->tdsver
    2713             :                                         );
    2714           0 :                                         ((char*)buffer)[buflen - 1]= 0;
    2715           0 :                                         if (*outlen < 0)
    2716           0 :                                                 *outlen = strlen((char*) buffer);
    2717             :                                         ret = CS_SUCCEED;
    2718             :                                 }
    2719             :                                 break;
    2720             :                                 default:
    2721             :                                         ret = CS_FAIL;
    2722             :                                         break;
    2723             :                                 }
    2724             :                         }
    2725             :                 }
    2726             :                 break;
    2727           0 :         case CS_VERSION:
    2728           0 :                 ret = CS_FAIL;
    2729           0 :                 switch (action) {
    2730           0 :                         case CS_GET: {
    2731           0 :                                 if (buffer && buflen > 0 && outlen) {
    2732           0 :                                         const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
    2733           0 :                                         *outlen= snprintf((char*) buffer, buflen, "%s", settings->freetds_version);
    2734           0 :                                         ((char*)buffer)[buflen - 1]= 0;
    2735           0 :                                         if (*outlen < 0)
    2736           0 :                                                 *outlen = strlen((char*) buffer);
    2737             :                                         ret = CS_SUCCEED;
    2738             :                                 }
    2739             :                                 break;
    2740             :                         default:
    2741             :                                 ret = CS_FAIL;
    2742             :                                 break;
    2743             :                         }
    2744             :                 }
    2745             :                 break;
    2746           0 :         case CS_TIMEOUT:
    2747           0 :                 switch (action) {
    2748           0 :                 case CS_SET:
    2749           0 :                         ctx->query_timeout = *((unsigned int*)buf);
    2750           0 :                         break;
    2751           0 :                 case CS_GET:
    2752           0 :                         *((unsigned int*)buf) = ctx->query_timeout;
    2753           0 :                         break;
    2754           0 :                 case CS_CLEAR:
    2755           0 :                         ctx->query_timeout = -1;
    2756           0 :                         break;
    2757             :                 default:
    2758             :                         ret = CS_FAIL;
    2759             :                         break;
    2760             :                 }
    2761             :                 break;
    2762           0 :         case CS_LOGIN_TIMEOUT:
    2763           0 :                 switch (action) {
    2764           0 :                 case CS_SET:
    2765           0 :                         ctx->login_timeout = *((unsigned int*)buf);
    2766           0 :                         break;
    2767           0 :                 case CS_GET:
    2768           0 :                         *((unsigned int*)buf) = ctx->login_timeout;
    2769           0 :                         break;
    2770           0 :                 case CS_CLEAR:
    2771           0 :                         ctx->login_timeout = -1;
    2772           0 :                         break;
    2773             :                 default:
    2774             :                         ret = CS_FAIL;
    2775             :                         break;
    2776             :                 }
    2777             :                 break;
    2778           0 :         case CS_NOTE_EMPTY_DATA:
    2779           0 :                 ret = config_bool(action, buf, &ctx->config.cs_note_empty_data);
    2780           0 :                 break;
    2781             :         default:
    2782             :                 ret = CS_SUCCEED;
    2783             :                 break;
    2784             :         }
    2785             : 
    2786           0 :         return ret;
    2787             : }
    2788             : 
    2789             : CS_RETCODE
    2790          56 : ct_cmd_props(CS_COMMAND * cmd, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
    2791             : {
    2792             :         TDSCURSOR *cursor;
    2793             :         int maxcp;
    2794             : 
    2795          56 :         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props(%p, %d, %d, %p, %d, %p)\n", cmd, action, property, buffer, buflen, outlen);
    2796             : 
    2797          56 :         if (!cmd->con || !cmd->con->tds_socket)
    2798             :                 return CS_FAIL;
    2799             : 
    2800          56 :         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property);
    2801          56 :         if (action == CS_SET) {
    2802           0 :                 switch (property) {
    2803           0 :                 case CS_USERDATA:
    2804           0 :                         free(cmd->userdata);
    2805           0 :                         cmd->userdata = (void *) malloc(buflen + 1);
    2806           0 :                         if (!cmd->userdata)
    2807             :                                 return CS_FAIL;
    2808           0 :                         tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, cmd->userdata);
    2809           0 :                         cmd->userdata_len = buflen;
    2810           0 :                         memcpy(cmd->userdata, buffer, buflen);
    2811           0 :                         break;
    2812             :                 default:
    2813             :                         break;
    2814             :                 }
    2815          56 :         }
    2816          56 :         if (action == CS_GET) {
    2817          56 :                 switch (property) {
    2818             : 
    2819          40 :                 case CS_PARENT_HANDLE:
    2820          40 :                         *(CS_CONNECTION **) buffer = cmd->con;
    2821          40 :                         break;
    2822             : 
    2823          16 :                 case CS_CUR_STATUS:
    2824             :                 case CS_CUR_ID:
    2825             :                 case CS_CUR_NAME:
    2826             :                 case CS_CUR_ROWCOUNT:
    2827             : 
    2828          16 :                         cursor = cmd->cursor;
    2829             : 
    2830          16 :                         if (!cursor) {
    2831           8 :                                 tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() : cannot find cursor\n");
    2832           8 :                                 if (property == CS_CUR_STATUS) {
    2833           8 :                                         *(CS_INT *)buffer = (CS_INT) CS_CURSTAT_NONE;
    2834           8 :                                         if (outlen) *outlen = sizeof(CS_INT);
    2835             :                                         return CS_SUCCEED;
    2836             :                                 } else {
    2837             :                                         return CS_FAIL;
    2838             :                                 }
    2839             :                         }
    2840             : 
    2841           8 :                         if (property == CS_CUR_STATUS) {
    2842           8 :                                 *(CS_INT *)buffer = cursor->srv_status;
    2843           8 :                                 if (outlen) *outlen = sizeof(CS_INT);
    2844             :                         }
    2845           8 :                         if (property == CS_CUR_ID) {
    2846           0 :                                 *(CS_INT *)buffer = cursor->cursor_id;
    2847           0 :                                 if (outlen) *outlen = sizeof(CS_INT);
    2848             :                         }
    2849           8 :                         if (property == CS_CUR_NAME) {
    2850           0 :                                 size_t len = strlen(cursor->cursor_name);
    2851           0 :                                 if ((CS_INT) len >= buflen)
    2852             :                                         return CS_FAIL;
    2853           0 :                                 strcpy((char*) buffer, cursor->cursor_name);
    2854           0 :                                 if (outlen) *outlen = len;
    2855             :                         }
    2856           8 :                         if (property == CS_CUR_ROWCOUNT) {
    2857           0 :                                 *(CS_INT *)buffer = cursor->cursor_rows;
    2858           0 :                                 if (outlen) *outlen = sizeof(CS_INT);
    2859             :                         }
    2860             :                         break;
    2861             : 
    2862           0 :                 case CS_USERDATA:
    2863           0 :                         tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", cmd->userdata);
    2864           0 :                         maxcp = cmd->userdata_len;
    2865           0 :                         if (outlen) *outlen = maxcp;
    2866           0 :                         if (maxcp > buflen)
    2867           0 :                                 maxcp = buflen;
    2868           0 :                         memcpy(buffer, cmd->userdata, maxcp);
    2869           0 :                         break;
    2870             :                 default:
    2871             :                         break;
    2872             :                 }
    2873           0 :         }
    2874             :         return CS_SUCCEED;
    2875             : }
    2876             : 
    2877             : CS_RETCODE
    2878          24 : ct_compute_info(CS_COMMAND * cmd, CS_INT type, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
    2879             : {
    2880             :         TDSSOCKET *tds;
    2881             :         TDSRESULTINFO *resinfo;
    2882             :         TDSCOLUMN *curcol;
    2883             :         CS_INT int_val;
    2884             :         CS_SMALLINT *dest_by_col_ptr;
    2885             :         TDS_SMALLINT *src_by_col_ptr;
    2886             :         int i;
    2887             : 
    2888          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_compute_info(%p, %d, %d, %p, %d, %p)\n", cmd, type, colnum, buffer, buflen, outlen);
    2889             : 
    2890          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_compute_info() type = %d, colnum = %d\n", type, colnum);
    2891             : 
    2892          24 :         if (!cmd->con || !cmd->con->tds_socket)
    2893             :                 return CS_FAIL;
    2894             : 
    2895          24 :         tds = cmd->con->tds_socket;
    2896          24 :         resinfo = tds->current_results;
    2897             : 
    2898          24 :         switch (type) {
    2899           0 :         case CS_BYLIST_LEN:
    2900           0 :                 if (!resinfo) {
    2901             :                         int_val = 0;
    2902             :                 } else {
    2903           0 :                         int_val = resinfo->by_cols;
    2904             :                 }
    2905           0 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2906           0 :                 if (outlen)
    2907           0 :                         *outlen = sizeof(CS_INT);
    2908             :                 break;
    2909           0 :         case CS_COMP_BYLIST:
    2910           0 :                 if (buflen < (CS_INT) (resinfo->by_cols * sizeof(CS_SMALLINT))) {
    2911             :                         return CS_FAIL;
    2912             :                 } else {
    2913           0 :                         dest_by_col_ptr = (CS_SMALLINT *) buffer;
    2914           0 :                         src_by_col_ptr = resinfo->bycolumns;
    2915           0 :                         for (i = 0; i < resinfo->by_cols; i++) {
    2916           0 :                                 *dest_by_col_ptr = *src_by_col_ptr;
    2917           0 :                                 dest_by_col_ptr++;
    2918           0 :                                 src_by_col_ptr++;
    2919             :                         }
    2920           0 :                         if (outlen)
    2921           0 :                                 *outlen = (resinfo->by_cols * sizeof(CS_SMALLINT));
    2922             :                 }
    2923             :                 break;
    2924           0 :         case CS_COMP_COLID:
    2925           0 :                 if (!resinfo) {
    2926             :                         int_val = 0;
    2927             :                 } else {
    2928           0 :                         curcol = resinfo->columns[colnum - 1];
    2929           0 :                         int_val = curcol->column_operand;
    2930             :                 }
    2931           0 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2932           0 :                 if (outlen)
    2933           0 :                         *outlen = sizeof(CS_INT);
    2934             :                 break;
    2935          24 :         case CS_COMP_ID:
    2936          24 :                 if (!resinfo) {
    2937             :                         int_val = 0;
    2938             :                 } else {
    2939          24 :                         int_val = resinfo->computeid;
    2940             :                 }
    2941          24 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2942          24 :                 if (outlen)
    2943           0 :                         *outlen = sizeof(CS_INT);
    2944             :                 break;
    2945           0 :         case CS_COMP_OP:
    2946           0 :                 if (!resinfo) {
    2947             :                         int_val = 0;
    2948             :                 } else {
    2949           0 :                         curcol = resinfo->columns[colnum - 1];
    2950           0 :                         int_val = _ct_map_compute_op(curcol->column_operator);
    2951             :                 }
    2952           0 :                 memcpy(buffer, &int_val, sizeof(CS_INT));
    2953           0 :                 if (outlen)
    2954           0 :                         *outlen = sizeof(CS_INT);
    2955             :                 break;
    2956           0 :         default:
    2957           0 :                 _ctclient_msg(NULL, cmd->con, "ct_compute_info", 1, 1, 1, 5, "%d, %s", type, "type");
    2958           0 :                 return CS_FAIL;
    2959             :                 break;
    2960             :         }
    2961             :         return CS_SUCCEED;
    2962             : }
    2963             : 
    2964             : CS_RETCODE
    2965          18 : ct_get_data(CS_COMMAND * cmd, CS_INT item, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
    2966             : {
    2967             :         TDSRESULTINFO *resinfo;
    2968             :         TDSCOLUMN *curcol;
    2969             :         unsigned char *src;
    2970             :         TDS_INT srclen;
    2971             : 
    2972          18 :         tdsdump_log(TDS_DBG_FUNC, "ct_get_data(%p, %d, %p, %d, %p)\n", cmd, item, buffer, buflen, outlen);
    2973             : 
    2974          18 :         tdsdump_log(TDS_DBG_FUNC, "ct_get_data() item = %d buflen = %d\n", item, buflen);
    2975             : 
    2976             :         /* basic validations... */
    2977          18 :         if (!cmd || !cmd->con || !cmd->con->tds_socket || !(resinfo = cmd->con->tds_socket->current_results))
    2978             :                 return CS_FAIL;
    2979          18 :         if (item < 1 || item > resinfo->num_cols)
    2980             :                 return CS_FAIL;
    2981          18 :         if (!buffer)
    2982             :                 return CS_FAIL;
    2983          18 :         if (buflen == CS_UNUSED)
    2984             :                 return CS_FAIL;
    2985             : 
    2986          18 :         if (cmd->cancel_state == _CS_CANCEL_PENDING) {
    2987           0 :                 _ct_cancel_cleanup(cmd);
    2988           0 :                 return CS_CANCELED;
    2989             :         }
    2990             : 
    2991             :         /* This is a new column we are being asked to return */
    2992             : 
    2993          18 :         if (item != cmd->get_data_item) {
    2994           6 :                 TDSBLOB *blob = NULL;
    2995             :                 size_t table_namelen, column_namelen;
    2996             : 
    2997             :                 /* allocate needed descriptor if needed */
    2998           6 :                 free(cmd->iodesc);
    2999           6 :                 cmd->iodesc = tds_new0(CS_IODESC, 1);
    3000           6 :                 if (!cmd->iodesc)
    3001             :                         return CS_FAIL;
    3002             : 
    3003             :                 /* reset these values */
    3004           6 :                 cmd->get_data_item = item;
    3005           6 :                 cmd->get_data_bytes_returned = 0;
    3006             : 
    3007             :                 /* get at the source data and length */
    3008           6 :                 curcol = resinfo->columns[item - 1];
    3009             : 
    3010           6 :                 src = curcol->column_data;
    3011           6 :                 if (is_blob_col(curcol)) {
    3012           6 :                         blob = (TDSBLOB *) src;
    3013           6 :                         src = (unsigned char *) blob->textvalue;
    3014             :                 }
    3015             : 
    3016             :                 /* now populate the io_desc structure for this data item */
    3017             : 
    3018           6 :                 cmd->iodesc->iotype = CS_IODATA;
    3019           6 :                 cmd->iodesc->datatype = _ct_get_client_type(curcol, true);
    3020           6 :                 cmd->iodesc->locale = cmd->con->locale;
    3021           6 :                 cmd->iodesc->usertype = curcol->column_usertype;
    3022           6 :                 cmd->iodesc->total_txtlen = curcol->column_cur_size;
    3023           6 :                 cmd->iodesc->offset = 0;
    3024           6 :                 cmd->iodesc->log_on_update = CS_FALSE;
    3025             : 
    3026             :                 /* TODO quote needed ?? */
    3027             :                 /* avoid possible buffer overflow */
    3028          12 :                 table_namelen = tds_dstr_len(&curcol->table_name);
    3029           6 :                 if (table_namelen + 2 > sizeof(cmd->iodesc->name))
    3030           0 :                         table_namelen = sizeof(cmd->iodesc->name) - 2;
    3031          12 :                 column_namelen = tds_dstr_len(&curcol->column_name);
    3032           6 :                 if (table_namelen + column_namelen + 2 > sizeof(cmd->iodesc->name))
    3033           0 :                         column_namelen = sizeof(cmd->iodesc->name) - 2 - table_namelen;
    3034             : 
    3035          24 :                 sprintf(cmd->iodesc->name, "%*.*s.%*.*s",
    3036           6 :                         (int) table_namelen, (int) table_namelen, tds_dstr_cstr(&curcol->table_name),
    3037           6 :                         (int) column_namelen, (int) column_namelen, tds_dstr_cstr(&curcol->column_name));
    3038             : 
    3039           6 :                 cmd->iodesc->namelen = strlen(cmd->iodesc->name);
    3040             : 
    3041           6 :                 if (blob && blob->valid_ptr) {
    3042           6 :                         memcpy(cmd->iodesc->timestamp, blob->timestamp, CS_TS_SIZE);
    3043           6 :                         cmd->iodesc->timestamplen = CS_TS_SIZE;
    3044           6 :                         memcpy(cmd->iodesc->textptr, blob->textptr, CS_TP_SIZE);
    3045           6 :                         cmd->iodesc->textptrlen = CS_TP_SIZE;
    3046             :                 }
    3047             :         } else {
    3048             :                 /* get at the source data */
    3049          12 :                 curcol = resinfo->columns[item - 1];
    3050          12 :                 src = curcol->column_data;
    3051          12 :                 if (is_blob_col(curcol))
    3052          12 :                         src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
    3053             : 
    3054             :         }
    3055             : 
    3056             :         /*
    3057             :          * and adjust the data and length based on
    3058             :          * what we may have already returned
    3059             :          */
    3060             : 
    3061          18 :         srclen = curcol->column_cur_size;
    3062          18 :         if (srclen < 0) {
    3063             :                 /* this is NULL */
    3064           0 :                 if (!cmd->con->ctx->config.cs_note_empty_data) {
    3065             :                         srclen = 0;
    3066             :                 } else {
    3067           0 :                         if (outlen)
    3068           0 :                                 *outlen = srclen;
    3069           0 :                         if (item < resinfo->num_cols)
    3070             :                                 return CS_END_ITEM;
    3071           0 :                         return CS_END_DATA;
    3072             :                 }
    3073             :         }
    3074             : 
    3075          18 :         src += cmd->get_data_bytes_returned;
    3076          18 :         srclen -= cmd->get_data_bytes_returned;
    3077             : 
    3078             :         /* if we have enough buffer to cope with all the data */
    3079             : 
    3080          18 :         if (buflen >= srclen) {
    3081           6 :                 memcpy(buffer, src, srclen);
    3082           6 :                 cmd->get_data_bytes_returned += srclen;
    3083           6 :                 if (outlen)
    3084           6 :                         *outlen = srclen;
    3085           6 :                 if (item < resinfo->num_cols)
    3086             :                         return CS_END_ITEM;
    3087           6 :                 return CS_END_DATA;
    3088             : 
    3089             :         }
    3090          12 :         memcpy(buffer, src, buflen);
    3091          12 :         cmd->get_data_bytes_returned += buflen;
    3092          12 :         if (outlen)
    3093          12 :                 *outlen = buflen;
    3094             :         return CS_SUCCEED;
    3095             : }
    3096             : 
    3097             : CS_RETCODE
    3098          24 : ct_send_data(CS_COMMAND * cmd, CS_VOID * buffer, CS_INT buflen)
    3099             : {
    3100             :         TDSSOCKET *tds;
    3101             : 
    3102             :         char textptr_string[35];        /* 16 * 2 + 2 (0x) + 1 */
    3103             :         char timestamp_string[19];      /* 8 * 2 + 2 (0x) + 1 */
    3104             :         char *c;
    3105             :         int s;
    3106             :         char hex2[3];
    3107             : 
    3108          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_send_data(%p, %p, %d)\n", cmd, buffer, buflen);
    3109             : 
    3110          24 :         if (!cmd->con || !cmd->con->tds_socket)
    3111             :                 return CS_FAIL;
    3112             : 
    3113          24 :         tds = cmd->con->tds_socket;
    3114             : 
    3115             :         /* basic validations */
    3116             : 
    3117          24 :         if (cmd->command_type != CS_SEND_DATA_CMD)
    3118             :                 return CS_FAIL;
    3119             : 
    3120          24 :         if (!cmd->iodesc || !cmd->iodesc->textptrlen)
    3121             :                 return CS_FAIL;
    3122             : 
    3123             :         /* first ct_send_data for this column */
    3124             : 
    3125          24 :         if (!cmd->send_data_started) {
    3126             : 
    3127             :                 /* turn the timestamp and textptr into character format */
    3128             : 
    3129             :                 c = textptr_string;
    3130             : 
    3131          96 :                 for (s = 0; s < cmd->iodesc->textptrlen; s++) {
    3132          96 :                         sprintf(hex2, "%02x", cmd->iodesc->textptr[s]);
    3133          96 :                         *c++ = hex2[0];
    3134          96 :                         *c++ = hex2[1];
    3135             :                 }
    3136           6 :                 *c = '\0';
    3137             : 
    3138           6 :                 c = timestamp_string;
    3139             : 
    3140          54 :                 for (s = 0; s < cmd->iodesc->timestamplen; s++) {
    3141          48 :                         sprintf(hex2, "%02x", cmd->iodesc->timestamp[s]);
    3142          48 :                         *c++ = hex2[0];
    3143          48 :                         *c++ = hex2[1];
    3144             :                 }
    3145           6 :                 *c = '\0';
    3146             : 
    3147             :                 /* submit the writetext command */
    3148           6 :                 if (TDS_FAILED(tds_writetext_start(tds, cmd->iodesc->name,
    3149             :                         textptr_string, timestamp_string, (cmd->iodesc->log_on_update == CS_TRUE), cmd->iodesc->total_txtlen)))
    3150             :                         return CS_FAIL;
    3151             : 
    3152           6 :                 cmd->send_data_started = 1;
    3153             :         }
    3154             : 
    3155          24 :         if (TDS_FAILED(tds_writetext_continue(tds, (const TDS_UCHAR*) buffer, buflen)))
    3156             :                 return CS_FAIL;
    3157             : 
    3158          24 :         return CS_SUCCEED;
    3159             : }
    3160             : 
    3161             : CS_RETCODE
    3162          12 : ct_data_info(CS_COMMAND * cmd, CS_INT action, CS_INT colnum, CS_IODESC * iodesc)
    3163             : {
    3164             :         TDSSOCKET *tds;
    3165             :         TDSRESULTINFO *resinfo;
    3166             : 
    3167          12 :         tdsdump_log(TDS_DBG_FUNC, "ct_data_info(%p, %d, %d, %p)\n", cmd, action, colnum, iodesc);
    3168             : 
    3169          12 :         if (!cmd->con || !cmd->con->tds_socket)
    3170             :                 return CS_FAIL;
    3171             : 
    3172          12 :         tds = cmd->con->tds_socket;
    3173          12 :         resinfo = tds->current_results;
    3174             : 
    3175          12 :         switch (action) {
    3176           6 :         case CS_SET:
    3177           6 :                 if (iodesc->timestamplen < 0 || iodesc->timestamplen > CS_TS_SIZE)
    3178             :                         return CS_FAIL;
    3179           6 :                 if (iodesc->textptrlen < 0 || iodesc->textptrlen > CS_TP_SIZE)
    3180             :                         return CS_FAIL;
    3181           6 :                 free(cmd->iodesc);
    3182           6 :                 cmd->iodesc = tds_new0(CS_IODESC, 1);
    3183           6 :                 if (!cmd->iodesc)
    3184             :                         return CS_FAIL;
    3185             : 
    3186           6 :                 cmd->iodesc->iotype = CS_IODATA;
    3187           6 :                 cmd->iodesc->datatype = iodesc->datatype;
    3188           6 :                 cmd->iodesc->locale = cmd->con->locale;
    3189           6 :                 cmd->iodesc->usertype = iodesc->usertype;
    3190           6 :                 cmd->iodesc->total_txtlen = iodesc->total_txtlen;
    3191           6 :                 cmd->iodesc->offset = iodesc->offset;
    3192           6 :                 cmd->iodesc->log_on_update = iodesc->log_on_update;
    3193           6 :                 strcpy(cmd->iodesc->name, iodesc->name);
    3194           6 :                 cmd->iodesc->namelen = iodesc->namelen;
    3195           6 :                 memcpy(cmd->iodesc->timestamp, iodesc->timestamp, iodesc->timestamplen);
    3196           6 :                 cmd->iodesc->timestamplen = iodesc->timestamplen;
    3197           6 :                 memcpy(cmd->iodesc->textptr, iodesc->textptr, iodesc->textptrlen);
    3198           6 :                 cmd->iodesc->textptrlen = iodesc->textptrlen;
    3199           6 :                 break;
    3200             : 
    3201           6 :         case CS_GET:
    3202             : 
    3203           6 :                 if (colnum < 1 || colnum > resinfo->num_cols)
    3204             :                         return CS_FAIL;
    3205           6 :                 if (colnum != cmd->get_data_item)
    3206             :                         return CS_FAIL;
    3207             : 
    3208           6 :                 iodesc->iotype = cmd->iodesc->iotype;
    3209           6 :                 iodesc->datatype = cmd->iodesc->datatype;
    3210           6 :                 iodesc->locale = cmd->iodesc->locale;
    3211           6 :                 iodesc->usertype = cmd->iodesc->usertype;
    3212           6 :                 iodesc->total_txtlen = cmd->iodesc->total_txtlen;
    3213           6 :                 iodesc->offset = cmd->iodesc->offset;
    3214           6 :                 iodesc->log_on_update = CS_FALSE;
    3215           6 :                 strcpy(iodesc->name, cmd->iodesc->name);
    3216           6 :                 iodesc->namelen = cmd->iodesc->namelen;
    3217           6 :                 memcpy(iodesc->timestamp, cmd->iodesc->timestamp, cmd->iodesc->timestamplen);
    3218           6 :                 iodesc->timestamplen = cmd->iodesc->timestamplen;
    3219           6 :                 memcpy(iodesc->textptr, cmd->iodesc->textptr, cmd->iodesc->textptrlen);
    3220           6 :                 iodesc->textptrlen = cmd->iodesc->textptrlen;
    3221           6 :                 break;
    3222             : 
    3223             :         default:
    3224             :                 return CS_FAIL;
    3225             :         }
    3226             : 
    3227             :         return CS_SUCCEED;
    3228             : }
    3229             : 
    3230             : CS_RETCODE
    3231           0 : ct_capability(CS_CONNECTION * con, CS_INT action, CS_INT type, CS_INT capability, CS_VOID * value)
    3232             : {
    3233             :         TDSLOGIN *login;
    3234           0 :         int idx = 0;
    3235           0 :         unsigned char bitmask = 0;
    3236           0 :         TDS_CAPABILITY_TYPE *cap = NULL;
    3237             : 
    3238           0 :         tdsdump_log(TDS_DBG_FUNC, "ct_capability(%p, %d, %d, %d, %p)\n", con, action, type, capability, value);
    3239             : 
    3240           0 :         login = (TDSLOGIN *) con->tds_login;
    3241             : 
    3242             : #define CONV_CAP(ct,tds) case ct: idx=tds; break;
    3243           0 :         if (type == CS_CAP_RESPONSE) {
    3244           0 :                 cap = &login->capabilities.types[1];
    3245           0 :                 switch (capability) {
    3246           0 :                 CONV_CAP(CS_DATA_NOBOUNDARY,    TDS_RES_DATA_NOBOUNDARY);
    3247           0 :                 CONV_CAP(CS_RES_NOTDSDEBUG,     TDS_RES_NOTDSDEBUG);
    3248           0 :                 CONV_CAP(CS_RES_NOSTRIPBLANKS,  TDS_RES_NOSTRIPBLANKS);
    3249           0 :                 CONV_CAP(CS_DATA_NOINT8,        TDS_RES_DATA_NOINT8);
    3250             : 
    3251           0 :                 CONV_CAP(CS_DATA_NOINTN,        TDS_RES_DATA_INTN);
    3252           0 :                 CONV_CAP(CS_DATA_NODATETIMEN,   TDS_RES_DATA_NODATETIMEN);
    3253           0 :                 CONV_CAP(CS_DATA_NOMONEYN,      TDS_RES_DATA_NOMONEYN);
    3254           0 :                 CONV_CAP(CS_CON_NOOOB,          TDS_RES_CON_NOOOB);
    3255           0 :                 CONV_CAP(CS_CON_NOINBAND,       TDS_RES_CON_NOINBAND);
    3256           0 :                 CONV_CAP(CS_PROTO_NOTEXT,       TDS_RES_PROTO_NOTEXT);
    3257           0 :                 CONV_CAP(CS_PROTO_NOBULK,       TDS_RES_PROTO_NOBULK);
    3258           0 :                 CONV_CAP(CS_DATA_NOSENSITIVITY, TDS_RES_DATA_NOSENSITIVITY);
    3259             : 
    3260           0 :                 CONV_CAP(CS_DATA_NOFLT4,        TDS_RES_DATA_NOFLT4);
    3261           0 :                 CONV_CAP(CS_DATA_NOFLT8,        TDS_RES_DATA_NOFLT8);
    3262           0 :                 CONV_CAP(CS_DATA_NONUM,         TDS_RES_DATA_NONUM);
    3263           0 :                 CONV_CAP(CS_DATA_NOTEXT,        TDS_RES_DATA_NOTEXT);
    3264           0 :                 CONV_CAP(CS_DATA_NOIMAGE,       TDS_RES_DATA_NOIMAGE);
    3265           0 :                 CONV_CAP(CS_DATA_NODEC,         TDS_RES_DATA_NODEC);
    3266           0 :                 CONV_CAP(CS_DATA_NOLCHAR,       TDS_RES_DATA_NOLCHAR);
    3267           0 :                 CONV_CAP(CS_DATA_NOLBIN,        TDS_RES_DATA_NOLBIN);
    3268             : 
    3269           0 :                 CONV_CAP(CS_DATA_NOCHAR,        TDS_RES_DATA_NOCHAR);
    3270           0 :                 CONV_CAP(CS_DATA_NOVCHAR,       TDS_RES_DATA_NOVCHAR);
    3271           0 :                 CONV_CAP(CS_DATA_NOBIN,         TDS_RES_DATA_NOBIN);
    3272           0 :                 CONV_CAP(CS_DATA_NOVBIN,        TDS_RES_DATA_NOVBIN);
    3273           0 :                 CONV_CAP(CS_DATA_NOMNY8,        TDS_RES_DATA_NOMNY8);
    3274           0 :                 CONV_CAP(CS_DATA_NOMNY4,        TDS_RES_DATA_NOMNY4);
    3275           0 :                 CONV_CAP(CS_DATA_NODATE8,       TDS_RES_DATA_NODATE8);
    3276           0 :                 CONV_CAP(CS_DATA_NODATE4,       TDS_RES_DATA_NODATE4);
    3277             : 
    3278           0 :                 CONV_CAP(CS_RES_NOMSG,          TDS_RES_NOMSG);
    3279           0 :                 CONV_CAP(CS_RES_NOEED,          TDS_RES_NOEED);
    3280           0 :                 CONV_CAP(CS_RES_NOPARAM,        TDS_RES_NOPARAM);
    3281           0 :                 CONV_CAP(CS_DATA_NOINT1,        TDS_RES_DATA_NOINT1);
    3282           0 :                 CONV_CAP(CS_DATA_NOINT2,        TDS_RES_DATA_NOINT2);
    3283           0 :                 CONV_CAP(CS_DATA_NOINT4,        TDS_RES_DATA_NOINT4);
    3284           0 :                 CONV_CAP(CS_DATA_NOBIT,         TDS_RES_DATA_NOBIT);
    3285             :                 } /* end capability */
    3286             :         } /* End handling CS_CAP_RESPONSE (returned) */
    3287             : 
    3288             :         /*
    3289             :          * Begin handling CS_CAP_REQUEST
    3290             :          * These capabilities describe the types of requests that a server can support.
    3291             :          */
    3292           0 :         if (type == CS_CAP_REQUEST) {
    3293           0 :                 if (action == CS_SET) {
    3294           0 :                         tdsdump_log(TDS_DBG_SEVERE,
    3295             :                                     "ct_capability -- attempt to set a read-only capability (type %d, action %d)\n",
    3296             :                                     type, action);
    3297             :                         return CS_FAIL;
    3298             :                 }
    3299             : 
    3300           0 :                 cap = &login->capabilities.types[0];
    3301           0 :                 switch (capability) {
    3302           0 :                 CONV_CAP(CS_PROTO_DYNPROC,      TDS_REQ_PROTO_DYNPROC);
    3303           0 :                 CONV_CAP(CS_DATA_FLTN,          TDS_REQ_DATA_FLTN);
    3304           0 :                 CONV_CAP(CS_DATA_BITN,          TDS_REQ_DATA_BITN);
    3305           0 :                 CONV_CAP(CS_DATA_INT8,          TDS_REQ_DATA_INT8);
    3306           0 :                 CONV_CAP(CS_DATA_VOID,          TDS_REQ_DATA_VOID);
    3307             : 
    3308           0 :                 CONV_CAP(CS_CON_INBAND,         TDS_REQ_CON_INBAND);
    3309           0 :                 CONV_CAP(CS_CON_LOGICAL,        TDS_REQ_CON_LOGICAL);
    3310           0 :                 CONV_CAP(CS_PROTO_TEXT,         TDS_REQ_PROTO_TEXT);
    3311           0 :                 CONV_CAP(CS_PROTO_BULK,         TDS_REQ_PROTO_BULK);
    3312           0 :                 CONV_CAP(CS_REQ_URGNOTIF,       TDS_REQ_URGEVT);
    3313           0 :                 CONV_CAP(CS_DATA_SENSITIVITY,   TDS_REQ_DATA_SENSITIVITY);
    3314           0 :                 CONV_CAP(CS_DATA_BOUNDARY,      TDS_REQ_DATA_BOUNDARY);
    3315           0 :                 CONV_CAP(CS_PROTO_DYNAMIC,      TDS_REQ_PROTO_DYNAMIC);
    3316             : 
    3317           0 :                 CONV_CAP(CS_DATA_MONEYN,        TDS_REQ_DATA_MONEYN);
    3318           0 :                 CONV_CAP(CS_CSR_PREV,           TDS_REQ_CSR_PREV);
    3319           0 :                 CONV_CAP(CS_CSR_FIRST,          TDS_REQ_CSR_FIRST);
    3320           0 :                 CONV_CAP(CS_CSR_LAST,           TDS_REQ_CSR_LAST);
    3321           0 :                 CONV_CAP(CS_CSR_ABS,            TDS_REQ_CSR_ABS);
    3322           0 :                 CONV_CAP(CS_CSR_REL,            TDS_REQ_CSR_REL);
    3323           0 :                 CONV_CAP(CS_CSR_MULTI,          TDS_REQ_CSR_MULTI);
    3324           0 :                 CONV_CAP(CS_CON_OOB,            TDS_REQ_CON_OOB);
    3325             : 
    3326           0 :                 CONV_CAP(CS_DATA_NUM,           TDS_REQ_DATA_NUM);
    3327           0 :                 CONV_CAP(CS_DATA_TEXT,          TDS_REQ_DATA_TEXT);
    3328           0 :                 CONV_CAP(CS_DATA_IMAGE,         TDS_REQ_DATA_IMAGE);
    3329           0 :                 CONV_CAP(CS_DATA_DEC,           TDS_REQ_DATA_DEC);
    3330           0 :                 CONV_CAP(CS_DATA_LCHAR,         TDS_REQ_DATA_LCHAR);
    3331           0 :                 CONV_CAP(CS_DATA_LBIN,          TDS_REQ_DATA_LBIN);
    3332           0 :                 CONV_CAP(CS_DATA_INTN,          TDS_REQ_DATA_INTN);
    3333           0 :                 CONV_CAP(CS_DATA_DATETIMEN,     TDS_REQ_DATA_DATETIMEN);
    3334             : 
    3335           0 :                 CONV_CAP(CS_DATA_BIN,           TDS_REQ_DATA_BIN);
    3336           0 :                 CONV_CAP(CS_DATA_VBIN,          TDS_REQ_DATA_VBIN);
    3337           0 :                 CONV_CAP(CS_DATA_MNY8,          TDS_REQ_DATA_MNY8);
    3338           0 :                 CONV_CAP(CS_DATA_MNY4,          TDS_REQ_DATA_MNY4);
    3339           0 :                 CONV_CAP(CS_DATA_DATE8,         TDS_REQ_DATA_DATE8);
    3340           0 :                 CONV_CAP(CS_DATA_DATE4,         TDS_REQ_DATA_DATE4);
    3341           0 :                 CONV_CAP(CS_DATA_FLT4,          TDS_REQ_DATA_FLT4);
    3342           0 :                 CONV_CAP(CS_DATA_FLT8,          TDS_REQ_DATA_FLT8);
    3343             : 
    3344           0 :                 CONV_CAP(CS_REQ_MSG,            TDS_REQ_MSG);
    3345           0 :                 CONV_CAP(CS_REQ_PARAM,          TDS_REQ_PARAM);
    3346           0 :                 CONV_CAP(CS_DATA_INT1,          TDS_REQ_DATA_INT1);
    3347           0 :                 CONV_CAP(CS_DATA_INT2,          TDS_REQ_DATA_INT2);
    3348           0 :                 CONV_CAP(CS_DATA_INT4,          TDS_REQ_DATA_INT4);
    3349           0 :                 CONV_CAP(CS_DATA_BIT,           TDS_REQ_DATA_BIT);
    3350           0 :                 CONV_CAP(CS_DATA_CHAR,          TDS_REQ_DATA_CHAR);
    3351           0 :                 CONV_CAP(CS_DATA_VCHAR,         TDS_REQ_DATA_VCHAR);
    3352             : 
    3353           0 :                 CONV_CAP(CS_REQ_LANG,           TDS_REQ_LANG);
    3354           0 :                 CONV_CAP(CS_REQ_RPC,            TDS_REQ_RPC);
    3355           0 :                 CONV_CAP(CS_REQ_NOTIF,          TDS_REQ_EVT);
    3356           0 :                 CONV_CAP(CS_REQ_MSTMT,          TDS_REQ_MSTMT);
    3357           0 :                 CONV_CAP(CS_REQ_BCP,            TDS_REQ_BCP);
    3358           0 :                 CONV_CAP(CS_REQ_CURSOR,         TDS_REQ_CURSOR);
    3359           0 :                 CONV_CAP(CS_REQ_DYN,            TDS_REQ_DYNF);
    3360             :                 } /* end capability */
    3361             :         } /* End handling CS_CAP_REQUEST */
    3362             : #undef CONV_CAP
    3363             : 
    3364           0 :         if (!cap) {
    3365           0 :                 tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown capability type\n");
    3366             :                 return CS_FAIL;
    3367             :         }
    3368           0 :         if (idx == 0) {
    3369           0 :                 tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- attempt to set/get a non-existant capability\n");
    3370             :                 return CS_FAIL;
    3371             :         }
    3372             : 
    3373           0 :         bitmask = 1 << (idx&7);
    3374           0 :         idx = sizeof(cap->values) - 1 - (idx>>3);
    3375             :         assert(0 <= idx && idx <= sizeof(cap->values));
    3376             : 
    3377           0 :         switch (action) {
    3378           0 :         case CS_SET:
    3379             :                 /* Having established the offset and the bitmask, we can now turn the capability on or off */
    3380           0 :                 switch (*(CS_BOOL *) value) {
    3381           0 :                 case CS_TRUE:
    3382           0 :                         cap->values[idx] |= bitmask;
    3383           0 :                         break;
    3384           0 :                 case CS_FALSE:
    3385           0 :                         cap->values[idx] &= ~bitmask;
    3386           0 :                         break;
    3387           0 :                 default:
    3388           0 :                         tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown value\n");
    3389             :                         return CS_FAIL;
    3390             :                 }
    3391             :                 break;
    3392           0 :         case CS_GET:
    3393           0 :                 *(CS_BOOL *) value = (cap->values[idx] & bitmask) ? CS_TRUE : CS_FALSE;
    3394           0 :                 break;
    3395           0 :         default:
    3396           0 :                 tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown action\n");
    3397             :                 return CS_FAIL;
    3398             :         }
    3399             :         return CS_SUCCEED;
    3400             : } /* end ct_capability */
    3401             : 
    3402             : 
    3403             : CS_RETCODE
    3404         112 : ct_dynamic(CS_COMMAND * cmd, CS_INT type, CS_CHAR * id, CS_INT idlen, CS_CHAR * buffer, CS_INT buflen)
    3405             : {
    3406             :         int query_len;
    3407             :         CS_CONNECTION *con;
    3408             :         CS_DYNAMIC *dyn;
    3409             : 
    3410         112 :         tdsdump_log(TDS_DBG_FUNC, "ct_dynamic(%p, %d, %p, %d, %p, %d)\n", cmd, type, id, idlen, buffer, buflen);
    3411             : 
    3412         112 :         if (!cmd || !cmd->con)
    3413             :                 return CS_FAIL;
    3414             : 
    3415         112 :         con = cmd->con;
    3416             : 
    3417         112 :         switch (type) {
    3418          40 :         case CS_PREPARE:
    3419             : 
    3420          40 :                 dyn = _ct_allocate_dynamic(con, id, idlen);
    3421             : 
    3422          40 :                 if (!dyn)
    3423             :                         return CS_FAIL;
    3424             : 
    3425             :                 /* now the query */
    3426          24 :                 query_len = _ct_get_string_length(buffer, buflen);
    3427          24 :                 if (query_len < 0) {
    3428           8 :                         _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 5, "%d, buflen", buflen);
    3429           8 :                         return CS_FAIL;
    3430             :                 }
    3431          16 :                 dyn->stmt = tds_strndup(buffer, query_len);
    3432             : 
    3433          16 :                 cmd->dyn = dyn;
    3434             : 
    3435          16 :                 break;
    3436          32 :         case CS_DEALLOC:
    3437          32 :                 cmd->dyn = _ct_locate_dynamic(con, id, idlen);
    3438          32 :                 if (!cmd->dyn)
    3439             :                         return CS_FAIL;
    3440             :                 break;
    3441          16 :         case CS_DESCRIBE_INPUT:
    3442             :         case CS_DESCRIBE_OUTPUT:
    3443          16 :                 cmd->dyn = _ct_locate_dynamic(con, id, idlen);
    3444          16 :                 if (!cmd->dyn)
    3445             :                         return CS_FAIL;
    3446             :                 break;
    3447          16 :         case CS_EXECUTE:
    3448          16 :                 cmd->dyn = _ct_locate_dynamic(con, id, idlen);
    3449          16 :                 if (!cmd->dyn)
    3450             :                         return CS_FAIL;
    3451             : 
    3452          16 :                 tdsdump_log(TDS_DBG_FUNC, "ct_dynamic() calling param_clear\n");
    3453          16 :                 param_clear(cmd->dyn->param_list);
    3454          16 :                 cmd->dyn->param_list = NULL;
    3455          16 :                 break;
    3456           8 :         default:
    3457           8 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 5, "%d, type", type);
    3458           8 :                 return CS_FAIL;
    3459             :         }
    3460             : 
    3461          56 :         cmd->command_type = CS_DYNAMIC_CMD;
    3462          56 :         cmd->dynamic_cmd = type;
    3463             : 
    3464          56 :         ct_set_command_state(cmd, _CS_COMMAND_READY);
    3465          56 :         return CS_SUCCEED;
    3466             : }
    3467             : 
    3468             : CS_RETCODE
    3469         216 : ct_param(CS_COMMAND * cmd, CS_DATAFMT * datafmt_arg, CS_VOID * data, CS_INT datalen, CS_SMALLINT indicator)
    3470             : {
    3471             :         CSREMOTE_PROC *rpc;
    3472             :         CS_DYNAMIC *dyn;
    3473             :         CS_PARAM **pparam;
    3474             :         CS_PARAM *param;
    3475             :         const CS_DATAFMT_LARGE *datafmt;
    3476             :         CS_DATAFMT_LARGE datafmt_buf;
    3477             : 
    3478         216 :         tdsdump_log(TDS_DBG_FUNC, "ct_param(%p, %p, %p, %d, %hd)\n", cmd, datafmt_arg, data, datalen, indicator);
    3479             : 
    3480         216 :         if (!cmd || !cmd->con)
    3481             :                 return CS_FAIL;
    3482             : 
    3483         216 :         datafmt = _ct_datafmt_conv_in(cmd->con->ctx, datafmt_arg, &datafmt_buf);
    3484             : 
    3485         216 :         switch (cmd->command_type) {
    3486          72 :         case CS_RPC_CMD:
    3487          72 :                 if (!cmd->rpc) {
    3488           0 :                         tdsdump_log(TDS_DBG_ERROR, "RPC is NULL in ct_param\n");
    3489             :                         return CS_FAIL;
    3490             :                 }
    3491             : 
    3492          72 :                 param = tds_new0(CSREMOTE_PROC_PARAM, 1);
    3493          72 :                 if (!param)
    3494             :                         return CS_FAIL;
    3495             : 
    3496          72 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
    3497           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add rpc param\n");
    3498           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add input value\n");
    3499           0 :                         free(param);
    3500           0 :                         return CS_FAIL;
    3501             :                 }
    3502             : 
    3503          72 :                 rpc = cmd->rpc;
    3504          72 :                 pparam = &rpc->param_list;
    3505         432 :                 while (*pparam) {
    3506         288 :                         pparam = &(*pparam)->next;
    3507             :                 }
    3508             : 
    3509          72 :                 *pparam = param;
    3510          72 :                 tdsdump_log(TDS_DBG_INFO1, " ct_param() added rpc parameter %s \n", (*param).name);
    3511             :                 return CS_SUCCEED;
    3512             :                 break;
    3513             : 
    3514         144 :         case CS_LANG_CMD:
    3515             :                 /* only accept CS_INPUTVALUE as the status */
    3516         144 :                 if (CS_INPUTVALUE != datafmt->status) {
    3517           0 :                         tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_param()\n", datafmt->status);
    3518             :                         return CS_FAIL;
    3519             :                 }
    3520             : 
    3521         144 :                 param = tds_new0(CSREMOTE_PROC_PARAM, 1);
    3522         144 :                 if (!param)
    3523             :                         return CS_FAIL;
    3524             : 
    3525         144 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
    3526           0 :                         free(param);
    3527           0 :                         return CS_FAIL;
    3528             :                 }
    3529             : 
    3530         144 :                 pparam = &cmd->input_params;
    3531         648 :                 while (*pparam)
    3532         360 :                         pparam = &(*pparam)->next;
    3533         144 :                 *pparam = param;
    3534             : 
    3535         144 :                 tdsdump_log(TDS_DBG_INFO1, "ct_param() added input value\n");
    3536             :                 return CS_SUCCEED;
    3537             :                 break;
    3538             : 
    3539           0 :         case CS_DYNAMIC_CMD:
    3540           0 :                 if (!cmd->dyn) {
    3541           0 :                         tdsdump_log(TDS_DBG_INFO1, "cmd->dyn is NULL ct_param\n");
    3542             :                         return CS_FAIL;
    3543             :                 }
    3544             : 
    3545           0 :                 param = tds_new0(CS_DYNAMIC_PARAM, 1);
    3546           0 :                 if (!param)
    3547             :                         return CS_FAIL;
    3548             : 
    3549           0 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
    3550           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add CS_DYNAMIC param\n");
    3551           0 :                         free(param);
    3552           0 :                         return CS_FAIL;
    3553             :                 }
    3554             : 
    3555           0 :                 dyn = cmd->dyn;
    3556           0 :                 pparam = &dyn->param_list;
    3557           0 :                 while (*pparam) {
    3558           0 :                         pparam = &(*pparam)->next;
    3559             :                 }
    3560             : 
    3561           0 :                 *pparam = param;
    3562           0 :                 return CS_SUCCEED;
    3563             :                 break;
    3564             :         }
    3565             :         return CS_FAIL;
    3566             : }
    3567             : 
    3568             : CS_RETCODE
    3569          76 : ct_setparam(CS_COMMAND * cmd, CS_DATAFMT * datafmt_arg, CS_VOID * data, CS_INT * datalen, CS_SMALLINT * indicator)
    3570             : {
    3571             :         CSREMOTE_PROC *rpc;
    3572             :         CS_PARAM **pparam;
    3573             :         CS_PARAM *param;
    3574             :         CS_DYNAMIC *dyn;
    3575             :         const CS_DATAFMT_LARGE *datafmt;
    3576             :         CS_DATAFMT_LARGE datafmt_buf;
    3577             : 
    3578          76 :         tdsdump_log(TDS_DBG_FUNC, "ct_setparam(%p, %p, %p, %p, %p)\n", cmd, datafmt_arg, data, datalen, indicator);
    3579             : 
    3580          76 :         if (!cmd || !cmd->con)
    3581             :                 return CS_FAIL;
    3582             : 
    3583          76 :         datafmt = _ct_datafmt_conv_in(cmd->con->ctx, datafmt_arg, &datafmt_buf);
    3584             : 
    3585             :         /* Code changed for RPC functionality - SUHA */
    3586             :         /* RPC code changes starts here */
    3587             : 
    3588          76 :         tdsdump_log(TDS_DBG_FUNC, "ct_setparam() command type = %d, data type = %d\n", cmd->command_type, datafmt->datatype);
    3589             : 
    3590          76 :         switch (cmd->command_type) {
    3591             : 
    3592          60 :         case CS_RPC_CMD:
    3593             : 
    3594          60 :                 if (!cmd->rpc) {
    3595           0 :                         tdsdump_log(TDS_DBG_ERROR, "RPC is NULL in ct_setparam\n");
    3596             :                         return CS_FAIL;
    3597             :                 }
    3598             : 
    3599          60 :                 param = tds_new0(CSREMOTE_PROC_PARAM, 1);
    3600          60 :                 if (!param)
    3601             :                         return CS_FAIL;
    3602             : 
    3603          60 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
    3604           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add rpc param\n");
    3605           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add input value\n");
    3606           0 :                         free(param);
    3607           0 :                         return CS_FAIL;
    3608             :                 }
    3609             : 
    3610          60 :                 rpc = cmd->rpc;
    3611          60 :                 pparam = &rpc->param_list;
    3612          60 :                 tdsdump_log(TDS_DBG_INFO1, " ct_setparam() reached here\n");
    3613          60 :                 if (*pparam != NULL) {
    3614         168 :                         while ((*pparam)->next != NULL) {
    3615         120 :                                 pparam = &(*pparam)->next;
    3616             :                         }
    3617             : 
    3618          48 :                         pparam = &(*pparam)->next;
    3619             :                 }
    3620          60 :                 *pparam = param;
    3621          60 :                 param->next = NULL;
    3622          60 :                 tdsdump_log(TDS_DBG_INFO1, " ct_setparam() added parameter %s \n", (*param).name);
    3623             :                 return CS_SUCCEED;
    3624             :                 break;
    3625             : 
    3626          16 :         case CS_DYNAMIC_CMD :
    3627             : 
    3628          16 :                 if (!cmd->dyn) {
    3629           0 :                         tdsdump_log(TDS_DBG_ERROR, "cmd->dyn is NULL in ct_setparam\n");
    3630             :                         return CS_FAIL;
    3631             :                 }
    3632             : 
    3633          16 :                 param = tds_new0(CS_DYNAMIC_PARAM, 1);
    3634          16 :                 if (!param)
    3635             :                         return CS_FAIL;
    3636             : 
    3637          16 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
    3638           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add dynamic param\n");
    3639           0 :                         free(param);
    3640           0 :                         return CS_FAIL;
    3641             :                 }
    3642             : 
    3643          16 :                 dyn = cmd->dyn;
    3644          16 :                 pparam = &dyn->param_list;
    3645          16 :                 if (*pparam != NULL) {
    3646           0 :                         while ((*pparam)->next != NULL) {
    3647           0 :                                 pparam = &(*pparam)->next;
    3648             :                         }
    3649             : 
    3650           0 :                         pparam = &(*pparam)->next;
    3651             :                 }
    3652          16 :                 *pparam = param;
    3653          16 :                 param->next = NULL;
    3654          16 :                 tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added dynamic parameter\n");
    3655             :                 return CS_SUCCEED;
    3656             :                 break;
    3657             : 
    3658           0 :         case CS_LANG_CMD:
    3659             : 
    3660             :                 /* only accept CS_INPUTVALUE as the status */
    3661           0 :                 if (CS_INPUTVALUE != datafmt->status) {
    3662           0 :                         tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_setparam()\n", datafmt->status);
    3663             :                         return CS_FAIL;
    3664             :                 }
    3665             : 
    3666           0 :                 param = tds_new0(CSREMOTE_PROC_PARAM, 1);
    3667           0 :                 if (!param)
    3668             :                         return CS_FAIL;
    3669             : 
    3670           0 :                 if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
    3671           0 :                         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add language param\n");
    3672           0 :                         free(param);
    3673           0 :                         return CS_FAIL;
    3674             :                 }
    3675             : 
    3676           0 :                 if (!cmd->input_params) {
    3677           0 :                         cmd->input_params = param;
    3678             :                 } else {
    3679           0 :                         pparam = &cmd->input_params;
    3680           0 :                         while ((*pparam)->next)
    3681           0 :                                 pparam = &(*pparam)->next;
    3682           0 :                         (*pparam)->next = param;
    3683             :                 }
    3684           0 :                 tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added language parameter\n");
    3685             :                 return CS_SUCCEED;
    3686             :                 break;
    3687             :         }
    3688             :         return CS_FAIL;
    3689             : }
    3690             : 
    3691             : CS_RETCODE
    3692          64 : ct_options(CS_CONNECTION * con, CS_INT action, CS_INT option, CS_VOID * param, CS_INT paramlen, CS_INT * outlen)
    3693             : {
    3694             :         TDS_OPTION_CMD tds_command;
    3695          64 :         TDS_OPTION tds_option = 0;
    3696             :         TDS_OPTION_ARG tds_argument;
    3697          64 :         TDS_INT tds_argsize = 0;
    3698             :         TDSSOCKET *tds;
    3699             : 
    3700          64 :         const char *action_string = NULL;
    3701             :         int i;
    3702             : 
    3703             :         /* boolean options can all be treated the same way */
    3704             :         static const struct TDS_BOOL_OPTION_MAP
    3705             :         {
    3706             :                 CS_INT option;
    3707             :                 TDS_OPTION tds_option;
    3708             :         } tds_bool_option_map[] = {
    3709             :                   { CS_OPT_ANSINULL,       TDS_OPT_ANSINULL       }
    3710             :                 , { CS_OPT_CHAINXACTS,     TDS_OPT_CHAINXACTS     }
    3711             :                 , { CS_OPT_CURCLOSEONXACT, TDS_OPT_CURCLOSEONXACT }
    3712             :                 , { CS_OPT_FIPSFLAG,       TDS_OPT_FIPSFLAG       }
    3713             :                 , { CS_OPT_FORCEPLAN,      TDS_OPT_FORCEPLAN      }
    3714             :                 , { CS_OPT_FORMATONLY,     TDS_OPT_FORMATONLY     }
    3715             :                 , { CS_OPT_GETDATA,        TDS_OPT_GETDATA        }
    3716             :                 , { CS_OPT_NOCOUNT,        TDS_OPT_NOCOUNT        }
    3717             :                 , { CS_OPT_NOEXEC,         TDS_OPT_NOEXEC         }
    3718             :                 , { CS_OPT_PARSEONLY,      TDS_OPT_PARSEONLY      }
    3719             :                 , { CS_OPT_QUOTED_IDENT,   TDS_OPT_QUOTED_IDENT   }
    3720             :                 , { CS_OPT_RESTREES,       TDS_OPT_RESTREES       }
    3721             :                 , { CS_OPT_SHOWPLAN,       TDS_OPT_SHOWPLAN       }
    3722             :                 , { CS_OPT_STATS_IO,       TDS_OPT_STAT_IO        }
    3723             :                 , { CS_OPT_STATS_TIME,     TDS_OPT_STAT_TIME      }
    3724             :                 , { CS_OPT_ARITHIGNORE,    TDS_OPT_ARITHIGNOREON  }
    3725             :                 , { CS_OPT_ARITHABORT,     TDS_OPT_ARITHABORTON   }
    3726             :         };
    3727             : 
    3728          64 :         tdsdump_log(TDS_DBG_FUNC, "ct_options(%p, %d, %d, %p, %d, %p)\n", con, action, option, param, paramlen, outlen);
    3729             : 
    3730          64 :         if (!param)
    3731             :                 return CS_FAIL;
    3732             : 
    3733          64 :         if (!con || !(tds=con->tds_socket))
    3734             :                 return CS_FAIL;
    3735             : 
    3736             :         /*
    3737             :          * Set the tds command
    3738             :          */
    3739          64 :         switch (action) {
    3740             :         case CS_GET:
    3741             :                 tds_command = TDS_OPT_LIST;     /* will be acknowledged by TDS_OPT_INFO */
    3742             :                 action_string = "CS_GET";
    3743             :                 tds_argsize = 0;
    3744             :                 break;
    3745          32 :         case CS_SET:
    3746          32 :                 tds_command = TDS_OPT_SET;
    3747          32 :                 action_string = "CS_SET";
    3748          32 :                 break;
    3749           0 :         case CS_CLEAR:
    3750           0 :                 tds_command = TDS_OPT_DEFAULT;
    3751           0 :                 action_string = "CS_CLEAR";
    3752           0 :                 tds_argsize = 0;
    3753           0 :                 break;
    3754           0 :         default:
    3755           0 :                 tdsdump_log(TDS_DBG_FUNC, "ct_options: invalid action = %d\n", action);
    3756             :                 return CS_FAIL;
    3757             :         }
    3758             : 
    3759             :         assert(tds_command && action_string);
    3760             : 
    3761          64 :         tdsdump_log(TDS_DBG_FUNC, "ct_options: %s, option = %d\n", action_string, option);
    3762             : 
    3763             :         /*
    3764             :          * Set the tds option
    3765             :          *      The following TDS options apparently cannot be set with this function.
    3766             :          *      TDS_OPT_CHARSET
    3767             :          *      TDS_OPT_CURREAD
    3768             :          *      TDS_OPT_IDENTITYOFF
    3769             :          *      TDS_OPT_IDENTITYON
    3770             :          *      TDS_OPT_CURWRITE
    3771             :          *      TDS_OPT_NATLANG
    3772             :          *      TDS_OPT_ROWCOUNT
    3773             :          */
    3774             : 
    3775             :         /*
    3776             :          * First, take care of the easy cases, the booleans.
    3777             :          */
    3778        1248 :         for (i = 0; i < TDS_VECTOR_SIZE(tds_bool_option_map); i++) {
    3779         592 :                 if (tds_bool_option_map[i].option != option)
    3780         560 :                         continue;
    3781             : 
    3782          32 :                 tds_option = tds_bool_option_map[i].tds_option;
    3783          32 :                 if (action == CS_SET) {
    3784          16 :                         switch (*(CS_BOOL *) param) {
    3785          16 :                         case CS_TRUE:
    3786          16 :                                 tds_argument.ti = 1;
    3787          16 :                                 break;
    3788           0 :                         case CS_FALSE:
    3789           0 :                                 tds_argument.ti = 0;
    3790           0 :                                 break;
    3791             :                         default:
    3792             :                                 return CS_FAIL;
    3793             :                         }
    3794             :                         tds_argsize = 1;
    3795             :                 }
    3796          32 :                 if (action == CS_GET) {
    3797          16 :                         tds_argsize = 0;
    3798             :                 }
    3799             :                 goto SEND_OPTION;
    3800             :         }
    3801             : 
    3802             :         /*
    3803             :          * Non-booleans are more complicated.
    3804             :          */
    3805          32 :         switch (option) {
    3806           0 :         case CS_OPT_ANSIPERM:
    3807             :         case CS_OPT_STR_RTRUNC:
    3808             :                 /* no documented tds option */
    3809           0 :                 switch (*(CS_BOOL *) param) {
    3810             :                 case CS_TRUE:
    3811             :                 case CS_FALSE:
    3812             :                         break;  /* end valid choices */
    3813           0 :                 default:
    3814           0 :                         if (action == CS_SET)
    3815             :                                 return CS_FAIL;
    3816             :                 }
    3817             :                 break;
    3818           0 :         case CS_OPT_AUTHOFF:
    3819           0 :                 tds_option = TDS_OPT_AUTHOFF;
    3820           0 :                 tds_argument.c = (TDS_CHAR *) param;
    3821           0 :                 tds_argsize = (action == CS_SET) ? paramlen : 0;
    3822             :                 break;
    3823           0 :         case CS_OPT_AUTHON:
    3824           0 :                 tds_option = TDS_OPT_AUTHON;
    3825           0 :                 tds_argument.c = (TDS_CHAR *) param;
    3826           0 :                 tds_argsize = (action == CS_SET) ? paramlen : 0;
    3827             :                 break;
    3828             : 
    3829          16 :         case CS_OPT_DATEFIRST:
    3830          16 :                 tds_option = TDS_OPT_DATEFIRST;
    3831          16 :                 switch (*(CS_INT *) param) {
    3832           0 :                 case CS_OPT_SUNDAY:
    3833           0 :                         tds_argument.ti = TDS_OPT_SUNDAY;
    3834           0 :                         break;
    3835           0 :                 case CS_OPT_MONDAY:
    3836           0 :                         tds_argument.ti = TDS_OPT_MONDAY;
    3837           0 :                         break;
    3838           0 :                 case CS_OPT_TUESDAY:
    3839           0 :                         tds_argument.ti = TDS_OPT_TUESDAY;
    3840           0 :                         break;
    3841           8 :                 case CS_OPT_WEDNESDAY:
    3842           8 :                         tds_argument.ti = TDS_OPT_WEDNESDAY;
    3843           8 :                         break;
    3844           0 :                 case CS_OPT_THURSDAY:
    3845           0 :                         tds_argument.ti = TDS_OPT_THURSDAY;
    3846           0 :                         break;
    3847           0 :                 case CS_OPT_FRIDAY:
    3848           0 :                         tds_argument.ti = TDS_OPT_FRIDAY;
    3849           0 :                         break;
    3850           0 :                 case CS_OPT_SATURDAY:
    3851           0 :                         tds_argument.ti = TDS_OPT_SATURDAY;
    3852           0 :                         break;
    3853           8 :                 default:
    3854           8 :                         if (action == CS_SET)
    3855             :                                 return CS_FAIL;
    3856             :                 }
    3857          16 :                 tds_argsize = (action == CS_SET) ? 1 : 0;
    3858          16 :                 break;
    3859          16 :         case CS_OPT_DATEFORMAT:
    3860          16 :                 tds_option = TDS_OPT_DATEFORMAT;
    3861          16 :                 switch (*(CS_INT *) param) {
    3862           0 :                 case CS_OPT_FMTMDY:
    3863           0 :                         tds_argument.ti = TDS_OPT_FMTMDY;
    3864           0 :                         break;
    3865           0 :                 case CS_OPT_FMTDMY:
    3866           0 :                         tds_argument.ti = TDS_OPT_FMTDMY;
    3867           0 :                         break;
    3868           0 :                 case CS_OPT_FMTYMD:
    3869           0 :                         tds_argument.ti = TDS_OPT_FMTYMD;
    3870           0 :                         break;
    3871           0 :                 case CS_OPT_FMTYDM:
    3872           0 :                         tds_argument.ti = TDS_OPT_FMTYDM;
    3873           0 :                         break;
    3874           8 :                 case CS_OPT_FMTMYD:
    3875           8 :                         tds_argument.ti = TDS_OPT_FMTMYD;
    3876           8 :                         break;
    3877           0 :                 case CS_OPT_FMTDYM:
    3878           0 :                         tds_argument.ti = TDS_OPT_FMTDYM;
    3879           0 :                         break;
    3880           8 :                 default:
    3881           8 :                         if (action == CS_SET)
    3882             :                                 return CS_FAIL;
    3883             :                 }
    3884          16 :                 tds_argsize = (action == CS_SET) ? 1 : 0;
    3885          16 :                 break;
    3886           0 :         case CS_OPT_ISOLATION:
    3887           0 :                 tds_option = TDS_OPT_ISOLATION;
    3888           0 :                 switch (*(char *) param) {
    3889           0 :                 case CS_OPT_LEVEL0:     /* CS_OPT_LEVEL0 requires SQL Server version 11.0 or later or Adaptive Server. */
    3890           0 :                         tds_argument.ti = TDS_OPT_LEVEL0;
    3891           0 :                         break;
    3892           0 :                 case CS_OPT_LEVEL1:
    3893           0 :                         tds_argument.ti = TDS_OPT_LEVEL1;
    3894           0 :                         break;
    3895           0 :                 case CS_OPT_LEVEL2:
    3896           0 :                         tds_argument.ti = TDS_OPT_LEVEL2;
    3897           0 :                         break;
    3898           0 :                 case CS_OPT_LEVEL3:
    3899           0 :                         tds_argument.ti = TDS_OPT_LEVEL3;
    3900           0 :                         break;
    3901           0 :                 default:
    3902           0 :                         if (action == CS_SET)
    3903             :                                 return CS_FAIL;
    3904             :                 }
    3905           0 :                 tds_argsize = (action == CS_SET) ? 1 : 0;
    3906           0 :                 break;
    3907           0 :         case CS_OPT_TEXTSIZE:
    3908           0 :                 tds_option = TDS_OPT_TEXTSIZE;
    3909           0 :                 tds_argument.i = *(CS_INT *) param;
    3910           0 :                 tds_argsize = (action == CS_SET) ? sizeof(tds_argument.i) : 0;
    3911             :                 break;
    3912           0 :         case CS_OPT_TRUNCIGNORE:
    3913           0 :                 tds_option = TDS_OPT_TRUNCABORT;        /* note inverted sense */
    3914           0 :                 switch (*(CS_BOOL *) param) {
    3915             :                 case CS_TRUE:
    3916             :                 case CS_FALSE:
    3917             :                         break;
    3918           0 :                 default:
    3919           0 :                         if (action == CS_SET)
    3920             :                                 return CS_FAIL;
    3921             :                 }
    3922           0 :                 tds_argument.ti = !*(CS_BOOL *) param;
    3923           0 :                 tds_argsize = (action == CS_SET) ? 1 : 0;
    3924           0 :                 break;
    3925             :         default:
    3926             :                 return CS_FAIL; /* invalid option */
    3927             :         }
    3928             : 
    3929          64 : SEND_OPTION:
    3930             : 
    3931          64 :         tdsdump_log(TDS_DBG_FUNC, "\ttds_submit_optioncmd will be action(%s) option(%d) arg(%x) arglen(%d)\n",
    3932             :                                 action_string, tds_option,
    3933           0 :                                 tds_argsize == 1 ? tds_argument.ti : (tds_argsize == 4 ? tds_argument.i : 0), tds_argsize);
    3934             : 
    3935          64 :         if (TDS_FAILED(tds_submit_optioncmd(tds, tds_command, tds_option, &tds_argument, tds_argsize))) {
    3936             :                 return CS_FAIL;
    3937             :         }
    3938             : 
    3939          64 :         if (action == CS_GET) {
    3940          32 :                 switch (option) {
    3941          16 :                 case CS_OPT_ANSINULL :
    3942             :                 case CS_OPT_CHAINXACTS :
    3943             :                 case CS_OPT_CURCLOSEONXACT :
    3944             :                 case CS_OPT_NOCOUNT :
    3945             :                 case CS_OPT_QUOTED_IDENT :
    3946          16 :                         *(CS_BOOL *)param = tds->option_value;
    3947          16 :                         break;
    3948           8 :                 case CS_OPT_DATEFIRST:
    3949           8 :                         switch (tds->option_value) {
    3950           0 :                         case TDS_OPT_SUNDAY: *(CS_INT *)param = CS_OPT_SUNDAY; break;
    3951           0 :                         case TDS_OPT_MONDAY: *(CS_INT *)param = CS_OPT_MONDAY; break;
    3952           0 :                         case TDS_OPT_TUESDAY: *(CS_INT *)param = CS_OPT_TUESDAY; break;
    3953           8 :                         case TDS_OPT_WEDNESDAY: *(CS_INT *)param = CS_OPT_WEDNESDAY; break;
    3954           0 :                         case TDS_OPT_THURSDAY: *(CS_INT *)param = CS_OPT_THURSDAY; break;
    3955           0 :                         case TDS_OPT_FRIDAY: *(CS_INT *)param = CS_OPT_FRIDAY; break;
    3956           0 :                         case TDS_OPT_SATURDAY: *(CS_INT *)param = CS_OPT_SATURDAY; break;
    3957             :                         default: return CS_FAIL;
    3958             :                         }
    3959             :                         break;
    3960           8 :                 case CS_OPT_DATEFORMAT:
    3961           8 :                         switch (tds->option_value) {
    3962           0 :                         case TDS_OPT_FMTDMY: *(CS_INT *)param = CS_OPT_FMTDMY; break;
    3963           0 :                         case TDS_OPT_FMTDYM: *(CS_INT *)param = CS_OPT_FMTDYM; break;
    3964           0 :                         case TDS_OPT_FMTMDY: *(CS_INT *)param = CS_OPT_FMTMDY; break;
    3965           8 :                         case TDS_OPT_FMTMYD: *(CS_INT *)param = CS_OPT_FMTMYD; break;
    3966           0 :                         case TDS_OPT_FMTYMD: *(CS_INT *)param = CS_OPT_FMTYMD; break;
    3967           0 :                         case TDS_OPT_FMTYDM: *(CS_INT *)param = CS_OPT_FMTYDM; break;
    3968             :                         default: return CS_FAIL;
    3969             :                         }
    3970             :                         break;
    3971           0 :                 case CS_OPT_ARITHABORT :
    3972             :                 case CS_OPT_ARITHIGNORE :
    3973           0 :                         *(CS_BOOL *)param = tds->option_value;
    3974           0 :                         break;
    3975             :                 case CS_OPT_TRUNCIGNORE :
    3976             :                         break;
    3977             :                 }
    3978             :         }
    3979             : 
    3980             :         return CS_SUCCEED;
    3981             : }                               /* end ct_options() */
    3982             : 
    3983             : CS_RETCODE
    3984           0 : ct_poll(CS_CONTEXT * ctx, CS_CONNECTION * connection, CS_INT milliseconds, CS_CONNECTION ** compconn, CS_COMMAND ** compcmd,
    3985             :         CS_INT * compid, CS_INT * compstatus)
    3986             : {
    3987           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED ct_poll()\n");
    3988           0 :         tdsdump_log(TDS_DBG_FUNC, "ct_poll(%p, %p, %d, %p, %p, %p, %p)\n",
    3989             :                                 ctx, connection, milliseconds, compconn, compcmd, compid, compstatus);
    3990             : 
    3991           0 :         return CS_FAIL;
    3992             : }
    3993             : 
    3994             : CS_RETCODE
    3995         176 : ct_cursor(CS_COMMAND * cmd, CS_INT type, CS_CHAR * name, CS_INT namelen, CS_CHAR * text, CS_INT tlen, CS_INT option)
    3996             : {
    3997             :         TDSSOCKET *tds;
    3998             :         TDSCURSOR *cursor;
    3999             : 
    4000         176 :         tdsdump_log(TDS_DBG_FUNC, "ct_cursor(%p, %d, %p, %d, %p, %d, %d)\n", cmd, type, name, namelen, text, tlen, option);
    4001             : 
    4002         176 :         if (!cmd || !cmd->con || !cmd->con->tds_socket)
    4003             :                 return CS_FAIL;
    4004             : 
    4005         176 :         tds = cmd->con->tds_socket;
    4006         176 :         cmd->command_type = CS_CUR_CMD;
    4007             : 
    4008         176 :         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : type = %d \n", type);
    4009             : 
    4010         176 :         switch (type) {
    4011          56 :         case CS_CURSOR_DECLARE:
    4012             : 
    4013          56 :                 namelen = _ct_get_string_length(name, namelen);
    4014          56 :                 if (namelen < 0) {
    4015          16 :                         _ctclient_msg(NULL, cmd->con, "ct_cursor(DECLARE)", 1, 1, 1, 5, "%d, %s", namelen, "namelen");
    4016          16 :                         return CS_FAIL;
    4017             :                 }
    4018          40 :                 tlen = _ct_get_string_length(text, tlen);
    4019          40 :                 if (tlen < 0) {
    4020           8 :                         _ctclient_msg(NULL, cmd->con, "ct_cursor(DECLARE)", 1, 1, 1, 5, "%d, %s", tlen, "tlen");
    4021           8 :                         return CS_FAIL;
    4022             :                 }
    4023          32 :                 cursor = tds_alloc_cursor(tds, name, namelen, text, tlen);
    4024          32 :                 if (!cursor)
    4025             :                         return CS_FAIL;
    4026             : 
    4027          32 :                 cursor->cursor_rows = 1;
    4028          32 :                 cursor->options = option;
    4029          32 :                 cursor->status.declare    = TDS_CURSOR_STATE_REQUESTED;
    4030          32 :                 cursor->status.cursor_row = TDS_CURSOR_STATE_UNACTIONED;
    4031          32 :                 cursor->status.open       = TDS_CURSOR_STATE_UNACTIONED;
    4032          32 :                 cursor->status.fetch      = TDS_CURSOR_STATE_UNACTIONED;
    4033          32 :                 cursor->status.close      = TDS_CURSOR_STATE_UNACTIONED;
    4034          32 :                 cursor->status.dealloc    = TDS_CURSOR_STATE_UNACTIONED;
    4035             : 
    4036          32 :                 tds_release_cursor(&cmd->cursor);
    4037          32 :                 cmd->cursor = cursor;
    4038          32 :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
    4039          32 :                 return CS_SUCCEED;
    4040             :                 break;
    4041             : 
    4042          32 :         case CS_CURSOR_ROWS:
    4043             : 
    4044          32 :                 cursor = cmd->cursor;
    4045          32 :                 if (!cursor) {
    4046           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
    4047             :                         return CS_FAIL;
    4048             :                 }
    4049             : 
    4050          32 :                 if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
    4051             :                         cursor->status.declare == _CS_CURS_TYPE_SENT) {
    4052             : 
    4053          32 :                         cursor->cursor_rows = option;
    4054          32 :                         cursor->status.cursor_row = TDS_CURSOR_STATE_REQUESTED;
    4055             : 
    4056          32 :                         ct_set_command_state(cmd, _CS_COMMAND_READY);
    4057          32 :                         return CS_SUCCEED;
    4058             :                 }
    4059             :                 else {
    4060           0 :                         cursor->status.cursor_row  = TDS_CURSOR_STATE_UNACTIONED;
    4061           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
    4062             :                         return CS_FAIL;
    4063             :                 }
    4064             :                 break;
    4065             : 
    4066          32 :         case CS_CURSOR_OPEN:
    4067             : 
    4068          32 :                 cursor = cmd->cursor;
    4069          32 :                 if (!cursor) {
    4070           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
    4071             :                         return CS_FAIL;
    4072             :                 }
    4073             : 
    4074          32 :                 if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
    4075             :                         cursor->status.declare == _CS_CURS_TYPE_SENT ) {
    4076             : 
    4077          32 :                         cursor->status.open  = TDS_CURSOR_STATE_REQUESTED;
    4078             : 
    4079          32 :                         return CS_SUCCEED;
    4080             :                         ct_set_command_state(cmd, _CS_COMMAND_READY);
    4081             :                 }
    4082             :                 else {
    4083           0 :                         cursor->status.open = TDS_CURSOR_STATE_UNACTIONED;
    4084           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
    4085             :                         return CS_FAIL;
    4086             :                 }
    4087             : 
    4088             :                 break;
    4089             : 
    4090          32 :         case CS_CURSOR_CLOSE:
    4091             : 
    4092          32 :                 cursor = cmd->cursor;
    4093          32 :                 if (!cursor) {
    4094           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
    4095             :                         return CS_FAIL;
    4096             :                 }
    4097             : 
    4098          32 :                 cursor->status.cursor_row = TDS_CURSOR_STATE_UNACTIONED;
    4099          32 :                 cursor->status.open       = TDS_CURSOR_STATE_UNACTIONED;
    4100          32 :                 cursor->status.fetch      = TDS_CURSOR_STATE_UNACTIONED;
    4101          32 :                 cursor->status.close      = TDS_CURSOR_STATE_REQUESTED;
    4102          32 :                 if (option == CS_DEALLOC) {
    4103           8 :                         cursor->status.dealloc   = TDS_CURSOR_STATE_REQUESTED;
    4104             :                 }
    4105          32 :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
    4106          32 :                 return CS_SUCCEED;
    4107             : 
    4108          24 :         case CS_CURSOR_DEALLOC:
    4109             : 
    4110          24 :                 cursor = cmd->cursor;
    4111          24 :                 if (!cursor) {
    4112           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
    4113             :                         return CS_FAIL;
    4114             :                 }
    4115          24 :                 cursor->status.dealloc   = TDS_CURSOR_STATE_REQUESTED;
    4116          24 :                 ct_set_command_state(cmd, _CS_COMMAND_READY);
    4117          24 :                 return CS_SUCCEED;
    4118             : 
    4119           0 :         case CS_IMPLICIT_CURSOR:
    4120           0 :                 tdsdump_log(TDS_DBG_INFO1, "CS_IMPLICIT_CURSOR: Option not implemented\n");
    4121             :                 return CS_FAIL;
    4122           0 :         case CS_CURSOR_OPTION:
    4123           0 :                 tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_OPTION: Option not implemented\n");
    4124             :                 return CS_FAIL;
    4125           0 :         case CS_CURSOR_UPDATE:
    4126           0 :                 tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_UPDATE: Option not implemented\n");
    4127             :                 return CS_FAIL;
    4128           0 :         case CS_CURSOR_DELETE:
    4129           0 :                 tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_DELETE: Option not implemented\n");
    4130             :                 return CS_FAIL;
    4131             : 
    4132             :         }
    4133             : 
    4134             :         return CS_FAIL;
    4135             : }
    4136             : 
    4137             : static int
    4138           0 : _ct_fetchable_results(CS_COMMAND * cmd)
    4139             : {
    4140           0 :         tdsdump_log(TDS_DBG_FUNC, "_ct_fetchable_results(%p)\n", cmd);
    4141             : 
    4142           0 :         switch (cmd->curr_result_type) {
    4143             :         case CS_COMPUTE_RESULT:
    4144             :         case CS_CURSOR_RESULT:
    4145             :         case CS_PARAM_RESULT:
    4146             :         case CS_ROW_RESULT:
    4147             :         case CS_STATUS_RESULT:
    4148             :                 return 1;
    4149             :         }
    4150             :         return 0;
    4151             : }
    4152             : 
    4153             : static TDSRET
    4154          58 : _ct_process_return_status(TDSSOCKET * tds)
    4155             : {
    4156             :         TDSRESULTINFO *info;
    4157             :         TDSCOLUMN *curcol;
    4158             :         TDS_INT saved_status;
    4159             :         TDSRET rc;
    4160             : 
    4161             :         enum { num_cols = 1 };
    4162             : 
    4163          58 :         tdsdump_log(TDS_DBG_FUNC, "_ct_process_return_status(%p)\n", tds);
    4164             : 
    4165          58 :         assert(tds);
    4166          58 :         saved_status = tds->ret_status;
    4167          58 :         tds_free_all_results(tds);
    4168             : 
    4169             :         /* allocate the columns structure */
    4170          58 :         tds->res_info = tds_alloc_results(num_cols);
    4171          58 :         tds_set_current_results(tds, tds->res_info);
    4172             : 
    4173          58 :         if (!tds->res_info)
    4174             :                 return TDS_FAIL;
    4175             : 
    4176          58 :         info = tds->res_info;
    4177             : 
    4178          58 :         curcol = info->columns[0];
    4179             : 
    4180          58 :         tds_set_column_type(tds->conn, curcol, SYBINT4);
    4181             : 
    4182          58 :         tdsdump_log(TDS_DBG_INFO1, "generating return status row. type = %d(%s), varint_size %d\n",
    4183           0 :                     curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
    4184             : 
    4185          58 :         rc = tds_alloc_row(info);
    4186          58 :         if (TDS_FAILED(rc))
    4187             :                 return rc;
    4188             : 
    4189          58 :         assert(curcol->column_data != NULL);
    4190             : 
    4191          58 :         *(TDS_INT *) curcol->column_data = saved_status;
    4192             : 
    4193          58 :         return TDS_SUCCESS;
    4194             : }
    4195             : 
    4196             : /* Code added for RPC functionality  - SUHA */
    4197             : /* RPC code changes starts here */
    4198             : 
    4199             : static const unsigned char *
    4200         356 : paramrowalloc(TDSPARAMINFO * params, TDSCOLUMN * curcol, int param_num, void *value, int size)
    4201             : {
    4202         356 :         const void *row = tds_alloc_param_data(curcol);
    4203             : 
    4204         356 :         tdsdump_log(TDS_DBG_INFO1, "paramrowalloc, size = %d, data = %p, row_size = %d\n",
    4205             :                                 size, curcol->column_data, params->row_size);
    4206         356 :         if (!row)
    4207             :                 return NULL;
    4208             : 
    4209         356 :         if (value) {
    4210             :                 /* TODO check for BLOB and numeric */
    4211         300 :                 if (size > curcol->column_size) {
    4212           0 :                         tdsdump_log(TDS_DBG_FUNC, "paramrowalloc(): RESIZE %d to %d\n", size, curcol->column_size);
    4213           0 :                         size = curcol->column_size;
    4214             :                 }
    4215             :                 /* TODO blobs */
    4216         300 :                 if (!is_blob_col(curcol))
    4217         292 :                         memcpy(curcol->column_data, value, size);
    4218             :                 else {
    4219           8 :                         TDSBLOB *blob = (TDSBLOB *) curcol->column_data;
    4220           8 :                         blob->textvalue = tds_new(TDS_CHAR, size ? size : 1);
    4221           8 :                         tdsdump_log(TDS_DBG_FUNC, "blob parameter supported, size %d textvalue pointer is %p\n",
    4222             :                                         size, blob->textvalue);
    4223           8 :                         if (!blob->textvalue)
    4224             :                                 return NULL;
    4225           8 :                         memcpy(blob->textvalue, value, size);
    4226             :                 }
    4227         300 :                 curcol->column_cur_size = size;
    4228             :         } else {
    4229          56 :                 tdsdump_log(TDS_DBG_FUNC, "paramrowalloc(): setting parameter #%d to NULL\n", param_num);
    4230          56 :                 curcol->column_cur_size = -1;
    4231             :         }
    4232             : 
    4233             :         return (const unsigned char*) row;
    4234             : }
    4235             : 
    4236             : /**
    4237             :  * Allocate memory and copy the rpc information into a TDSPARAMINFO structure.
    4238             :  */
    4239             : static TDSPARAMINFO *
    4240         116 : paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param)
    4241             : {
    4242             :         int i;
    4243             :         CS_PARAM *p;
    4244             :         TDSCOLUMN *pcol;
    4245         116 :         TDSPARAMINFO *params = NULL, *new_params;
    4246             : 
    4247             :         int temp_type;
    4248             :         TDS_SERVER_TYPE tds_type;
    4249             : 
    4250         116 :         tdsdump_log(TDS_DBG_FUNC, "paraminfoalloc(%p, %p)\n", tds, first_param);
    4251             : 
    4252             :         /* sanity */
    4253         116 :         if (!first_param)
    4254             :                 return NULL;
    4255             : 
    4256         356 :         for (i = 0, p = first_param; p != NULL; p = p->next, i++) {
    4257             :                 const unsigned char *prow;
    4258         356 :                 CS_BYTE *temp_value = NULL;
    4259         356 :                 CS_INT temp_datalen = 0;
    4260             : 
    4261         356 :                 if (!(new_params = tds_alloc_param_result(params)))
    4262             :                         goto memory_error;
    4263         356 :                 params = new_params;
    4264             : 
    4265             :                 /*
    4266             :                  * The parameteter data has been passed by reference
    4267             :                  * i.e. using ct_setparam rather than ct_param
    4268             :                  */
    4269         356 :                 temp_type = p->datatype;
    4270         356 :                 tds_type = _ct_get_server_type(tds, p->datatype);
    4271         356 :                 if (tds_type == TDS_INVALID_TYPE)
    4272             :                         goto type_error;
    4273         356 :                 if (p->param_by_value == 0) {
    4274             : 
    4275             :                         /*
    4276             :                          * there are three ways to indicate null parameters
    4277             :                          * 1) *ind == -1
    4278             :                          * 2) *datalen == 0
    4279             :                          * 3) value, datalen and ind as NULL. Here value == NULL is
    4280             :                          *    sufficient
    4281             :                          */
    4282         140 :                         if (*(p->ind) != -1 && p->value != NULL && *(p->datalen) != 0) {
    4283             :                                 /* datafmt.datalen is ignored for fixed length types */
    4284         108 :                                 if (is_fixed_type(tds_type)) {
    4285          88 :                                         temp_datalen = tds_get_size_by_type(tds_type);
    4286             :                                 } else {
    4287          20 :                                         temp_datalen = (*(p->datalen) == CS_UNUSED) ? 0 : *(p->datalen);
    4288             :                                 }
    4289             : 
    4290         108 :                                 temp_value = p->value;
    4291             :                         }
    4292             :                 } else {
    4293         216 :                         temp_value = p->value;
    4294         216 :                         temp_datalen = *(p->datalen);
    4295             :                 }
    4296             : 
    4297         356 :                 if (temp_type == CS_VARCHAR_TYPE || temp_type == CS_VARBINARY_TYPE) {
    4298           8 :                         CS_VARCHAR *vc = (CS_VARCHAR *) temp_value;
    4299             : 
    4300           8 :                         if (vc) {
    4301           0 :                                 temp_datalen = vc->len;
    4302           0 :                                 temp_value   = (CS_BYTE *) vc->str;
    4303             :                         }
    4304             :                 }
    4305             : 
    4306         356 :                 pcol = params->columns[i];
    4307             : 
    4308             :                 /* meta data */
    4309         356 :                 if (p->name)
    4310         236 :                         if (!tds_dstr_copy(&pcol->column_name, p->name))
    4311             :                                 goto memory_error;
    4312             : 
    4313         356 :                 tds_set_param_type(tds->conn, pcol, tds_type);
    4314             : 
    4315         356 :                 if (temp_datalen == CS_NULLTERM && temp_value)
    4316           0 :                         temp_datalen = strlen((const char*) temp_value);
    4317             : 
    4318         356 :                 pcol->column_prec = p->precision;
    4319         356 :                 pcol->column_scale = p->scale;
    4320         356 :                 if (pcol->column_varint_size) {
    4321         354 :                         if (p->maxlen < 0) {
    4322           0 :                                 tds_free_param_results(params);
    4323           0 :                                 return NULL;
    4324             :                         }
    4325         354 :                         pcol->on_server.column_size = pcol->column_size = p->maxlen;
    4326         354 :                         pcol->column_cur_size = temp_value ? temp_datalen : -1;
    4327         354 :                         if (temp_datalen > 0 && temp_datalen > p->maxlen)
    4328           4 :                                 pcol->on_server.column_size = pcol->column_size = temp_datalen;
    4329             :                 } else {
    4330           2 :                         pcol->column_cur_size = pcol->column_size;
    4331             :                 }
    4332             : 
    4333         356 :                 if (p->status == CS_RETURN)
    4334         152 :                         pcol->column_output = 1;
    4335             :                 else
    4336         204 :                         pcol->column_output = 0;
    4337             : 
    4338             :                 /* actual data */
    4339         356 :                 tdsdump_log(TDS_DBG_FUNC, "paraminfoalloc: status = %d, maxlen %d \n", p->status, p->maxlen);
    4340         356 :                 tdsdump_log(TDS_DBG_FUNC,
    4341             :                             "paraminfoalloc: name = %s, varint size %d "
    4342             :                             "column_type %d size %d, %d column_cur_size %d column_output = %d\n",
    4343           0 :                             tds_dstr_cstr(&pcol->column_name),
    4344           0 :                             pcol->column_varint_size, pcol->column_type,
    4345             :                             pcol->on_server.column_size, pcol->column_size,
    4346           0 :                             pcol->column_cur_size, pcol->column_output);
    4347         356 :                 prow = paramrowalloc(params, pcol, i, temp_value, temp_datalen);
    4348         356 :                 if (!prow)
    4349             :                         goto memory_error;
    4350             :         }
    4351             : 
    4352             :         return params;
    4353             : 
    4354           0 : memory_error:
    4355           0 :         tdsdump_log(TDS_DBG_SEVERE, "out of memory for rpc!");
    4356           0 :         _ctclient_msg(NULL, ((CS_CONNECTION*)tds_get_parent(tds)), "paraminfoalloc", 1, 1, 17, 2, "");
    4357           0 : type_error:
    4358           0 :         tds_free_param_results(params);
    4359           0 :         return NULL;
    4360             : }
    4361             : 
    4362             : static void
    4363        3426 : rpc_clear(CSREMOTE_PROC * rpc)
    4364             : {
    4365        3426 :         tdsdump_log(TDS_DBG_FUNC, "rpc_clear(%p)\n", rpc);
    4366             : 
    4367        3426 :         if (!rpc)
    4368             :                 return;
    4369             : 
    4370          60 :         param_clear(rpc->param_list);
    4371             : 
    4372          60 :         free(rpc->name);
    4373          60 :         free(rpc);
    4374             : }
    4375             : 
    4376             : /**
    4377             :  * recursively erase the parameter list
    4378             :  */
    4379             : static void
    4380         356 : param_clear(CS_PARAM * pparam)
    4381             : {
    4382         356 :         tdsdump_log(TDS_DBG_FUNC, "param_clear(%p)\n", pparam);
    4383             : 
    4384         356 :         if (!pparam)
    4385             :                 return;
    4386             : 
    4387         292 :         if (pparam->next) {
    4388         232 :                 param_clear(pparam->next);
    4389         232 :                 pparam->next = NULL;
    4390             :         }
    4391             : 
    4392             :         /* free self after clearing children */
    4393             : 
    4394         292 :         free(pparam->name);
    4395         292 :         if (pparam->param_by_value)
    4396         216 :                 free(pparam->value);
    4397             : 
    4398             :         /*
    4399             :          * DO NOT free datalen or ind, they are just pointer
    4400             :          * to client data or private structure
    4401             :          */
    4402             : 
    4403         292 :         free(pparam);
    4404             : }
    4405             : 
    4406             : /* RPC Code changes ends here */
    4407             : 
    4408             : 
    4409             : static int
    4410         292 : _ct_fill_param(CS_INT cmd_type, CS_PARAM *param,
    4411             :                const CS_DATAFMT_LARGE *datafmt, CS_VOID *data, CS_INT *p_datalen,
    4412             :                CS_SMALLINT *indicator, CS_BYTE byvalue)
    4413             : {
    4414             :         TDS_SERVER_TYPE desttype;
    4415             : 
    4416         292 :         tdsdump_log(TDS_DBG_FUNC, "_ct_fill_param(%d, %p, %p, %p, %p, %p, %x)\n",
    4417             :                                 cmd_type, param, datafmt, data, p_datalen, indicator, byvalue);
    4418             : 
    4419         292 :         if (cmd_type == CS_DYNAMIC_CMD) {
    4420          16 :                 param->name = NULL;
    4421             :         } else {
    4422         276 :                 CS_INT namelen = datafmt->namelen;
    4423         276 :                 namelen = _ct_get_string_length(datafmt->name, namelen);
    4424         276 :                 if (namelen > 0) {
    4425         180 :                         param->name = tds_strndup(datafmt->name, namelen);
    4426         180 :                         if (!param->name)
    4427             :                                 return CS_FAIL;
    4428             :                 } else {
    4429          96 :                         param->name = NULL;
    4430             :                 }
    4431             :         }
    4432             : 
    4433         292 :         param->status = datafmt->status;
    4434         292 :         tdsdump_log(TDS_DBG_INFO1, " _ct_fill_param() status = %d \n", param->status);
    4435             : 
    4436             :         /*
    4437             :          * translate datafmt.datatype, e.g. CS_SMALLINT_TYPE
    4438             :          * to Server type, e.g. SYBINT2
    4439             :          */
    4440         292 :         desttype = _ct_get_server_type(NULL, datafmt->datatype);
    4441         292 :         if (desttype == TDS_INVALID_TYPE)
    4442             :                 return CS_FAIL;
    4443         292 :         param->datatype = datafmt->datatype;
    4444             : 
    4445         292 :         if (is_numeric_type(desttype)) {
    4446           0 :                 param->scale = datafmt->scale;
    4447           0 :                 param->precision = datafmt->precision;
    4448           0 :                 if (param->scale < 0 || param->precision < 0
    4449           0 :                     || param->precision > MAXPRECISION || param->scale > param->precision)
    4450             :                         return CS_FAIL;
    4451             :         }
    4452             : 
    4453         292 :         param->maxlen = datafmt->maxlength;
    4454             : 
    4455         292 :         if (is_fixed_type(desttype)) {
    4456         200 :                 param->maxlen = tds_get_size_by_type(desttype);
    4457             :         }
    4458             : 
    4459         292 :         param->param_by_value = byvalue;
    4460             : 
    4461         292 :         if (byvalue) {
    4462         216 :                 CS_INT datalen = *p_datalen;
    4463             : 
    4464         216 :                 param->datalen = &param->datalen_value;
    4465         216 :                 *(param->datalen) = datalen;
    4466             : 
    4467         216 :                 param->ind = &param->indicator_value;
    4468         216 :                 *(param->ind) = *indicator;
    4469             : 
    4470             :                 /*
    4471             :                  * There are two ways to indicate a parameter with a null value:
    4472             :                  * - Pass indicator as -1. In this case, data and datalen are ignored.
    4473             :                  * - Pass data as NULL and datalen as 0 or CS_UNUSED
    4474             :                  */
    4475         216 :                 if (*indicator == -1 || (!data && (datalen == 0 || datalen == CS_UNUSED))) {
    4476          24 :                         param->value = NULL;
    4477          24 :                         datalen = 0;
    4478             :                 } else {
    4479             :                         /* datafmt.datalen is ignored for fixed length types */
    4480             : 
    4481         192 :                         if (is_fixed_type(desttype)) {
    4482         136 :                                 datalen = tds_get_size_by_type(desttype);
    4483             :                         } else {
    4484          56 :                                 datalen = (datalen == CS_UNUSED) ? 0 : datalen;
    4485             :                         }
    4486             : 
    4487         192 :                         if (data) {
    4488         192 :                                 if (datalen == CS_NULLTERM) {
    4489           0 :                                         tdsdump_log(TDS_DBG_INFO1,
    4490             :                                                     " _ct_fill_param() about to strdup string %u bytes long\n",
    4491           0 :                                                     (unsigned int) strlen((const char*) data));
    4492           0 :                                         datalen = strlen((const char*) data);
    4493         192 :                                 } else if (datalen < 0) {
    4494             :                                         return CS_FAIL;
    4495             :                                 }
    4496         192 :                                 param->value = tds_new(CS_BYTE, datalen ? datalen : 1);
    4497         192 :                                 if (!param->value)
    4498             :                                         return CS_FAIL;
    4499         192 :                                 memcpy(param->value, data, datalen);
    4500         192 :                                 param->param_by_value = 1;
    4501             :                         } else {
    4502           0 :                                 param->value = NULL;
    4503           0 :                                 datalen = 0;
    4504             :                         }
    4505             :                 }
    4506         216 :                 *(param->datalen) = datalen;
    4507             :         } else {                /* not by value, i.e. by reference */
    4508          76 :                 param->datalen = p_datalen;
    4509          76 :                 param->ind = indicator;
    4510          76 :                 param->value = (CS_BYTE*) data;
    4511             :         }
    4512             :         return CS_SUCCEED;
    4513             : }
    4514             : 
    4515             : /* Code added for ct_diag implementation */
    4516             : /* Code changes start here - CT_DIAG - 02*/
    4517             : 
    4518             : CS_RETCODE
    4519         176 : ct_diag(CS_CONNECTION * conn, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
    4520             : {
    4521         176 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag(%p, %d, %d, %d, %p)\n", conn, operation, type, idx, buffer);
    4522             : 
    4523         176 :         switch (operation) {
    4524          24 :         case CS_INIT:
    4525          24 :                 if (conn->ctx->cs_errhandletype == _CS_ERRHAND_CB) {
    4526             :                         /* contrary to the manual page you don't seem to */
    4527             :                         /* be able to turn on inline message handling    */
    4528             :                         /* using cs_diag, once a callback is installed!  */
    4529             :                         return CS_FAIL;
    4530             :                 }
    4531             : 
    4532          24 :                 conn->ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
    4533             : 
    4534          24 :                 if (conn->ctx->cs_diag_msglimit_client == 0)
    4535          24 :                         conn->ctx->cs_diag_msglimit_client = CS_NO_LIMIT;
    4536             : 
    4537          24 :                 if (conn->ctx->cs_diag_msglimit_server == 0)
    4538          24 :                         conn->ctx->cs_diag_msglimit_server = CS_NO_LIMIT;
    4539             : 
    4540          24 :                 if (conn->ctx->cs_diag_msglimit_total == 0)
    4541          24 :                         conn->ctx->cs_diag_msglimit_total = CS_NO_LIMIT;
    4542             : 
    4543          24 :                 conn->ctx->clientmsg_cb = (CS_CLIENTMSG_FUNC) ct_diag_storeclientmsg;
    4544          24 :                 conn->ctx->servermsg_cb = (CS_SERVERMSG_FUNC) ct_diag_storeservermsg;
    4545             : 
    4546          24 :                 break;
    4547             : 
    4548          24 :         case CS_MSGLIMIT:
    4549          24 :                 if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
    4550             :                         return CS_FAIL;
    4551             : 
    4552          24 :                 if (type == CS_CLIENTMSG_TYPE)
    4553           8 :                         conn->ctx->cs_diag_msglimit_client = *(CS_INT *) buffer;
    4554             : 
    4555          24 :                 if (type == CS_SERVERMSG_TYPE)
    4556           8 :                         conn->ctx->cs_diag_msglimit_server = *(CS_INT *) buffer;
    4557             : 
    4558          24 :                 if (type == CS_ALLMSG_TYPE)
    4559           8 :                         conn->ctx->cs_diag_msglimit_total = *(CS_INT *) buffer;
    4560             : 
    4561             :                 break;
    4562             : 
    4563          24 :         case CS_CLEAR:
    4564          24 :                 if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
    4565             :                         return CS_FAIL;
    4566          24 :                 return _ct_diag_clearmsg(conn->ctx, type);
    4567             :                 break;
    4568             : 
    4569          40 :         case CS_GET:
    4570          40 :                 if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
    4571             :                         return CS_FAIL;
    4572             : 
    4573          40 :                 if (!buffer)
    4574             :                         return CS_FAIL;
    4575             : 
    4576          40 :                 if (type == CS_CLIENTMSG_TYPE) {
    4577          16 :                         if (idx == 0
    4578          16 :                             || (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_client))
    4579             :                                 return CS_FAIL;
    4580             : 
    4581          16 :                         return ct_diag_getclientmsg(conn->ctx, idx, (CS_CLIENTMSG *) buffer);
    4582             :                 }
    4583             : 
    4584          24 :                 if (type == CS_SERVERMSG_TYPE) {
    4585          24 :                         if (idx == 0
    4586          24 :                             || (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_server))
    4587             :                                 return CS_FAIL;
    4588          24 :                         return ct_diag_getservermsg(conn->ctx, idx, (CS_SERVERMSG *) buffer);
    4589             :                 }
    4590             : 
    4591             :                 break;
    4592             : 
    4593          64 :         case CS_STATUS:
    4594          64 :                 if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
    4595             :                         return CS_FAIL;
    4596          64 :                 if (!buffer)
    4597             :                         return CS_FAIL;
    4598             : 
    4599          64 :                 return (ct_diag_countmsg(conn->ctx, type, (CS_INT *) buffer));
    4600             :                 break;
    4601             :         }
    4602             :         return CS_SUCCEED;
    4603             : }
    4604             : 
    4605             : static CS_INT
    4606          16 : ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message)
    4607             : {
    4608             :         struct cs_diag_msg_client **curptr;
    4609          16 :         CS_INT msg_count = 0;
    4610             : 
    4611          16 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag_storeclientmsg(%p, %p, %p)\n", context, conn, message);
    4612             : 
    4613          16 :         curptr = &(conn->ctx->clientstore);
    4614             : 
    4615             :         /* if we already have a list of messages, go to the end of the list... */
    4616             : 
    4617          32 :         while (*curptr != NULL) {
    4618           0 :                 msg_count++;
    4619           0 :                 curptr = &((*curptr)->next);
    4620             :         }
    4621             : 
    4622             :         /* messages over and above the agreed limit */
    4623             :         /* are simply discarded...                  */
    4624             : 
    4625          16 :         if (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_client) {
    4626             :                 return CS_FAIL;
    4627             :         }
    4628             : 
    4629             :         /* messages over and above the agreed TOTAL limit */
    4630             :         /* are simply discarded */
    4631             : 
    4632          16 :         if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
    4633             :                 const struct cs_diag_msg_svr *scurptr;
    4634             : 
    4635           8 :                 scurptr = conn->ctx->svrstore;
    4636          16 :                 while (scurptr != NULL) {
    4637           0 :                         msg_count++;
    4638           0 :                         scurptr = scurptr->next;
    4639             :                 }
    4640           8 :                 if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
    4641             :                         return CS_FAIL;
    4642             :                 }
    4643             :         }
    4644             : 
    4645          16 :         *curptr = tds_new(struct cs_diag_msg_client, 1);
    4646          16 :         if (!*curptr)
    4647             :                 return CS_FAIL;
    4648             : 
    4649          16 :         (*curptr)->next = NULL;
    4650          16 :         memcpy(&(*curptr)->clientmsg, message, sizeof(CS_CLIENTMSG));
    4651             : 
    4652          16 :         return CS_SUCCEED;
    4653             : }
    4654             : 
    4655             : static CS_INT
    4656          24 : ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message)
    4657             : {
    4658             :         struct cs_diag_msg_svr **curptr;
    4659             : 
    4660          24 :         CS_INT msg_count = 0;
    4661             : 
    4662          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag_storeservermsg(%p, %p, %p)\n", context, conn, message);
    4663             : 
    4664          24 :         curptr = &(conn->ctx->svrstore);
    4665             : 
    4666             :         /* if we already have a list of messages, go to the end of the list...  */
    4667             : 
    4668          72 :         while (*curptr != NULL) {
    4669          24 :                 msg_count++;
    4670          24 :                 curptr = &((*curptr)->next);
    4671             :         }
    4672             : 
    4673             :         /* messages over and above the agreed limit */
    4674             :         /* are simply discarded...                  */
    4675             : 
    4676          24 :         if (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_server) {
    4677             :                 return CS_FAIL;
    4678             :         }
    4679             : 
    4680             :         /* messages over and above the agreed TOTAL limit */
    4681             :         /* are simply discarded...                  */
    4682             : 
    4683          24 :         if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
    4684             :                 const struct cs_diag_msg_client *ccurptr;
    4685             : 
    4686          24 :                 ccurptr = conn->ctx->clientstore;
    4687          72 :                 while (ccurptr != NULL) {
    4688          24 :                         msg_count++;
    4689          24 :                         ccurptr = ccurptr->next;
    4690             :                 }
    4691          24 :                 if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
    4692             :                         return CS_FAIL;
    4693             :                 }
    4694             :         }
    4695             : 
    4696          24 :         *curptr = tds_new(struct cs_diag_msg_svr, 1);
    4697          24 :         if (!*curptr)
    4698             :                 return CS_FAIL;
    4699             : 
    4700          24 :         (*curptr)->next = NULL;
    4701          48 :         memcpy(&(*curptr)->servermsg, message, cs_servermsg_len(conn->ctx));
    4702             : 
    4703          24 :         return CS_SUCCEED;
    4704             : }
    4705             : 
    4706             : static CS_INT
    4707          16 : ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message)
    4708             : {
    4709             :         const struct cs_diag_msg_client *curptr;
    4710          16 :         CS_INT msg_count = 0;
    4711             : 
    4712          16 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag_getclientmsg(%p, %d, %p)\n", context, idx, message);
    4713             : 
    4714          16 :         curptr = context->clientstore;
    4715             : 
    4716             :         /* if we already have a list of messages, go to the end of the list...  */
    4717             : 
    4718          32 :         while (curptr != NULL) {
    4719          16 :                 msg_count++;
    4720          16 :                 if (msg_count == idx) {
    4721          16 :                         memcpy(message, &curptr->clientmsg, sizeof(CS_CLIENTMSG));
    4722          16 :                         return CS_SUCCEED;
    4723             :                 }
    4724           0 :                 curptr = curptr->next;
    4725             :         }
    4726             : 
    4727             :         return CS_NOMSG;
    4728             : }
    4729             : 
    4730             : static CS_INT
    4731          24 : ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message)
    4732             : {
    4733             :         struct cs_diag_msg_svr *curptr;
    4734          24 :         CS_INT msg_count = 0;
    4735             : 
    4736          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag_getservermsg(%p, %d, %p)\n", context, idx, message);
    4737             : 
    4738          24 :         curptr = context->svrstore;
    4739             : 
    4740             :         /* if we already have a list of messages, go to the end of the list...  */
    4741             : 
    4742          72 :         while (curptr != NULL) {
    4743          48 :                 msg_count++;
    4744          48 :                 if (msg_count == idx) {
    4745          48 :                         memcpy(message, &curptr->servermsg, cs_servermsg_len(context));
    4746          24 :                         return CS_SUCCEED;
    4747             :                 }
    4748          24 :                 curptr = curptr->next;
    4749             :         }
    4750             : 
    4751             :         return CS_NOMSG;
    4752             : }
    4753             : 
    4754             : CS_INT
    4755        1136 : _ct_diag_clearmsg(CS_CONTEXT * context, CS_INT type)
    4756             : {
    4757        1136 :         tdsdump_log(TDS_DBG_FUNC, "_ct_diag_clearmsg(%p, %d)\n", context, type);
    4758             : 
    4759        1136 :         if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
    4760             :                 struct cs_diag_msg_client *curptr, *freeptr;
    4761             : 
    4762        1128 :                 curptr = context->clientstore;
    4763        1128 :                 context->clientstore = NULL;
    4764             : 
    4765        2272 :                 while (curptr != NULL) {
    4766          16 :                         freeptr = curptr;
    4767          16 :                         curptr = freeptr->next;
    4768          16 :                         free(freeptr);
    4769             :                 }
    4770             :         }
    4771             : 
    4772        1136 :         if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
    4773             :                 struct cs_diag_msg_svr *scurptr, *sfreeptr;
    4774             : 
    4775        1128 :                 scurptr = context->svrstore;
    4776        1128 :                 context->svrstore = NULL;
    4777             : 
    4778        2280 :                 while (scurptr != NULL) {
    4779          24 :                         sfreeptr = scurptr;
    4780          24 :                         scurptr = sfreeptr->next;
    4781          24 :                         free(sfreeptr);
    4782             :                 }
    4783             :         }
    4784        1136 :         return CS_SUCCEED;
    4785             : }
    4786             : 
    4787             : static CS_INT
    4788          64 : ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count)
    4789             : {
    4790          64 :         CS_INT msg_count = 0;
    4791             : 
    4792          64 :         tdsdump_log(TDS_DBG_FUNC, "ct_diag_countmsg(%p, %d, %p)\n", context, type, count);
    4793             : 
    4794          64 :         if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
    4795             :                 const struct cs_diag_msg_client *curptr;
    4796             : 
    4797          40 :                 curptr = context->clientstore;
    4798             : 
    4799         104 :                 while (curptr != NULL) {
    4800          24 :                         msg_count++;
    4801          24 :                         curptr = curptr->next;
    4802             :                 }
    4803             :         }
    4804             : 
    4805          64 :         if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
    4806             :                 const struct cs_diag_msg_svr *scurptr;
    4807             : 
    4808          40 :                 scurptr = context->svrstore;
    4809             : 
    4810         128 :                 while (scurptr != NULL) {
    4811          48 :                         msg_count++;
    4812          48 :                         scurptr = scurptr->next;
    4813             :                 }
    4814             :         }
    4815          64 :         *count = msg_count;
    4816             : 
    4817          64 :         return CS_SUCCEED;
    4818             : }
    4819             : 
    4820             : /* Code changes ends here - CT_DIAG - 02*/
    4821             : 
    4822             : static CS_DYNAMIC *
    4823          40 : _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int id_len)
    4824             : {
    4825             :         CS_DYNAMIC *dyn;
    4826             :         CS_DYNAMIC **pdyn;
    4827             : 
    4828          40 :         tdsdump_log(TDS_DBG_FUNC, "_ct_allocate_dynamic(%p, %p, %d)\n", con, id, id_len);
    4829             : 
    4830          40 :         id_len = _ct_get_string_length(id, id_len);
    4831          40 :         if (id_len < 0) {
    4832          16 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 5, "%d, idlen", id_len);
    4833          16 :                 return NULL;
    4834             :         }
    4835             : 
    4836          24 :         dyn = tds_new0(CS_DYNAMIC, 1);
    4837          24 :         if (!dyn) {
    4838           0 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 2, "");
    4839           0 :                 return NULL;
    4840             :         }
    4841             : 
    4842          24 :         dyn->id = tds_strndup(id, id_len);
    4843          24 :         if (!dyn->id) {
    4844           0 :                 free(dyn);
    4845           0 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 2, "");
    4846           0 :                 return NULL;
    4847             :         }
    4848             : 
    4849          24 :         if (!con->dynlist) {
    4850          24 :                 tdsdump_log(TDS_DBG_INFO1, "_ct_allocate_dynamic() attaching dynamic command to head\n");
    4851          24 :                 con->dynlist = dyn;
    4852             :         } else {
    4853           0 :                 pdyn = &con->dynlist;
    4854           0 :                 while (*pdyn) {
    4855           0 :                         pdyn = &(*pdyn)->next;
    4856             :                 }
    4857             : 
    4858           0 :                 *pdyn = dyn;
    4859             :         }
    4860             :         return dyn;
    4861             : }
    4862             : 
    4863             : static CS_DYNAMIC *
    4864          64 : _ct_locate_dynamic(CS_CONNECTION * con, char *id, int id_len)
    4865             : {
    4866             :         CS_DYNAMIC *dyn;
    4867             : 
    4868          64 :         tdsdump_log(TDS_DBG_FUNC, "_ct_locate_dynamic(%p, %p, %d)\n", con, id, id_len);
    4869             : 
    4870          64 :         id_len = _ct_get_string_length(id, id_len);
    4871          64 :         if (id_len < 0) {
    4872           8 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 5, "%d, idlen", id_len);
    4873           8 :                 return NULL;
    4874             :         }
    4875             : 
    4876          56 :         tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() looking for %s\n", (char *) id);
    4877             : 
    4878          72 :         for (dyn = con->dynlist; dyn != NULL; dyn = dyn->next) {
    4879          56 :                 tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() matching with %s\n", (char *) dyn->id);
    4880          56 :                 if (strncmp(dyn->id, id, id_len) == 0 && strlen(dyn->id) == id_len + 0u)
    4881             :                         break;
    4882             :         }
    4883             : 
    4884          56 :         if (!dyn)
    4885          16 :                 _ctclient_msg(NULL, con, "ct_dynamic", 1, 1, 1, 135, "");
    4886             :         return dyn;
    4887             : }
    4888             : 
    4889             : static CS_INT
    4890          24 : _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn)
    4891             : {
    4892             :         CS_DYNAMIC **pvictim;
    4893             : 
    4894          24 :         tdsdump_log(TDS_DBG_FUNC, "_ct_deallocate_dynamic(%p, %p)\n", con, dyn);
    4895             : 
    4896          24 :         if (!dyn)
    4897             :                 return CS_SUCCEED;
    4898             : 
    4899          24 :         pvictim = &con->dynlist;
    4900          48 :         for (; *pvictim != dyn;) {
    4901           0 :                 if (!*pvictim) {
    4902           0 :                         tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : cannot find entry in list\n");
    4903             :                         return CS_FAIL;
    4904             :                 }
    4905           0 :                 pvictim = &(*pvictim)->next;
    4906             :         }
    4907             : 
    4908             :         /* detach node */
    4909          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinking list\n");
    4910          24 :         *pvictim = dyn->next;
    4911          24 :         dyn->next = NULL;
    4912          24 :         tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinked list\n");
    4913             : 
    4914             :         /* free dynamic */
    4915          24 :         tds_release_dynamic(&dyn->tdsdyn);
    4916          24 :         free(dyn->id);
    4917          24 :         free(dyn->stmt);
    4918          24 :         param_clear(dyn->param_list);
    4919             : 
    4920          24 :         free(dyn);
    4921             : 
    4922          24 :         return CS_SUCCEED;
    4923             : }
    4924             : 
    4925             : static CS_INT
    4926             : _ct_map_compute_op(CS_INT comp_op)
    4927             : {
    4928           0 :         switch (comp_op) {
    4929             :         case SYBAOPCNT:
    4930             :         case SYBAOPCNTU:
    4931             :         case SYBAOPCNT_BIG:
    4932             :                 return CS_OP_COUNT;
    4933           0 :         case SYBAOPSUM:
    4934             :         case SYBAOPSUMU:
    4935             :                 return CS_OP_SUM;
    4936           0 :         case SYBAOPAVG:
    4937             :         case SYBAOPAVGU:
    4938             :                 return CS_OP_AVG;
    4939           0 :         case SYBAOPMIN:
    4940             :                 return CS_OP_MIN;
    4941           0 :         case SYBAOPMAX:
    4942             :                 return CS_OP_MAX;
    4943             :         }
    4944             :         return comp_op;
    4945             : }

Generated by: LCOV version 1.13