LCOV - code coverage report
Current view: top level - src/ctlib - ct.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1492 2364 63.1 %
Date: 2025-01-18 12:13:41 Functions: 56 61 91.8 %

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

Generated by: LCOV version 1.13