LCOV - code coverage report
Current view: top level - src/ctlib - ct.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1736 2577 67.4 %
Date: 2026-11-07 23:58:45 Functions: 60 66 90.9 %

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

Generated by: LCOV version 1.13