LCOV - code coverage report
Current view: top level - src/ctlib - ct.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1669 2539 65.7 %
Date: 2026-03-24 22:22:09 Functions: 58 65 89.2 %

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

Generated by: LCOV version 1.13