src/dbapi/driver/ftds64/freetds/ctlib/ct.c

Go to the documentation of this file.
00001 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
00002  * Copyright (C) 1998, 1999, 2000, 2001  Brian Bruns
00003  * Copyright (C) 2002, 2003, 2004, 2005  James K. Lowden
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the
00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #if HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif /* HAVE_CONFIG_H */
00024 
00025 #include <stdio.h>
00026 #include <assert.h>
00027 
00028 #if HAVE_STDLIB_H
00029 #include <stdlib.h>
00030 #endif /* HAVE_STDLIB_H */
00031 
00032 #if HAVE_STRING_H
00033 #include <string.h>
00034 #endif /* HAVE_STRING_H */
00035 
00036 #include "ctpublic.h"
00037 #include "ctlib.h"
00038 #include "tdsstring.h"
00039 #include "replacements.h"
00040 
00041 TDS_RCSID(var, "$Id: ct.c 177293 2009-11-30 13:36:02Z ivanovp $");
00042 
00043 
00044 static char * ct_describe_cmd_state(CS_INT state);
00045 /**
00046  * Read a row of data
00047  * @return 0 on success
00048  */
00049 static int _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read);
00050 int _ct_get_client_type(CS_CONTEXT *ctx, int datatype, int usertype, int size);
00051 static int _ct_fetchable_results(CS_COMMAND * cmd);
00052 static int _ct_process_return_status(TDSSOCKET * tds);
00053 
00054 static int _ct_fill_param(CS_INT cmd_type, CS_PARAM * param, CS_DATAFMT * datafmt, CS_VOID * data,
00055               CS_INT * datalen, CS_SMALLINT * indicator, CS_BYTE byvalue);
00056 void _ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number,
00057               const char *fmt, ...);
00058 int _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset);
00059 static void _ct_initialise_cmd(CS_COMMAND *cmd);
00060 static CS_RETCODE _ct_cancel_cleanup(CS_COMMAND * cmd);
00061 static CS_RETCODE _ct_cmd_drop(CS_COMMAND * cmd, CS_INT free_conn_ref);
00062 
00063 /* Added for CT_DIAG */
00064 /* Code changes starts here - CT_DIAG - 01 */
00065 
00066 static CS_INT ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message);
00067 static CS_INT ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message);
00068 static CS_INT ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count);
00069 static CS_INT ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message);
00070 static CS_INT ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message);
00071 
00072 /* Code changes ends here - CT_DIAG - 01 */
00073 
00074 /* Added code for RPC functionality -SUHA */
00075 /* RPC Code changes starts here */
00076 
00077 static void rpc_clear(CSREMOTE_PROC * rpc);
00078 static void param_clear(CSREMOTE_PROC_PARAM * pparam);
00079 
00080 static TDSPARAMINFO *paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param);
00081 
00082 static CS_DYNAMIC * _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen);
00083 static CS_INT  _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn);
00084 static CS_DYNAMIC * _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen);
00085 
00086 /* RPC Code changes ends here */
00087 
00088 void _csclient_msg(CS_CONTEXT * ctx, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...);
00089 
00090 
00091 static const char *
00092 _ct_get_layer(int layer)
00093 {
00094     switch (layer) {
00095     case 1:
00096         return "user api layer";
00097         break;
00098     case 2:
00099         return "blk layer";
00100         break;
00101     default:
00102         break;
00103     }
00104     return "unrecognized layer";
00105 }
00106 
00107 static const char *
00108 _ct_get_origin(int origin)
00109 {
00110     switch (origin) {
00111     case 1:
00112         return "external error";
00113         break;
00114     case 2:
00115         return "internal CT-Library error";
00116         break;
00117     case 4:
00118         return "common library error";
00119         break;
00120     case 5:
00121         return "intl library error";
00122         break;
00123     case 6:
00124         return "user error";
00125         break;
00126     case 7:
00127         return "internal BLK-Library error";
00128         break;
00129     default:
00130         break;
00131     }
00132     return "unrecognized origin";
00133 }
00134 
00135 static const char *
00136 _ct_get_user_api_layer_error(int error)
00137 {
00138     switch (error) {
00139     case 137:
00140         return "A bind count of %1! is not consistent with the count supplied for existing binds. The current bind count is %2!.";
00141         break;
00142     case 138:
00143         return "Use direction CS_BLK_IN or CS_BLK_OUT for a bulk copy operation.";
00144         break;
00145     case 139:
00146         return "The parameter tblname cannot be NULL.";
00147         break;
00148     case 140:
00149         return "Failed when processing results from server.";
00150         break;
00151     case 141:
00152         return "Parameter %1! has an illegal value of %2!";
00153         break;
00154     case 142:
00155         return "No value or default value available and NULL not allowed. col = %1! row = %2! .";
00156         break;
00157     case 143:
00158         return "parameter name(s) must be supplied for LANGUAGE command.";
00159         break;
00160     case 16843163:
00161         return "This routine cannot be called when the command structure is idle.";
00162         break;
00163     case 16843164:
00164         return "Cannot send anything else but Text/Image for column %1! when server datatype is Text/Image";
00165         break;
00166     default:
00167         break;
00168     }
00169     return "unrecognized error";
00170 }
00171 
00172 static char *
00173 _ct_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
00174 {
00175     char *m;
00176 
00177     if (asprintf(&m,
00178              "%s: %s: %s: %s", funcname, _ct_get_layer(layer), _ct_get_origin(origin), _ct_get_user_api_layer_error(number)
00179         ) < 0) {
00180         return NULL;
00181     }
00182     return m;
00183 }
00184 
00185 void
00186 _ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...)
00187 {
00188     CS_CONTEXT *ctx = con->ctx;
00189     va_list ap;
00190     CS_CLIENTMSG cm;
00191     char *msgstr;
00192 
00193     va_start(ap, fmt);
00194 
00195     if (ctx->_clientmsg_cb) {
00196         cm.severity = severity;
00197         cm.msgnumber = (((layer << 24) & 0xFF000000)
00198                 | ((origin << 16) & 0x00FF0000)
00199                 | ((severity << 8) & 0x0000FF00)
00200                 | ((number) & 0x000000FF));
00201         msgstr = _ct_get_msgstr(funcname, layer, origin, severity, number);
00202         tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
00203         cm.msgstring[cm.msgstringlen] = '\0';
00204         free(msgstr);
00205         cm.osnumber = 0;
00206         cm.osstring[0] = '\0';
00207         cm.osstringlen = 0;
00208         cm.status = 0;
00209         /* cm.sqlstate */
00210         cm.sqlstatelen = 0;
00211         ctx->_clientmsg_cb(ctx, con, &cm);
00212     }
00213 
00214     va_end(ap);
00215 }
00216 
00217 static CS_RETCODE
00218 ct_set_command_state(CS_COMMAND *cmd, CS_INT state) {
00219 
00220     tdsdump_log(TDS_DBG_FUNC, "setting command state from %s to %s\n",
00221             ct_describe_cmd_state(cmd->command_state),
00222             ct_describe_cmd_state(state));
00223 
00224     cmd->command_state = state;
00225 
00226     return CS_SUCCEED;
00227 }
00228 
00229 static char *
00230 ct_describe_cmd_state(CS_INT state) {
00231     switch (state) {
00232     case _CS_COMMAND_IDLE:
00233         return "IDLE";
00234     case _CS_COMMAND_BUILDING:
00235         return "BUILDING";
00236     case _CS_COMMAND_READY:
00237         return "READY";
00238     case _CS_COMMAND_SENT:
00239         return "SENT";
00240     }
00241     return "???";
00242 }
00243 
00244 CS_RETCODE
00245 ct_exit(CS_CONTEXT * ctx, CS_INT unused)
00246 {
00247     tdsdump_log(TDS_DBG_FUNC, "ct_exit()\n");
00248     return CS_SUCCEED;
00249 }
00250 
00251 CS_RETCODE
00252 ct_init(CS_CONTEXT * ctx, CS_INT version)
00253 {
00254     /* uncomment the next line to get pre-login trace */
00255     /* tdsdump_open("/tmp/tds2.log"); */
00256     tdsdump_log(TDS_DBG_FUNC, "ct_init()\n");
00257     ctx->tds_ctx->msg_handler = _ct_handle_server_message;
00258     ctx->tds_ctx->err_handler = _ct_handle_client_message;
00259 
00260     return CS_SUCCEED;
00261 }
00262 
00263 CS_RETCODE
00264 ct_con_alloc(CS_CONTEXT * ctx, CS_CONNECTION ** con)
00265 {
00266     TDSLOGIN *login;
00267 
00268     tdsdump_log(TDS_DBG_FUNC, "ct_con_alloc()\n");
00269     login = tds_alloc_login();
00270     if (!login)
00271         return CS_FAIL;
00272     *con = (CS_CONNECTION *) malloc(sizeof(CS_CONNECTION));
00273     if (!*con) {
00274         tds_free_login(login);
00275         return CS_FAIL;
00276     }
00277     memset(*con, '\0', sizeof(CS_CONNECTION));
00278     (*con)->tds_login = login;
00279 
00280     /* so we know who we belong to */
00281     (*con)->ctx = ctx;
00282 
00283     /* set default values */
00284     tds_set_library((*con)->tds_login, "CT-Library");
00285     /* tds_set_client_charset((*con)->tds_login, "iso_1"); */
00286     /* tds_set_packet((*con)->tds_login, TDS_DEF_BLKSZ); */
00287     return CS_SUCCEED;
00288 }
00289 
00290 CS_RETCODE
00291 ct_callback(CS_CONTEXT * ctx, CS_CONNECTION * con, CS_INT action, CS_INT type, CS_VOID * func)
00292 {
00293     int (*funcptr) (void *, void *, void *) = (int (*)(void *, void *, void *)) func;
00294 
00295     tdsdump_log(TDS_DBG_FUNC, "ct_callback() action = %s\n", CS_GET ? "CS_GET" : "CS_SET");
00296     /* one of these has to be defined */
00297     if (!ctx && !con)
00298         return CS_FAIL;
00299 
00300     if (action == CS_GET) {
00301         switch (type) {
00302         case CS_CLIENTMSG_CB:
00303             *(void **) func = (CS_VOID *) (con ? con->_clientmsg_cb : ctx->_clientmsg_cb);
00304             return CS_SUCCEED;
00305         case CS_SERVERMSG_CB:
00306             *(void **) func = (CS_VOID *) (con ? con->_servermsg_cb : ctx->_servermsg_cb);
00307             return CS_SUCCEED;
00308         default:
00309             _csclient_msg(ctx, "ct_callback", 2, 1, 16, 27, "%d", type);
00310             *(void **) func = NULL;
00311             return CS_SUCCEED;
00312         }
00313     }
00314     /* CS_SET */
00315     switch (type) {
00316     case CS_CLIENTMSG_CB:
00317         if (con)
00318             con->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
00319         else
00320             ctx->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
00321         break;
00322     case CS_SERVERMSG_CB:
00323         if (con)
00324             con->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
00325         else
00326             ctx->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
00327         break;
00328     }
00329     return CS_SUCCEED;
00330 }
00331 
00332 CS_RETCODE
00333 ct_con_props(CS_CONNECTION * con, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
00334 {
00335     CS_INT intval = 0, maxcp;
00336     TDSSOCKET *tds;
00337     TDSLOGIN *tds_login;
00338     char *set_buffer = NULL;
00339 
00340     tdsdump_log(TDS_DBG_FUNC, "ct_con_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property);
00341 
00342     tds = con->tds_socket;
00343     tds_login = con->tds_login;
00344 
00345     if (action == CS_SET) {
00346         if (property == CS_USERNAME || property == CS_PASSWORD || property == CS_APPNAME ||
00347             property == CS_HOSTNAME || property == CS_SERVERADDR) {
00348             if (buflen == CS_NULLTERM) {
00349                 maxcp = strlen((char *) buffer);
00350                 set_buffer = (char *) malloc(maxcp + 1);
00351                 strcpy(set_buffer, (char *) buffer);
00352             } else if (buflen == CS_UNUSED) {
00353                 return CS_SUCCEED;
00354             } else {
00355                 set_buffer = (char *) malloc(buflen + 1);
00356                 strncpy(set_buffer, (char *) buffer, buflen);
00357                 set_buffer[buflen] = '\0';
00358             }
00359         }
00360 
00361         /*
00362          * XXX "login" properties shouldn't be set after
00363          * login.  I don't know if it should fail silently
00364          * or return an error.
00365          */
00366         switch (property) {
00367         case CS_USERNAME:
00368             tds_set_user(tds_login, set_buffer);
00369             break;
00370         case CS_PASSWORD:
00371             tds_set_passwd(tds_login, set_buffer);
00372             break;
00373         case CS_APPNAME:
00374             tds_set_app(tds_login, set_buffer);
00375             break;
00376         case CS_HOSTNAME:
00377             tds_set_host(tds_login, set_buffer);
00378             break;
00379         case CS_PORT:
00380             tds_set_port(tds_login, *((int *) buffer));
00381             break;
00382         case CS_SERVERADDR: {
00383             /* Format of this property: "[hostname] [port]" */
00384             char *host, *port;
00385             int portno;
00386             host= strtok(set_buffer, " ");
00387             port= strtok(NULL, " ");
00388             if (!host || !port)
00389                 return CS_FAIL;
00390 
00391             portno= (int)strtol(port, NULL, 10);
00392             tds_set_server_addr(tds_login, host);
00393             tds_set_port(tds_login, portno);
00394             break;
00395         }
00396         case CS_LOC_PROP:
00397             con->locale = (CS_LOCALE *) buffer;
00398             break;
00399         case CS_USERDATA:
00400             if (con->userdata)
00401                 free(con->userdata);
00402             con->userdata = (void *) malloc(buflen + 1);
00403             tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, con->userdata);
00404             con->userdata_len = buflen;
00405             memcpy(con->userdata, buffer, buflen);
00406             break;
00407         case CS_BULK_LOGIN:
00408             memcpy(&intval, buffer, sizeof(intval));
00409             if (intval)
00410                 tds_set_bulk(tds_login, 1);
00411             else
00412                 tds_set_bulk(tds_login, 0);
00413             break;
00414         case CS_PACKETSIZE:
00415             memcpy(&intval, buffer, sizeof(intval));
00416             tds_set_packet(tds_login, (short) intval);
00417             break;
00418         case CS_TDS_VERSION:
00419             /*
00420              * FIXME
00421              * (a) We don't support all versions in tds/login.c -
00422              *     I tried to pick reasonable versions.
00423              * (b) Might need support outside of tds/login.c
00424              * (c) It's a "negotiated" property so probably
00425              *     needs tds_process_env_chg() support
00426              * (d) Minor - we don't check against context
00427              *     which should limit the acceptable values
00428              */
00429             if (*(int *) buffer == 0) {
00430                 /* autodetect version */
00431                 tds_set_version(tds_login, 0, 0);
00432             } else if (*(int *) buffer == CS_TDS_40) {
00433                 tds_set_version(tds_login, 4, 2);
00434             } else if (*(int *) buffer == CS_TDS_42) {
00435                 tds_set_version(tds_login, 4, 2);
00436             } else if (*(int *) buffer == CS_TDS_46) {
00437                 tds_set_version(tds_login, 4, 6);
00438             } else if (*(int *) buffer == CS_TDS_495) {
00439                 tds_set_version(tds_login, 4, 6);
00440             } else if (*(int *) buffer == CS_TDS_50) {
00441                 tds_set_version(tds_login, 5, 0);
00442             } else if (*(int *) buffer == CS_TDS_70) {
00443                 tds_set_version(tds_login, 7, 0);
00444             } else if (*(int *) buffer == CS_TDS_80) {
00445                 tds_set_version(tds_login, 8, 0);
00446             } else {
00447                 return CS_FAIL;
00448             }
00449             break;
00450         default:
00451             tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
00452             break;
00453         }
00454         if (set_buffer)
00455             free(set_buffer);
00456     } else if (action == CS_GET) {
00457         switch (property) {
00458         case CS_USERNAME:
00459             if (out_len)
00460                 *out_len = tds_dstr_len(&tds_login->user_name);
00461             tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->user_name), buflen);
00462             break;
00463         case CS_PASSWORD:
00464             if (out_len)
00465                 *out_len = tds_dstr_len(&tds_login->password);
00466             tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->password), buflen);
00467             break;
00468         case CS_APPNAME:
00469             if (out_len)
00470                 *out_len = tds_dstr_len(&tds_login->app_name);
00471             tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->app_name), buflen);
00472             break;
00473         case CS_HOSTNAME:
00474             if (out_len)
00475                 *out_len = tds_dstr_len(&tds_login->client_host_name);
00476             tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->client_host_name), buflen);
00477             break;
00478         case CS_SERVERNAME:
00479             if (out_len)
00480                 *out_len = tds_dstr_len(&tds_login->server_name);
00481             tds_strlcpy((char *) buffer, tds_dstr_cstr(&tds_login->server_name), buflen);
00482             break;
00483         case CS_LOC_PROP:
00484             buffer = (CS_VOID *) con->locale;
00485             break;
00486         case CS_USERDATA:
00487             tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", con->userdata);
00488             maxcp = con->userdata_len;
00489             if (out_len)
00490                 *out_len = maxcp;
00491             if (maxcp > buflen)
00492                 maxcp = buflen;
00493             memcpy(buffer, con->userdata, maxcp);
00494             break;
00495         case CS_CON_STATUS:
00496             if (!(IS_TDSDEAD(tds)))
00497                 intval |= CS_CONSTAT_CONNECTED;
00498             else
00499                 intval &= ~CS_CONSTAT_CONNECTED;
00500             if (tds && tds->state == TDS_DEAD)
00501                 intval |= CS_CONSTAT_DEAD;
00502             else
00503                 intval &= ~CS_CONSTAT_DEAD;
00504             memcpy(buffer, &intval, sizeof(intval));
00505             break;
00506         case CS_BULK_LOGIN:
00507             if (tds_login->bulk_copy)
00508                 intval = CS_FALSE;
00509             else
00510                 intval = CS_TRUE;
00511             memcpy(buffer, &intval, sizeof(intval));
00512             break;
00513         case CS_PACKETSIZE:
00514             if (tds)
00515                 intval = tds->env.block_size;
00516             else
00517                 intval = tds_login->block_size;
00518             memcpy(buffer, &intval, sizeof(intval));
00519             if (out_len)
00520                 *out_len = sizeof(intval);
00521             break;
00522         case CS_TDS_VERSION:
00523             switch (tds_version(tds, NULL)) {
00524             case 40:
00525                 (*(int *) buffer = CS_TDS_40);
00526                 break;
00527             case 42:
00528                 (*(int *) buffer = CS_TDS_42);
00529                 break;
00530             case 46:
00531                 (*(int *) buffer = CS_TDS_46);
00532                 break;
00533             case 40 + 95:
00534                 (*(int *) buffer = CS_TDS_495);
00535                 break;
00536             case 50:
00537                 (*(int *) buffer = CS_TDS_50);
00538                 break;
00539             case 70:
00540                 (*(int *) buffer = CS_TDS_70);
00541                 break;
00542             case 80:
00543                 (*(int *) buffer = CS_TDS_80);
00544                 break;
00545             default:
00546                 return CS_FAIL;
00547             }
00548             break;
00549         case CS_PARENT_HANDLE:
00550             *(CS_CONTEXT **) buffer = con->ctx;
00551             break;
00552 
00553         default:
00554             tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
00555             break;
00556         }
00557     }
00558     return CS_SUCCEED;
00559 }
00560 
00561 static int
00562 ctlib_query_timeout(void *param, unsigned int total_timeout)
00563 {
00564     CS_CONNECTION* con = (CS_CONNECTION*) param;
00565 
00566     if (!con)
00567         return TDS_INT_CONTINUE;
00568 
00569     /* tds_set_state(con->tds_socket, TDS_PENDING); */
00570     tds_set_state(con->tds_socket, TDS_QUERYING);
00571 
00572     /* tds_process_cancel(con->tds_socket); */
00573     ct_cancel(con, NULL, CS_CANCEL_ATTN);
00574 
00575     return TDS_INT_CANCEL;
00576 }
00577 
00578 CS_RETCODE
00579 ct_connect(CS_CONNECTION * con, CS_CHAR * servername, CS_INT snamelen)
00580 {
00581     char *server;
00582     int needfree = 0;
00583     CS_CONTEXT *ctx;
00584     TDSCONNECTION *connection;
00585 
00586     tdsdump_log(TDS_DBG_FUNC, "ct_connect() servername = %s\n", servername ? servername : "NULL");
00587 
00588     if (!tds_dstr_isempty(&con->tds_login->server_addr)) {
00589         server = tds_dstr_cstr(&con->tds_login->server_addr);
00590     } else if (snamelen == 0 || snamelen == CS_UNUSED) {
00591         server = NULL;
00592     } else if (snamelen == CS_NULLTERM) {
00593         server = (char *) servername;
00594     } else {
00595         server = (char *) malloc(snamelen + 1);
00596         needfree++;
00597         strncpy(server, servername, snamelen);
00598         server[snamelen] = '\0';
00599     }
00600     tds_set_server(con->tds_login, server);
00601     if (needfree)
00602         free(server);
00603     ctx = con->ctx;
00604     if (!(con->tds_socket = tds_alloc_socket(ctx->tds_ctx, 512)))
00605         return CS_FAIL;
00606     tds_set_parent(con->tds_socket, (void *) con);
00607     if (!(connection = tds_read_config_info(NULL, con->tds_login, ctx->tds_ctx->locale))) {
00608         tds_free_socket(con->tds_socket);
00609         con->tds_socket = NULL;
00610         return CS_FAIL;
00611     }
00612 
00613     /* Timeouts ... */
00614     con->tds_socket->query_timeout_param = con;
00615     con->tds_socket->query_timeout_func = ctlib_query_timeout;
00616 
00617     if (ctx->login_timeout > 0) {
00618         connection->connect_timeout = ctx->login_timeout;
00619     }
00620 
00621     if (ctx->query_timeout > 0) {
00622         connection->query_timeout = ctx->query_timeout;
00623     }
00624 
00625     if (con->locale && con->locale->charset) {
00626         tds_dstr_copy(&connection->client_charset, con->locale->charset);
00627     }
00628     /*     tds_dstr_copy(&connection->server_charset, "UCS-2LE"); */
00629 
00630     if (tds_connect(con->tds_socket, connection) == TDS_FAIL) {
00631         tds_free_socket(con->tds_socket);
00632         con->tds_socket = NULL;
00633         tds_free_connection(connection);
00634         tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_FAIL);
00635         return CS_FAIL;
00636     }
00637     tds_free_connection(connection);
00638 
00639     tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_SUCCEED);
00640     return CS_SUCCEED;
00641 }
00642 
00643 CS_RETCODE
00644 ct_cmd_alloc(CS_CONNECTION * con, CS_COMMAND ** cmd)
00645 {
00646 
00647     CS_COMMAND_LIST *command_list;
00648     CS_COMMAND_LIST *pcommand;
00649 
00650     tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc()\n");
00651 
00652     *cmd = (CS_COMMAND *) malloc(sizeof(CS_COMMAND));
00653     if (!*cmd)
00654         return CS_FAIL;
00655     memset(*cmd, '\0', sizeof(CS_COMMAND));
00656 
00657     /* so we know who we belong to */
00658     (*cmd)->con = con;
00659 
00660     /* initialise command state */
00661     ct_set_command_state(*cmd, _CS_COMMAND_IDLE);
00662 
00663     command_list = malloc(sizeof(CS_COMMAND_LIST));
00664     memset(command_list, '\0', sizeof(CS_COMMAND_LIST));
00665     command_list->cmd = *cmd;
00666     command_list->next = NULL;
00667 
00668     if ( con->cmds == NULL ) {
00669         tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc() : allocating command list to head\n");
00670         con->cmds = command_list;
00671     } else {
00672         pcommand = con->cmds;
00673         for (;;) {
00674             tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc() : stepping thru existing commands\n");
00675             if (pcommand->next == NULL)
00676                 break;
00677             pcommand = pcommand->next;
00678         }
00679         pcommand->next = command_list;
00680     }
00681 
00682     return CS_SUCCEED;
00683 }
00684 
00685 CS_RETCODE
00686 ct_command(CS_COMMAND * cmd, CS_INT type, const CS_VOID * buffer, CS_INT buflen, CS_INT option)
00687 {
00688     int query_len;
00689     int current_query_len;
00690 
00691     tdsdump_log(TDS_DBG_FUNC, "ct_command()\n");
00692 
00693     /* Unless we are in the process of building a CS_LANG_CMD   */
00694     /* type command, then clear everything, ready to start anew */
00695 
00696     if (cmd->command_state != _CS_COMMAND_BUILDING) {
00697         _ct_initialise_cmd(cmd);
00698         ct_set_command_state(cmd, _CS_COMMAND_IDLE);
00699     }
00700 
00701     switch (type) {
00702     case CS_LANG_CMD:
00703         switch (option) {
00704         case CS_MORE:   /* The text in buffer is only part of the language command to be executed. */
00705         case CS_END:    /* The text in buffer is the last part of the language command to be executed. */
00706         case CS_UNUSED: /* Equivalent to CS_END. */
00707             if (buflen == CS_NULLTERM) {
00708                 query_len = strlen((const char *) buffer);
00709             } else {
00710                 query_len = buflen;
00711             }
00712             /* small fix for no crash */
00713             if (query_len == CS_UNUSED) {
00714                 cmd->query = NULL;
00715                 return CS_FAIL;
00716             }
00717             if (cmd->command_state == _CS_COMMAND_IDLE) {
00718                 cmd->query = (char *) malloc(query_len + 1);
00719                 strncpy(cmd->query, (const char *) buffer, query_len);
00720                 cmd->query[query_len] = '\0';
00721                 if (option == CS_MORE) {
00722                     ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
00723                 } else {
00724                     ct_set_command_state(cmd, _CS_COMMAND_READY);
00725                 }
00726             }
00727             if (cmd->command_state == _CS_COMMAND_BUILDING) {
00728                 current_query_len = strlen(cmd->query);
00729                 cmd->query = (char *) realloc(cmd->query, current_query_len + query_len + 1);
00730                 strncat(cmd->query, (const char *) buffer, query_len);
00731                 cmd->query[current_query_len + query_len] = '\0';
00732                 if (option == CS_MORE) {
00733                     ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
00734                 } else {
00735                     ct_set_command_state(cmd, _CS_COMMAND_READY);
00736                 }
00737             }
00738 
00739             break;
00740         default:
00741             return CS_FAIL;
00742         }
00743         break;
00744 
00745     case CS_RPC_CMD:
00746 
00747         /* Code changed for RPC functionality -SUHA */
00748         /* RPC code changes starts here */
00749 
00750         if (cmd == NULL)
00751             return CS_FAIL;
00752 
00753         cmd->rpc = (CSREMOTE_PROC *) malloc(sizeof(CSREMOTE_PROC));
00754         if (cmd->rpc == NULL)
00755             return CS_FAIL;
00756 
00757         memset(cmd->rpc, 0, sizeof(CSREMOTE_PROC));
00758 
00759         if (buflen == CS_NULLTERM) {
00760             cmd->rpc->name = strdup(buffer);
00761             if (cmd->rpc->name == NULL)
00762                 return CS_FAIL;
00763         } else if (buflen > 0) {
00764             cmd->rpc->name = (char *) malloc(buflen + 1);
00765             if (cmd->rpc->name == NULL)
00766                 return CS_FAIL;
00767             memset(cmd->rpc->name, 0, buflen + 1);
00768             strncpy(cmd->rpc->name, (const char *) buffer, buflen);
00769         } else {
00770             return CS_FAIL;
00771         }
00772 
00773         cmd->rpc->param_list = NULL;
00774 
00775         tdsdump_log(TDS_DBG_INFO1, "ct_command() added rpcname \"%s\"\n", cmd->rpc->name);
00776 
00777         /* FIXME: I don't know the value for RECOMPILE, NORECOMPILE options. Hence assigning zero  */
00778         switch (option) {
00779         case CS_RECOMPILE:  /* Recompile the stored procedure before executing it. */
00780             cmd->rpc->options = 0;
00781             break;
00782         case CS_NO_RECOMPILE:   /* Do not recompile the stored procedure before executing it. */
00783             cmd->rpc->options = 0;
00784             break;
00785         case CS_UNUSED: /* Equivalent to CS_NO_RECOMPILE. */
00786             cmd->rpc->options = 0;
00787             break;
00788         default:
00789             return CS_FAIL;
00790         }
00791         ct_set_command_state(cmd, _CS_COMMAND_READY);
00792         break;
00793         /* RPC code changes ends here */
00794 
00795     case CS_SEND_DATA_CMD:
00796         switch (option) {
00797         case CS_COLUMN_DATA:    /* The data will be used for a text or image column update. */
00798             cmd->send_data_started = 0;
00799             break;
00800         case CS_BULK_DATA:  /* For internal Sybase use only. The data will be used for a bulk copy operation. */
00801         default:
00802             return CS_FAIL;
00803         }
00804         ct_set_command_state(cmd, _CS_COMMAND_READY);
00805         break;
00806 
00807     case CS_SEND_BULK_CMD:
00808         switch (option) {
00809         case CS_BULK_INIT:  /* For internal Sybase use only. Initialize a bulk copy operation. */
00810         case CS_BULK_CONT:  /* For internal Sybase use only. Continue a bulk copy operation. */
00811         default:
00812             return CS_FAIL;
00813         }
00814         ct_set_command_state(cmd, _CS_COMMAND_READY);
00815         break;
00816 
00817     default:
00818         return CS_FAIL;
00819     }
00820 
00821     cmd->command_type = type;
00822 
00823 
00824     return CS_SUCCEED;
00825 }
00826 
00827 static void
00828 _ct_initialise_cmd(CS_COMMAND *cmd)
00829 {
00830     if (cmd->query) {
00831         free(cmd->query);
00832         cmd->query = NULL;
00833     }
00834 
00835     if (cmd->input_params) {
00836         param_clear(cmd->input_params);
00837         cmd->input_params = NULL;
00838     }
00839     ct_set_command_state(cmd, _CS_COMMAND_IDLE);
00840 
00841     rpc_clear(cmd->rpc);
00842     cmd->rpc = NULL;
00843 }
00844 
00845 CS_RETCODE
00846 ct_send(CS_COMMAND * cmd)
00847 {
00848     TDSSOCKET *tds;
00849     CS_RETCODE ret;
00850     CSREMOTE_PROC **rpc;
00851     TDSPARAMINFO *pparam_info;
00852     TDSCURSOR *cursor;
00853     TDSDYNAMIC *tdsdyn;
00854 
00855     tdsdump_log(TDS_DBG_FUNC, "ct_send() command_type = %d\n", cmd->command_type);
00856 
00857     if (!cmd->con || !cmd->con->tds_socket)
00858         return CS_FAIL;
00859 
00860     tds = cmd->con->tds_socket;
00861 
00862     if (cmd->cancel_state == _CS_CANCEL_PENDING) {
00863         _ct_cancel_cleanup(cmd);
00864         return CS_CANCELED;
00865     }
00866 
00867     if (cmd->command_state == _CS_COMMAND_IDLE) {
00868         tdsdump_log(TDS_DBG_FUNC, "ct_send() command_state = IDLE\n");
00869         _ctclient_msg(cmd->con, "ct_send", 1, 1, 1, 16843163, "");
00870         return CS_FAIL;
00871     }
00872 
00873     cmd->results_state = _CS_RES_NONE;
00874 
00875     if (cmd->command_type == CS_DYNAMIC_CMD) {
00876 
00877         if (cmd->dyn == NULL)
00878             return CS_FAIL;
00879 
00880         switch (cmd->dynamic_cmd) {
00881         case CS_PREPARE:
00882             if (tds_submit_prepare(tds, cmd->dyn->stmt, cmd->dyn->id, NULL, NULL) == TDS_FAIL)
00883                 return CS_FAIL;
00884             ct_set_command_state(cmd, _CS_COMMAND_SENT);
00885             return CS_SUCCEED;
00886             break;
00887         case CS_EXECUTE:
00888             pparam_info = paraminfoalloc(tds, cmd->dyn->param_list);
00889             tdsdyn = tds_lookup_dynamic(tds, cmd->dyn->id);
00890             if (!tdsdyn) {
00891                 tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_EXECUTE) no tdsdyn!\n");
00892                 return CS_FAIL;
00893             }
00894             tds_free_input_params(tdsdyn);
00895             tdsdyn->params = pparam_info;
00896             if (tds_submit_execute(tds, tdsdyn) == TDS_FAIL)
00897                 return CS_FAIL;
00898             ct_set_command_state(cmd, _CS_COMMAND_SENT);
00899             return CS_SUCCEED;
00900             break;
00901         case CS_DESCRIBE_INPUT:
00902             tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_INPUT)\n");
00903             ct_set_command_state(cmd, _CS_COMMAND_SENT);
00904             cmd->results_state = _CS_RES_DESCRIBE_RESULT;
00905             if (tds->cur_dyn)
00906                 tds->current_results = tds->cur_dyn->res_info;
00907             else
00908                 tds->current_results = tds->param_info;
00909             break;
00910 
00911         case CS_DESCRIBE_OUTPUT:
00912             tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_OUTPUT)\n");
00913             ct_set_command_state(cmd, _CS_COMMAND_SENT);
00914             cmd->results_state = _CS_RES_DESCRIBE_RESULT;
00915             tds->current_results = tds->res_info;
00916             break;
00917 
00918         case CS_DEALLOC:
00919             tdsdyn = tds_lookup_dynamic(tds, cmd->dyn->id);
00920             if (!tdsdyn) {
00921                 tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DEALLOC) no tdsdyn!\n");
00922                 return CS_FAIL;
00923             }
00924             if (tds_submit_unprepare(tds, tdsdyn) == TDS_FAIL)
00925                 return CS_FAIL;
00926             else {
00927                 ct_set_command_state(cmd, _CS_COMMAND_SENT);
00928                 return CS_SUCCEED;
00929             }
00930             break;
00931 
00932         default:
00933             return CS_FAIL;
00934         }
00935     }
00936 
00937     if (cmd->command_type == CS_RPC_CMD) {
00938         /* sanity */
00939         if (cmd == NULL || cmd->rpc == NULL /* ct_command should allocate pointer */
00940             || cmd->rpc->name == NULL) {    /* can't be ready without a name      */
00941             return CS_FAIL;
00942         }
00943 
00944         rpc = &(cmd->rpc);
00945         pparam_info = paraminfoalloc(tds, cmd->rpc->param_list);
00946         ret = tds_submit_rpc(tds, cmd->rpc->name, pparam_info);
00947 
00948         tds_free_param_results(pparam_info);
00949 
00950         ct_set_command_state(cmd, _CS_COMMAND_SENT);
00951 
00952         if (ret == TDS_FAIL) {
00953             return CS_FAIL;
00954         }
00955 
00956         return CS_SUCCEED;
00957     }
00958 
00959     /* RPC Code changes ends here */
00960 
00961     if (cmd->command_type == CS_LANG_CMD) {
00962         ret = CS_FAIL;
00963         if (cmd->input_params) {
00964             pparam_info = paraminfoalloc(tds, cmd->input_params);
00965             ret = tds_submit_query_params(tds, cmd->query, pparam_info);
00966             tds_free_param_results(pparam_info);
00967         } else {
00968             ret = tds_submit_query(tds, cmd->query);
00969         }
00970 
00971         ct_set_command_state(cmd, _CS_COMMAND_SENT);
00972 
00973         if (ret == TDS_FAIL) {
00974             tdsdump_log(TDS_DBG_WARN, "ct_send() failed\n");
00975             return CS_FAIL;
00976         }
00977         tdsdump_log(TDS_DBG_INFO2, "ct_send() succeeded\n");
00978         return CS_SUCCEED;
00979     }
00980 
00981     /* Code added for CURSOR support */
00982 
00983     if (cmd->command_type == CS_CUR_CMD) {
00984         /* sanity */
00985         /*
00986          * ct_cursor declare should allocate cursor pointer
00987          * cursor stmt cannot be NULL
00988          * cursor name cannot be NULL
00989          */
00990 
00991         int something_to_send = 0;
00992 
00993         tdsdump_log(TDS_DBG_FUNC, "ct_send() : CS_CUR_CMD\n");
00994 
00995         cursor = cmd->cursor;
00996         if (!cursor) {
00997             tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor not present\n");
00998             return CS_FAIL;
00999         }
01000 
01001         if (cmd == NULL ) {
01002             tdsdump_log(TDS_DBG_FUNC, "ct_send() : cmd is null\n");
01003             return CS_FAIL;
01004         }
01005         if (cursor->query == NULL ) {
01006             tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->query is null\n");
01007             return CS_FAIL;
01008         }
01009         if ( cursor->cursor_name == NULL ) {
01010             tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->name is null\n");
01011             return CS_FAIL;
01012         }
01013 
01014         if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED) {
01015             ret =  tds_cursor_declare(tds, cursor, &something_to_send);
01016             if (ret == CS_SUCCEED){
01017                 cursor->status.declare = _CS_CURS_TYPE_SENT; /* Cursor is declared */
01018                 if (something_to_send == 0) {
01019                     cmd->results_state = _CS_RES_END_RESULTS;
01020                 }
01021             }
01022             else {
01023                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor declare failed \n");
01024                 return CS_FAIL;
01025             }
01026         }
01027 
01028         if (cursor->status.cursor_row == _CS_CURS_TYPE_REQUESTED &&
01029             cursor->status.declare == _CS_CURS_TYPE_SENT) {
01030 
01031             ret = tds_cursor_setrows(tds, cursor, &something_to_send);
01032             if (ret == CS_SUCCEED){
01033                 cursor->status.cursor_row = _CS_CURS_TYPE_SENT; /* Cursor rows set */
01034                 if (something_to_send == 0) {
01035                     cmd->results_state = _CS_RES_END_RESULTS;
01036                 }
01037             }
01038             else {
01039                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor set rows failed\n");
01040                 return CS_FAIL;
01041             }
01042         }
01043 
01044         if (cursor->status.open == _CS_CURS_TYPE_REQUESTED &&
01045             cursor->status.declare == _CS_CURS_TYPE_SENT) {
01046 
01047             ret = tds_cursor_open(tds, cursor, &something_to_send);
01048             if (ret == CS_SUCCEED){
01049                 cursor->status.open = _CS_CURS_TYPE_SENT;
01050                 cmd->results_state = _CS_RES_INIT;
01051             }
01052             else {
01053                 tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor open failed\n");
01054                 return CS_FAIL;
01055             }
01056         }
01057 
01058         if (something_to_send) {
01059             tdsdump_log(TDS_DBG_WARN, "ct_send(): sending cursor commands\n");
01060             tds_flush_packet(tds);
01061             tds_set_state(tds, TDS_PENDING);
01062             something_to_send = 0;
01063 
01064             ct_set_command_state(cmd, _CS_COMMAND_SENT);
01065 
01066             return CS_SUCCEED;
01067         }
01068 
01069         if (cursor->status.close == _CS_CURS_TYPE_REQUESTED){
01070             if (cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
01071                 /* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
01072                 ret = tds_cursor_close(tds, cursor);
01073                 cmd->cursor = NULL;
01074                 /* 0.95
01075                 tds_release_cursor(tds, cursor);
01076                 cmd->cursor = cursor = NULL;
01077                 */
01078             } else {
01079                 ret = tds_cursor_close(tds, cursor);
01080                 cursor->status.close = _CS_CURS_TYPE_SENT;
01081             }
01082         }
01083 
01084         if (cursor && cursor->status.dealloc == _CS_CURS_TYPE_REQUESTED) {
01085             /* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
01086             ret = tds_cursor_dealloc(tds, cursor);
01087             cmd->cursor = NULL;
01088             tds_free_all_results(tds);
01089         }
01090 
01091         ct_set_command_state(cmd, _CS_COMMAND_SENT);
01092         return CS_SUCCEED;
01093     }
01094 
01095     if (cmd->command_type == CS_SEND_DATA_CMD) {
01096         tds_flush_packet(tds);
01097         tds_set_state(tds, TDS_PENDING);
01098         ct_set_command_state(cmd, _CS_COMMAND_SENT);
01099     }
01100 
01101     return CS_SUCCEED;
01102 }
01103 
01104 
01105 CS_RETCODE
01106 ct_results(CS_COMMAND * cmd, CS_INT * result_type)
01107 {
01108     TDSSOCKET *tds;
01109     CS_CONTEXT *context;
01110 
01111     int tdsret;
01112     CS_INT res_type;
01113     CS_INT done_flags;
01114 
01115     tdsdump_log(TDS_DBG_FUNC, "ct_results()\n");
01116 
01117     if (cmd->cancel_state == _CS_CANCEL_PENDING) {
01118         _ct_cancel_cleanup(cmd);
01119         return CS_CANCELED;
01120     }
01121 
01122     if (!cmd->con || !cmd->con->tds_socket)
01123         return CS_FAIL;
01124 
01125     cmd->bind_count = CS_UNUSED;
01126 
01127     context = cmd->con->ctx;
01128 
01129     tds = cmd->con->tds_socket;
01130     cmd->row_prefetched = 0;
01131 
01132     /*
01133      * depending on the current results state, we may
01134      * not need to call tds_process_tokens...
01135      */
01136 
01137     switch (cmd->results_state) {
01138     case _CS_RES_CMD_SUCCEED:
01139         *result_type = CS_CMD_SUCCEED;
01140         cmd->results_state = _CS_RES_CMD_DONE;
01141         return CS_SUCCEED;
01142     case _CS_RES_CMD_DONE:
01143         *result_type = CS_CMD_DONE;
01144         cmd->results_state = _CS_RES_INIT;
01145         return CS_SUCCEED;
01146     case _CS_RES_END_RESULTS:
01147         *result_type = CS_CMD_DONE;
01148         cmd->results_state = _CS_RES_INIT;
01149         return CS_END_RESULTS;
01150     case _CS_RES_DESCRIBE_RESULT:
01151         *result_type = CS_DESCRIBE_RESULT;
01152         cmd->results_state = _CS_RES_CMD_DONE;
01153         return CS_SUCCEED;
01154     case _CS_RES_NONE:              /* first time in after ct_send */
01155         cmd->results_state = _CS_RES_INIT;
01156         break;
01157     default:
01158         break;
01159     }
01160 
01161     /*
01162      * see what "result" tokens we have. a "result" in ct-lib terms also
01163      * includes row data. Some result types always get reported back  to
01164      * the calling program, others are only reported back if the relevant
01165      * config flag is set.
01166      */
01167 
01168     for (;;) {
01169 
01170         tdsret = tds_process_tokens(tds, &res_type, &done_flags, TDS_TOKEN_RESULTS);
01171 
01172         tdsdump_log(TDS_DBG_FUNC, "ct_results() process_result_tokens returned %d (type %d) \n",
01173                 tdsret, res_type);
01174 
01175         switch (tdsret) {
01176 
01177         case TDS_SUCCEED:
01178 
01179             cmd->curr_result_type = res_type;
01180 
01181             switch (res_type) {
01182 
01183             case CS_COMPUTEFMT_RESULT:
01184             case CS_ROWFMT_RESULT:
01185 
01186                 /*
01187                  * set results state to indicate that we
01188                  * have a result set (empty for the moment)
01189                  * If the CS_EXPOSE_FMTS  property has been
01190                  * set in ct_config(), we need to return an
01191                  * appropraite format result, otherwise just
01192                  * carry on and get the next token.....
01193                  */
01194 
01195                 cmd->results_state = _CS_RES_RESULTSET_EMPTY;
01196 
01197                 if (context->config.cs_expose_formats) {
01198                     *result_type = res_type;
01199                     return CS_SUCCEED;
01200                 }
01201                 break;
01202 
01203             case CS_ROW_RESULT:
01204 
01205                 /*
01206                  * we've hit a data row. pass back that fact
01207                  * to the calling program. set results state
01208                  * to show that the result set has rows...
01209                  */
01210 
01211                 cmd->results_state = _CS_RES_RESULTSET_ROWS;
01212                 if (cmd->command_type == CS_CUR_CMD) {
01213                     *result_type = CS_CURSOR_RESULT;
01214                 } else {
01215                     *result_type = CS_ROW_RESULT;
01216                 }
01217                 return CS_SUCCEED;
01218                 break;
01219 
01220             case CS_COMPUTE_RESULT:
01221 
01222                 /*
01223                  * we've hit a compute data row. We have to get hold of this
01224                  * data now, as it's necessary  to tie this data back to its
01225                  * result format...the user may call ct_res_info() & friends
01226                  * after getting back a compute "result".
01227                  *
01228                  * but first, if we've hit this compute row without having
01229                  * hit a data row first, we need to return a  CS_ROW_RESULT
01230                  * before letting them have the compute row...
01231                  */
01232 
01233                 if (cmd->results_state == _CS_RES_RESULTSET_EMPTY) {
01234                     *result_type = CS_ROW_RESULT;
01235                     tds->current_results = tds->res_info;
01236                     cmd->results_state = _CS_RES_RESULTSET_ROWS;
01237                     return CS_SUCCEED;
01238                 }
01239 
01240                 tdsret = tds_process_tokens(tds, &res_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
01241 
01242                 /* set results state to show that the result set has rows... */
01243 
01244                 cmd->results_state = _CS_RES_RESULTSET_ROWS;
01245 
01246                 *result_type = res_type;
01247                 if (tdsret == TDS_SUCCEED && (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT)) {
01248                     if (res_type == TDS_COMPUTE_RESULT) {
01249                         cmd->row_prefetched = 1;
01250                         return CS_SUCCEED;
01251                     } else {
01252                         /* this couldn't really happen, but... */
01253                         return CS_FAIL;
01254                     }
01255                 } else
01256                     return CS_FAIL;
01257                 break;
01258 
01259             case TDS_DONE_RESULT:
01260 
01261                 /*
01262                  * A done token signifies the end of a logical
01263                  * command. There are three possibilities...
01264                  * 1. Simple command with no result set, i.e.
01265                  *    update, delete, insert
01266                  * 2. Command with result set but no rows
01267                  * 3. Command with result set and rows
01268                  * in these cases we need to:
01269                  * 1. return CS_CMD_FAIL/SUCCED depending on
01270                  *    the status returned in done_flags
01271                  * 2. "manufacture" a CS_ROW_RESULT return,
01272                  *    and set the results state to DONE
01273                  * 3. return with CS_CMD_DONE and reset the
01274                  *    results_state
01275                  */
01276 
01277                 tdsdump_log(TDS_DBG_FUNC, "ct_results() results state = %d\n",cmd->results_state);
01278                 tdsdump_log(TDS_DBG_FUNC, "ct_results() command type  = %d\n",cmd->command_type);
01279                 tdsdump_log(TDS_DBG_FUNC, "ct_results() dynamic cmd   = %d\n",cmd->dynamic_cmd);
01280 
01281                 if ((cmd->command_type == CS_DYNAMIC_CMD) &&
01282                     (cmd->dynamic_cmd == CS_PREPARE || cmd->dynamic_cmd == CS_DEALLOC)) {
01283                     *result_type = CS_CMD_SUCCEED;
01284                     cmd->results_state = _CS_RES_CMD_DONE;
01285                     return CS_SUCCEED;
01286                 }
01287 
01288                 switch (cmd->results_state) {
01289 
01290                 case _CS_RES_INIT:
01291                 case _CS_RES_STATUS:
01292                     if (done_flags & TDS_DONE_ERROR)
01293                         *result_type = CS_CMD_FAIL;
01294                     else
01295                         *result_type = CS_CMD_SUCCEED;
01296                     cmd->results_state = _CS_RES_CMD_DONE;
01297                     break;
01298 
01299                 case _CS_RES_RESULTSET_EMPTY:
01300                     if (cmd->command_type == CS_CUR_CMD) {
01301                         *result_type = CS_CURSOR_RESULT;
01302                         cmd->results_state = _CS_RES_RESULTSET_ROWS;
01303                     } else {
01304                         *result_type = CS_ROW_RESULT;
01305                         cmd->results_state = _CS_RES_CMD_DONE;
01306                     }
01307                     break;
01308 
01309                 case _CS_RES_RESULTSET_ROWS:
01310                     *result_type = CS_CMD_DONE;
01311                     cmd->results_state = _CS_RES_INIT;
01312                     break;
01313 
01314                 }
01315                 return CS_SUCCEED;
01316                 break;
01317 
01318             case TDS_DONEINPROC_RESULT:
01319 
01320                 /*
01321                  * A doneinproc token may signify the end of a
01322                  * logical command if the command had a result
01323                  * set. Otherwise it is ignored....
01324                  */
01325 
01326                 switch (cmd->results_state) {
01327                 case _CS_RES_INIT:   /* command had no result set */
01328                     break;
01329                 case _CS_RES_RESULTSET_EMPTY:
01330                     if (cmd->command_type == CS_CUR_CMD) {
01331                         *result_type = CS_CURSOR_RESULT;
01332                     } else {
01333                         *result_type = CS_ROW_RESULT;
01334                     }
01335                     cmd->results_state = _CS_RES_CMD_DONE;
01336                     return CS_SUCCEED;
01337                     break;
01338                 case _CS_RES_RESULTSET_ROWS:
01339                     *result_type = CS_CMD_DONE;
01340                     cmd->results_state = _CS_RES_INIT;
01341                     return CS_SUCCEED;
01342                     break;
01343                 }
01344                 break;
01345 
01346             case TDS_DONEPROC_RESULT:
01347 
01348                 /*
01349                  * A DONEPROC result means the end of a logical
01350                  * command only if it was one of the commands
01351                  * directly sent from ct_send, not as a result
01352                  * of a nested stored procedure call. We know
01353                  * if this is the case if a STATUS_RESULT was
01354                  * received immediately prior to the DONE_PROC
01355                  */
01356 
01357                 if (cmd->results_state == _CS_RES_STATUS ||
01358                     cmd->results_state == _CS_RES_INIT /* ssikorsk */
01359                     ) {
01360                     if (done_flags & TDS_DONE_ERROR)
01361                         *result_type = CS_CMD_FAIL;
01362                     else
01363                         *result_type = CS_CMD_SUCCEED;
01364                     cmd->results_state = _CS_RES_CMD_DONE;
01365                     return CS_SUCCEED;
01366                 } else {
01367                     if (cmd->command_type == CS_DYNAMIC_CMD) {
01368                         *result_type = CS_CMD_SUCCEED;
01369                         cmd->results_state = _CS_RES_CMD_DONE;
01370                         return CS_SUCCEED;
01371                     }
01372                 }
01373 
01374                 break;
01375 
01376             case TDS_PARAM_RESULT:
01377                 cmd->row_prefetched = 1;
01378                 *result_type = res_type;
01379                 return CS_SUCCEED;
01380                 break;
01381 
01382             case TDS_STATUS_RESULT:
01383                 _ct_process_return_status(tds);
01384                 cmd->row_prefetched = 1;
01385                 *result_type = res_type;
01386                 cmd->results_state = _CS_RES_STATUS;
01387                 return CS_SUCCEED;
01388                 break;
01389 
01390             case TDS_DESCRIBE_RESULT:
01391                 if (cmd->dynamic_cmd == CS_DESCRIBE_INPUT ||
01392                     cmd->dynamic_cmd == CS_DESCRIBE_OUTPUT) {
01393                     *result_type = res_type;
01394                     return CS_SUCCEED;
01395                 }
01396                 break;
01397             default:
01398                 *result_type = res_type;
01399                 return CS_SUCCEED;
01400                 break;
01401             }
01402 
01403             break;
01404 
01405         case TDS_NO_MORE_RESULTS:
01406 
01407             /* some commands can be re-sent once completed */
01408             /* so mark the command state as 'ready'...     */
01409 
01410             if (cmd->command_type == CS_LANG_CMD ||
01411                 cmd->command_type == CS_RPC_CMD ||
01412                 cmd->command_type == CS_CUR_CMD ||
01413                 cmd->command_type == CS_DYNAMIC_CMD) {
01414                 ct_set_command_state(cmd, _CS_COMMAND_READY);
01415             }
01416             /* if we have just completed processing a dynamic deallocate */
01417             /* get rid of our dynamic statement structure...             */
01418 
01419             if (cmd->command_type == CS_DYNAMIC_CMD &&
01420                 cmd->dynamic_cmd  == CS_DEALLOC) {
01421                 _ct_deallocate_dynamic(cmd->con, cmd->dyn);
01422                 cmd->dyn = NULL;
01423             }
01424             return CS_END_RESULTS;
01425             break;
01426 
01427         case TDS_CANCELLED:
01428             cmd->cancel_state = _CS_CANCEL_NOCANCEL;
01429             return CS_CANCELED;
01430             break;
01431 
01432         case TDS_FAIL:
01433         default:
01434             return CS_FAIL;
01435             break;
01436 
01437         }  /* switch (tdsret) */
01438     }      /* for (;;)        */
01439 }
01440 
01441 
01442 CS_RETCODE
01443 ct_bind(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT * copied, CS_SMALLINT * indicator)
01444 {
01445     TDSCOLUMN *colinfo;
01446     TDSRESULTINFO *resinfo;
01447     TDSSOCKET *tds;
01448     CS_CONNECTION *con = cmd->con;
01449     CS_INT bind_count;
01450 
01451     tdsdump_log(TDS_DBG_FUNC, "ct_bind() datafmt count = %d column_number = %d\n", datafmt->count, item);
01452 
01453     if (!con || !con->tds_socket)
01454         return CS_FAIL;
01455 
01456     tds = con->tds_socket;
01457     resinfo = tds->current_results;
01458 
01459     /* check item value */
01460     if (!resinfo || item <= 0 || item > resinfo->num_cols)
01461         return CS_FAIL;
01462 
01463     colinfo = resinfo->columns[item - 1];
01464 
01465     /* check whether the request is for array binding and ensure that user */
01466     /* supplies the same datafmt->count to the subsequent ct_bind calls    */
01467 
01468     bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
01469 
01470     /* first bind for this result set */
01471 
01472     if (cmd->bind_count == CS_UNUSED) {
01473         cmd->bind_count = bind_count;
01474     } else {
01475         /* all subsequent binds for this result set - the bind counts must be the same */
01476         if (cmd->bind_count != bind_count) {
01477             _ctclient_msg(con, "ct_bind", 1, 1, 1, 137, "%d, %d", bind_count, cmd->bind_count);
01478             return CS_FAIL;
01479         }
01480     }
01481 
01482     /* bind the column_varaddr to the address of the buffer */
01483 
01484     colinfo = resinfo->columns[item - 1];
01485     colinfo->column_varaddr = (char *) buffer;
01486     colinfo->column_bindtype = datafmt->datatype;
01487     colinfo->column_bindfmt = datafmt->format;
01488     colinfo->column_bindlen = datafmt->maxlength;
01489     if (indicator) {
01490         colinfo->column_nullbind = indicator;
01491     }
01492     if (copied) {
01493         colinfo->column_lenbind = copied;
01494     }
01495     return CS_SUCCEED;
01496 }
01497 
01498 CS_RETCODE
01499 ct_fetch(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read)
01500 {
01501     TDS_INT ret_type;
01502     TDS_INT ret;
01503     TDS_INT marker;
01504     TDS_INT temp_count;
01505     TDSSOCKET *tds;
01506 
01507     tdsdump_log(TDS_DBG_FUNC, "ct_fetch()\n");
01508 
01509     if (!cmd->con || !cmd->con->tds_socket)
01510         return CS_FAIL;
01511 
01512     if (cmd->command_state == _CS_COMMAND_IDLE) {
01513         _ctclient_msg(cmd->con, "ct_fetch", 1, 1, 1, 16843163, "");
01514         return CS_FAIL;
01515     }
01516 
01517     if (cmd->cancel_state == _CS_CANCEL_PENDING) {
01518         _ct_cancel_cleanup(cmd);
01519         return CS_CANCELED;
01520     }
01521 
01522     tds = cmd->con->tds_socket;
01523 
01524     /* We'll call a special function for fetches from a cursor            */
01525     /* the processing is too incompatible to patch into a single function */
01526 
01527     if (cmd->command_type == CS_CUR_CMD) {
01528         return _ct_fetch_cursor(cmd, type, offset, option, rows_read);
01529     }
01530 
01531     if (rows_read)
01532         *rows_read = 0;
01533 
01534     /* taking a copy of the cmd->bind_count value. */
01535     temp_count = cmd->bind_count;
01536 
01537     if ( cmd->bind_count == CS_UNUSED )
01538         cmd->bind_count = 1;
01539 
01540     /* compute rows and parameter results have been pre-fetched by ct_results() */
01541 
01542     if (cmd->row_prefetched) {
01543         cmd->row_prefetched = 0;
01544         cmd->get_data_item = 0;
01545         cmd->get_data_bytes_returned = 0;
01546         if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, 0))
01547             return CS_ROW_FAIL;
01548         if (rows_read)
01549             *rows_read = 1;
01550         return CS_SUCCEED;
01551     }
01552 
01553     if (cmd->results_state == _CS_RES_CMD_DONE)
01554         return CS_END_DATA;
01555     if (cmd->curr_result_type == CS_COMPUTE_RESULT)
01556         return CS_END_DATA;
01557     if (cmd->curr_result_type == CS_CMD_FAIL)
01558         return CS_CMD_FAIL;
01559 
01560 
01561     marker = tds_peek(tds);
01562     if ((cmd->curr_result_type == CS_ROW_RESULT && marker != TDS_ROW_TOKEN) ||
01563         (cmd->curr_result_type == CS_STATUS_RESULT && marker != TDS_RETURNSTATUS_TOKEN) )
01564         return CS_END_DATA;
01565 
01566     /* Array Binding Code changes start here */
01567 
01568     for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
01569 
01570         ret = tds_process_tokens(tds, &ret_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
01571 
01572         tdsdump_log(TDS_DBG_FUNC, "inside ct_fetch()process_row_tokens returned %d\n", ret);
01573 
01574         switch (ret) {
01575             case TDS_SUCCEED:
01576                 if (ret_type == TDS_ROW_RESULT || ret_type == TDS_COMPUTE_RESULT) {
01577                     cmd->get_data_item = 0;
01578                     cmd->get_data_bytes_returned = 0;
01579                     if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, temp_count))
01580                         return CS_ROW_FAIL;
01581                     if (rows_read)
01582                         *rows_read = *rows_read + 1;
01583                     break;
01584                 }
01585             case TDS_NO_MORE_RESULTS:
01586                 return CS_END_DATA;
01587                 break;
01588 
01589             case TDS_CANCELLED:
01590                 cmd->cancel_state = _CS_CANCEL_NOCANCEL;
01591                 return CS_CANCELED;
01592                 break;
01593 
01594             default:
01595                 return CS_FAIL;
01596                 break;
01597         }
01598 
01599         /* have we reached the end of the rows ? */
01600 
01601         marker = tds_peek(tds);
01602 
01603         if (cmd->curr_result_type == CS_ROW_RESULT && marker != TDS_ROW_TOKEN)
01604             break;
01605 
01606     }
01607 
01608     /* Array Binding Code changes end here */
01609 
01610     return CS_SUCCEED;
01611 }
01612 
01613 static CS_RETCODE
01614 _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read)
01615 {
01616     TDSSOCKET * tds;
01617     TDSCURSOR *cursor;
01618     TDS_INT restype;
01619     TDS_INT ret;
01620     TDS_INT temp_count;
01621     TDS_INT done_flags;
01622     TDS_INT rows_this_fetch = 0;
01623 
01624     tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor()\n");
01625 
01626     if (!cmd->con || !cmd->con->tds_socket)
01627         return CS_FAIL;
01628 
01629     tds = cmd->con->tds_socket;
01630 
01631     if (rows_read)
01632         *rows_read = 0;
01633 
01634     /* taking a copy of the cmd->bind_count value. */
01635     temp_count = cmd->bind_count;
01636 
01637     if ( cmd->bind_count == CS_UNUSED )
01638         cmd->bind_count = 1;
01639 
01640     cursor = cmd->cursor;
01641     if (!cursor) {
01642         tdsdump_log(TDS_DBG_FUNC, "ct_fetch_cursor() : cursor not present\n");
01643         return CS_FAIL;
01644     }
01645 
01646     /* currently we are placing this restriction on cursor fetches.  */
01647     /* the alternatives are too awful to contemplate at the moment   */
01648     /* i.e. buffering all the rows from the fetch internally...      */
01649 
01650     if (cmd->bind_count < cursor->cursor_rows) {
01651         tdsdump_log(TDS_DBG_WARN, "_ct_fetch_cursor(): bind count must equal cursor rows \n");
01652         return CS_FAIL;
01653     }
01654 
01655     /* if ( tds_cursor_fetch(tds, cursor) == CS_SUCCEED) { ssikorsk */
01656     if (tds_cursor_fetch(tds, cursor, TDS_CURSOR_FETCH_NEXT, 0) == CS_SUCCEED) {
01657         cursor->status.fetch = _CS_CURS_TYPE_SENT;
01658     }
01659     else {
01660         tdsdump_log(TDS_DBG_WARN, "ct_fetch(): cursor fetch failed\n");
01661         return CS_FAIL;
01662     }
01663 
01664     tds->cur_cursor = cursor;
01665 
01666     while ((tds_process_tokens(tds, &restype, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCEED) {
01667         switch (restype) {
01668             case CS_ROWFMT_RESULT:
01669                 break;
01670             case CS_ROW_RESULT:
01671                 for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
01672 
01673                     ret = tds_process_tokens(tds, &restype, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
01674 
01675                     tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor() tds_process_tokens returned %d\n", ret);
01676 
01677                     if (ret == TDS_SUCCEED && (restype == TDS_ROW_RESULT || restype == TDS_COMPUTE_RESULT)) {
01678                         cmd->get_data_item = 0;
01679                         cmd->get_data_bytes_returned = 0;
01680                         if (restype == TDS_ROW_RESULT) {
01681                             if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, temp_count))
01682                                 return CS_ROW_FAIL;
01683                             if (rows_read)
01684                                 *rows_read = *rows_read + 1;
01685                             rows_this_fetch++;
01686                         }
01687                     } else {
01688                         if (ret != TDS_FAIL) {
01689                             break;
01690                         } else {
01691                             return CS_FAIL;
01692                         }
01693                     }
01694                 }
01695                 break;
01696             case TDS_DONE_RESULT:
01697                 break;
01698         }
01699     }
01700     if (rows_this_fetch)
01701         return CS_SUCCEED;
01702     else {
01703         cmd->results_state = _CS_RES_CMD_SUCCEED;
01704         return CS_END_DATA;
01705     }
01706 
01707 }
01708 
01709 
01710 int
01711 _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset)
01712 {
01713     int i;
01714     TDSCOLUMN *curcol;
01715     TDSCOLUMN *bindcol;
01716     unsigned char *src;
01717     unsigned char *dest, *temp_add;
01718     int result = 0;
01719     TDS_INT srctype, srclen, desttype, len;
01720     CS_DATAFMT srcfmt, destfmt;
01721     TDS_INT *datalen = NULL;
01722     TDS_SMALLINT *nullind = NULL;
01723 
01724     tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data()\n");
01725 
01726     for (i = 0; i < resinfo->num_cols; i++) {
01727         datalen = NULL;
01728         nullind = NULL;
01729 
01730         curcol = resinfo->columns[i];
01731         bindcol = bindinfo->columns[i];
01732 
01733         tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data(): column_type: %d column_len: %d\n",
01734             curcol->column_type,
01735             curcol->column_cur_size
01736         );
01737 
01738         if (curcol->column_hidden)
01739             continue;
01740 
01741 
01742         srctype = curcol->column_type;
01743         desttype = _ct_get_server_type(bindcol->column_bindtype);
01744 
01745         /* retrieve the initial bound column_varaddress */
01746         /* and increment it if offset specified         */
01747 
01748         temp_add = (unsigned char *) bindcol->column_varaddr;
01749         dest = temp_add + (offset * bindcol->column_bindlen);
01750 
01751         if (bindcol->column_nullbind) {
01752             nullind = bindcol->column_nullbind;
01753             nullind += offset;
01754         }
01755         if (bindcol->column_lenbind) {
01756             datalen = bindcol->column_lenbind;
01757             datalen += offset;
01758         }
01759 
01760         if (dest) {
01761 
01762             if (curcol->column_cur_size < 0) {
01763                 if (nullind)
01764                     *nullind = -1;
01765                 if (datalen)
01766                     *datalen = 0;
01767             } else {
01768 
01769                 srctype = _ct_get_client_type(ctx, curcol->column_type, curcol->column_usertype, curcol->column_size);
01770 
01771                 src = &(resinfo->current_row[curcol->column_offset]);
01772                 if (is_blob_type(curcol->column_type))
01773                     src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
01774 
01775                 srclen = curcol->column_cur_size;
01776                 srcfmt.datatype = srctype;
01777                 srcfmt.maxlength = srclen;
01778 
01779                 destfmt.datatype = bindcol->column_bindtype;
01780                 /*destfmt.maxlength = bindcol->column_cur_size;*/ /*ssikorsk*/
01781                 destfmt.maxlength = bindcol->column_bindlen; /* original */
01782                 destfmt.format = bindcol->column_bindfmt;
01783 
01784                 /* if convert return FAIL mark error but process other columns */
01785                 if ((result= cs_convert(ctx, &srcfmt, (CS_VOID *) src, &destfmt, (CS_VOID *) dest, &len) != CS_SUCCEED)) {
01786                     tdsdump_log(TDS_DBG_FUNC, "cs_convert-result = %d\n", result);
01787                     result = 1;
01788                     len = 0;
01789                     tdsdump_log(TDS_DBG_INFO1, "\n  convert failed for %d \n", srcfmt.datatype);
01790                 }
01791 
01792                 if (nullind)
01793                     *nullind = 0;
01794                 if (datalen) {
01795                     *datalen = len;
01796                 }
01797             }
01798         } else {
01799             if (datalen)
01800                 *datalen = 0;
01801         }
01802     }
01803     return result;
01804 }
01805 
01806 CS_RETCODE
01807 ct_cmd_drop(CS_COMMAND * cmd)
01808 {
01809     CS_RETCODE ret;
01810     ret = _ct_cmd_drop(cmd, 1);
01811     return ret;
01812 }
01813 
01814 static CS_RETCODE
01815 _ct_cmd_drop(CS_COMMAND * cmd, CS_INT free_conn_ref)
01816 {
01817     CS_COMMAND_LIST *victim = NULL;
01818     CS_COMMAND_LIST *prev = NULL;
01819     CS_COMMAND_LIST *next = NULL;
01820     CS_CONNECTION *con;
01821 
01822     tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop()\n");
01823     if (cmd) {
01824         if (cmd->query)
01825             free(cmd->query);
01826         if (cmd->input_params)
01827             param_clear(cmd->input_params);
01828         if (cmd->userdata)
01829             free(cmd->userdata);
01830         if (cmd->rpc) {
01831             if (cmd->rpc->param_list)
01832                 param_clear(cmd->rpc->param_list);
01833             free(cmd->rpc->name);
01834             free(cmd->rpc);
01835         }
01836         if (cmd->iodesc)
01837             free(cmd->iodesc);
01838 
01839         /* now remove this command from the list of commands in the connection */
01840 
01841         if (free_conn_ref && cmd->con) {
01842             con = cmd->con;
01843             victim = con->cmds;
01844 
01845             for (;;) {
01846                 if (victim->cmd == cmd)
01847                     break;
01848                 prev = victim;
01849                 victim = victim->next;
01850                 if (victim == NULL) {
01851                     tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : cannot find command entry in list \n");
01852                     return CS_FAIL;
01853                 }
01854             }
01855 
01856             tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : command entry found in list\n");
01857 
01858             next = victim->next;
01859             free(victim);
01860 
01861             tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : relinking list\n");
01862 
01863             if (prev)
01864                 prev->next = next;
01865             else
01866                 con->cmds = next;
01867 
01868             tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : relinked list\n");
01869         }
01870 
01871         free(cmd);
01872     }
01873     return CS_SUCCEED;
01874 }
01875 
01876 CS_RETCODE
01877 ct_close(CS_CONNECTION * con, CS_INT option)
01878 {
01879     tdsdump_log(TDS_DBG_FUNC, "ct_close()\n");
01880     tds_free_socket(con->tds_socket);
01881     con->tds_socket = NULL;
01882     return CS_SUCCEED;
01883 }
01884 
01885 CS_RETCODE
01886 ct_con_drop(CS_CONNECTION * con)
01887 {
01888     CS_COMMAND_LIST *currptr;
01889     CS_COMMAND_LIST *freeptr;
01890 
01891     tdsdump_log(TDS_DBG_FUNC, "ct_con_drop()\n");
01892     if (con) {
01893         if (con->userdata)
01894             free(con->userdata);
01895         if (con->tds_login)
01896             tds_free_login(con->tds_login);
01897         if (con->cmds) {
01898             currptr = con->cmds;
01899             while (currptr != NULL) {
01900                 freeptr = currptr;
01901                 if (currptr->cmd)
01902                     currptr->cmd->con = NULL;
01903                 currptr = currptr->next;
01904                 free(freeptr);
01905             }
01906         }
01907         free(con);
01908     }
01909     return CS_SUCCEED;
01910 }
01911 
01912 int
01913 _ct_get_client_type(CS_CONTEXT *ctx, int datatype, int usertype, int size)
01914 {
01915     tdsdump_log(TDS_DBG_FUNC, "_ct_get_client_type(type %d, user %d, size %d)\n", datatype, usertype, size);
01916     switch (datatype) {
01917     case SYBBIT:
01918     case SYBBITN:
01919         return CS_BIT_TYPE;
01920         break;
01921     case SYBCHAR:
01922         return CS_VARCHAR_TYPE;
01923         break;
01924     case SYBVARCHAR:
01925         return CS_VARCHAR_TYPE;
01926         break;
01927     case SYBINT8:
01928         return CS_LONG_TYPE;
01929         break;
01930     case SYBINT4:
01931         return CS_INT_TYPE;
01932         break;
01933     case SYBINT2:
01934         return CS_SMALLINT_TYPE;
01935         break;
01936     case SYBINT1:
01937         return CS_TINYINT_TYPE;
01938         break;
01939     case SYBINTN:
01940         switch (size) {
01941         case 8:
01942             return CS_LONG_TYPE;
01943         case 4:
01944             return CS_INT_TYPE;
01945         case 2:
01946             return CS_SMALLINT_TYPE;
01947         case 1:
01948             return CS_TINYINT_TYPE;
01949         default:
01950             _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 28, "%d", size);
01951         }
01952         break;
01953     case SYBREAL:
01954         return CS_REAL_TYPE;
01955         break;
01956     case SYBFLT8:
01957         return CS_FLOAT_TYPE;
01958         break;
01959     case SYBFLTN:
01960         if (size == 4) {
01961             return CS_REAL_TYPE;
01962         } else if (size == 8) {
01963             return CS_FLOAT_TYPE;
01964         } else {
01965             _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 29, "%d", size);
01966         }
01967     case SYBMONEY:
01968         return CS_MONEY_TYPE;
01969         break;
01970     case SYBMONEY4:
01971         return CS_MONEY4_TYPE;
01972         break;
01973     case SYBMONEYN:
01974         if (size == 4) {
01975             return CS_MONEY4_TYPE;
01976         } else if (size == 8) {
01977             return CS_MONEY_TYPE;
01978         } else {
01979             _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 30, "%d", size);
01980         }
01981     case SYBDATETIME:
01982         return CS_DATETIME_TYPE;
01983         break;
01984     case SYBDATETIME4:
01985         return CS_DATETIME4_TYPE;
01986         break;
01987     case SYBDATETIMN:
01988         if (size == 4) {
01989             return CS_DATETIME4_TYPE;
01990         } else if (size == 8) {
01991             return CS_DATETIME_TYPE;
01992         } else {
01993             _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 31, "%d", size);
01994         }
01995         break;
01996     case SYBNUMERIC:
01997         return CS_NUMERIC_TYPE;
01998         break;
01999     case SYBDECIMAL:
02000         return CS_DECIMAL_TYPE;
02001         break;
02002     case SYBBINARY:
02003         return CS_BINARY_TYPE;
02004         break;
02005     case SYBIMAGE:
02006         return CS_IMAGE_TYPE;
02007         break;
02008     case SYBVARBINARY:
02009         return CS_VARBINARY_TYPE;
02010         break;
02011     case SYBTEXT:
02012         return CS_TEXT_TYPE;
02013         break;
02014     case SYBUNIQUE:
02015         return CS_UNIQUE_TYPE;
02016         break;
02017     case SYBLONGBINARY:
02018         if (usertype == USER_UNICHAR_TYPE || usertype == USER_UNIVARCHAR_TYPE)
02019             return CS_UNICHAR_TYPE;
02020         /*return CS_CHAR_TYPE;*/
02021         return CS_LONGBINARY_TYPE;
02022         break;
02023     }
02024 
02025     return CS_FAIL;
02026 }
02027 
02028 int
02029 _ct_get_server_type(int datatype)
02030 {
02031     tdsdump_log(TDS_DBG_FUNC, "_ct_get_server_type(%d)\n", datatype);
02032     switch (datatype) {
02033     case CS_IMAGE_TYPE:
02034         return SYBIMAGE;
02035         break;
02036     case CS_BINARY_TYPE:
02037         return SYBBINARY;
02038         break;
02039     case CS_BIT_TYPE:
02040         return SYBBIT;
02041         break;
02042     case CS_CHAR_TYPE:
02043         return SYBCHAR;
02044         break;
02045     case CS_LONG_TYPE:
02046         return SYBINT8;
02047         break;
02048     case CS_INT_TYPE:
02049         return SYBINT4;
02050         break;
02051     case CS_SMALLINT_TYPE:
02052         return SYBINT2;
02053         break;
02054     case CS_TINYINT_TYPE:
02055         return SYBINT1;
02056         break;
02057     case CS_REAL_TYPE:
02058         return SYBREAL;
02059         break;
02060     case CS_FLOAT_TYPE:
02061         return SYBFLT8;
02062         break;
02063     case CS_MONEY_TYPE:
02064         return SYBMONEY;
02065         break;
02066     case CS_MONEY4_TYPE:
02067         return SYBMONEY4;
02068         break;
02069     case CS_DATETIME_TYPE:
02070         return SYBDATETIME;
02071         break;
02072     case CS_DATETIME4_TYPE:
02073         return SYBDATETIME4;
02074         break;
02075     case CS_NUMERIC_TYPE:
02076         return SYBNUMERIC;
02077         break;
02078     case CS_DECIMAL_TYPE:
02079         return SYBDECIMAL;
02080         break;
02081     case CS_VARBINARY_TYPE:
02082         return SYBVARBINARY;
02083         break;
02084     case CS_TEXT_TYPE:
02085         return SYBTEXT;
02086         break;
02087     case CS_UNIQUE_TYPE:
02088         return SYBUNIQUE;
02089         break;
02090     case CS_LONGBINARY_TYPE:    /* vicm */
02091         return SYBLONGBINARY;
02092         break;
02093     case CS_UNICHAR_TYPE:
02094         return SYBNVARCHAR;
02095     case CS_LONGCHAR_TYPE:
02096         return SYBVARCHAR;
02097     case CS_NLONGCHAR_TYPE:
02098         return SYBNVARCHAR;
02099     case CS_VARCHAR_TYPE:
02100         return SYBVARCHAR;
02101     case CS_NVARCHAR_TYPE:
02102         return SYBNVARCHAR;
02103     default:
02104         /*
02105         CS_SENSITIVITY_TYPE
02106         CS_BOUNDARY_TYPE
02107         CS_VOID_TYPE
02108         */
02109         return -1;
02110         break;
02111     }
02112 }
02113 
02114 CS_RETCODE
02115 ct_cancel(CS_CONNECTION * conn, CS_COMMAND * cmd, CS_INT type)
02116 {
02117     CS_RETCODE ret;
02118     CS_COMMAND_LIST *cmds;
02119     CS_COMMAND *conn_cmd;
02120     CS_CONNECTION *cmd_conn;
02121 
02122     tdsdump_log(TDS_DBG_FUNC, "ct_cancel()\n");
02123 
02124     /*
02125      * Comments taken from Sybase ct-library reference manual
02126      * ------------------------------------------------------
02127      *
02128      * "To cancel current results, an application calls ct_cancel
02129      *  with type as CT_CANCEL CURRENT. This is equivalent to
02130      *  calling ct_fetch until it returns CS_END_DATA"
02131      *
02132      * "For CS_CANCEL_CURRENT cancels, cmd must be supplied"
02133      * "For CS_CANCEL_CURRENT cancels, connection must be NULL"
02134      */
02135 
02136     if (type == CS_CANCEL_CURRENT) {
02137 
02138 
02139         tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_CURRENT\n");
02140         if (conn || !cmd)
02141             return CS_FAIL;
02142 
02143 
02144         if (!_ct_fetchable_results(cmd)) {
02145             tdsdump_log(TDS_DBG_FUNC, "ct_cancel() no fetchable results - return()\n");
02146             return CS_SUCCEED;
02147         }
02148 
02149         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() - fetching results()\n");
02150         do {
02151             ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL);
02152         } while ((ret == CS_SUCCEED) || (ret == CS_ROW_FAIL));
02153 
02154         if (cmd->con && cmd->con->tds_socket)
02155             tds_free_all_results(cmd->con->tds_socket);
02156 
02157         if (ret == CS_END_DATA) {
02158             return CS_SUCCEED;
02159         }
02160         return CS_FAIL;
02161     }
02162 
02163     /*
02164      * Comments taken from Sybase ct-library reference manual
02165      * ------------------------------------------------------
02166      *
02167      * "To cancel the current command and all results generated
02168      *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
02169      *  CS_CANCEL_ALL. Both of these calls tell client library
02170      *  to :
02171      *  * Send an attention to the server
02172      *  * discard any results already generated by the command
02173      *  Both types of cancel return CS_SUCCEED immediately, w/o
02174      *  sending an attention, if no command is in progress.
02175      *  If an application has not yet called ct_send to send an
02176      *  initiated command, a CS_CANCEL_ATTN has no effect.
02177      *
02178      *  If a command has been sent and ct_results has not been
02179      *  called, a ct_cancel (CS_CANCEL_ATTN) has no effect."
02180      *
02181      * "For CS_CANCEL_ATTN cancels, one of connection or cmd
02182      *  must be NULL. if cmd is supplied and connection is NULL
02183      *  the cancel operation applies only to the command pend-
02184      *  ing for this command structure. If cmd is NULL and
02185      *  connection is supplied, the cancel operation applies to
02186      *  all commands pending for this connection.
02187      */
02188 
02189     if (type == CS_CANCEL_ATTN) {
02190         if ((conn && cmd) || (!conn && !cmd)) {
02191             return CS_FAIL;
02192         }
02193         if (cmd) {
02194             tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with cmd\n");
02195             cmd_conn = cmd->con;
02196             switch (cmd->command_state) {
02197                 case _CS_COMMAND_IDLE:
02198                 case _CS_COMMAND_READY:
02199                     tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
02200                     break;
02201                 case _CS_COMMAND_SENT:
02202                     tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT results_state %d\n", cmd->results_state);
02203                     if (cmd->results_state != _CS_RES_NONE) {
02204                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
02205                         tds_send_cancel(cmd_conn->tds_socket);
02206                         cmd->cancel_state = _CS_CANCEL_PENDING;
02207                     }
02208                     break;
02209             }
02210         }
02211         if (conn) {
02212             tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with connection\n");
02213             for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
02214                 conn_cmd = cmds->cmd;
02215                 switch (conn_cmd->command_state) {
02216                     case _CS_COMMAND_IDLE:
02217                     case _CS_COMMAND_READY:
02218                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
02219                         break;
02220                     case _CS_COMMAND_SENT:
02221                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
02222                         if (conn_cmd->results_state != _CS_RES_NONE) {
02223                             tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
02224                             tds_send_cancel(conn->tds_socket);
02225                             conn_cmd->cancel_state = _CS_CANCEL_PENDING;
02226                         }
02227                     break;
02228                 }
02229             }
02230         }
02231 
02232         return CS_SUCCEED;
02233     }
02234 
02235     /*
02236      * Comments taken from Sybase ct-library reference manual
02237      * ------------------------------------------------------
02238      *
02239      * "To cancel the current command and all results generated
02240      *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
02241      *  CS_CANCEL_ALL. Both of these calls tell client library
02242      *  to :
02243      *  * Send an attention to the server
02244      *  * discard any results already generated by the command
02245      *  Both types of cancel return CS_SUCCEED immediately, w/o
02246      *  sending an attention, if no command is in progress.
02247      *
02248      *  If an application has not yet called ct_send to send an
02249      *  initiated command, a CS_CANCEL_ALL cancel discards the
02250      *  initiated command without sending an attention to the
02251      *  server.
02252      *
02253      *  CS_CANCEL_ALL leaves the command structure in a 'clean'
02254      *  state, available for use in another operation.
02255      *
02256      * "For CS_CANCEL_ALL cancels, one of connection or cmd
02257      *  must be NULL. if cmd is supplied and connection is NULL
02258      *  the cancel operation applies only to the command pend-
02259      *  ing for this command structure. If cmd is NULL and
02260      *  connection is supplied, the cancel operation applies to
02261      *  all commands pending for this connection.
02262      */
02263 
02264     if (type == CS_CANCEL_ALL) {
02265 
02266         if ((conn && cmd) || (!conn && !cmd)) {
02267             return CS_FAIL;
02268         }
02269         if (cmd) {
02270             tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with cmd\n");
02271             cmd_conn = cmd->con;
02272             switch (cmd->command_state) {
02273                 case _CS_COMMAND_IDLE:
02274                 case _CS_COMMAND_BUILDING:
02275                 case _CS_COMMAND_READY:
02276                     tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
02277                     _ct_initialise_cmd(cmd);
02278                     break;
02279                 case _CS_COMMAND_SENT:
02280                     tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
02281                     tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
02282                     tds_send_cancel(cmd_conn->tds_socket);
02283                     tds_process_cancel(cmd_conn->tds_socket);
02284                     _ct_initialise_cmd(cmd);
02285                     break;
02286             }
02287         }
02288         if (conn) {
02289             tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with connection\n");
02290             for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
02291                 tdsdump_log(TDS_DBG_FUNC, "ct_cancel() cancelling a command for a connection\n");
02292                 conn_cmd = cmds->cmd;
02293                 switch (conn_cmd->command_state) {
02294                     case _CS_COMMAND_IDLE:
02295                     case _CS_COMMAND_BUILDING:
02296                     case _CS_COMMAND_READY:
02297                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
02298                         _ct_initialise_cmd(conn_cmd);
02299                         break;
02300                     case _CS_COMMAND_SENT:
02301                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
02302                         tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
02303                         tds_send_cancel(conn->tds_socket);
02304                         tds_process_cancel(conn->tds_socket);
02305                         _ct_initialise_cmd(conn_cmd);
02306                     break;
02307                 }
02308             }
02309         }
02310 
02311         return CS_SUCCEED;
02312     }
02313     return CS_FAIL;
02314 }
02315 
02316 static CS_RETCODE
02317 _ct_cancel_cleanup(CS_COMMAND * cmd)
02318 {
02319     CS_CONNECTION * con;
02320 
02321     con = cmd->con;
02322 
02323     if (con && !IS_TDSDEAD(con->tds_socket))
02324         tds_process_cancel(con->tds_socket);
02325 
02326     cmd->cancel_state = _CS_CANCEL_NOCANCEL;
02327 
02328     return CS_SUCCEED;
02329 
02330 }
02331 
02332 CS_RETCODE
02333 ct_describe(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt)
02334 {
02335     TDSSOCKET *tds;
02336     TDSRESULTINFO *resinfo;
02337     TDSCOLUMN *curcol;
02338     int len;
02339 
02340     tdsdump_log(TDS_DBG_FUNC, "ct_describe()\n");
02341 
02342     if (!cmd->con || !cmd->con->tds_socket)
02343         return CS_FAIL;
02344 
02345     tds = cmd->con->tds_socket;
02346     resinfo = tds->current_results;;
02347 
02348     if (item < 1 || item > resinfo->num_cols)
02349         return CS_FAIL;
02350 
02351     curcol = resinfo->columns[item - 1];
02352     len = curcol->column_namelen;
02353     if (len >= CS_MAX_NAME)
02354         len = CS_MAX_NAME - 1;
02355     strncpy(datafmt->name, curcol->column_name, len);
02356     /* name is always null terminated */
02357     datafmt->name[len] = 0;
02358     datafmt->namelen = len;
02359     /* need to turn the SYBxxx into a CS_xxx_TYPE */
02360     datafmt->datatype = _ct_get_client_type(cmd->con->ctx, curcol->column_type, curcol->column_usertype, curcol->column_size);
02361     tdsdump_log(TDS_DBG_INFO1, "ct_describe() datafmt->datatype = %d server type %d\n", datafmt->datatype,
02362             curcol->column_type);
02363     /* FIXME is ok this value for numeric/decimal? */
02364     datafmt->maxlength = curcol->column_size;
02365     datafmt->usertype = curcol->column_usertype;
02366     datafmt->precision = curcol->column_prec;
02367     datafmt->scale = curcol->column_scale;
02368     /* Added by ssikorsk */
02369     datafmt->format = curcol->column_bindfmt;
02370 
02371     /*
02372      * There are other options that can be returned, but these are the
02373      * only two being noted via the TDS layer.
02374      */
02375     datafmt->status = 0;
02376     if (curcol->column_nullable)
02377         datafmt->status |= CS_CANBENULL;
02378     if (curcol->column_identity)
02379         datafmt->status |= CS_IDENTITY;
02380     if (strcmp(datafmt->name, "txts") == 0)
02381         datafmt->status |= CS_TIMESTAMP;
02382 
02383     datafmt->count = 1;
02384     datafmt->locale = NULL;
02385 
02386     return CS_SUCCEED;
02387 }
02388 
02389 CS_RETCODE
02390 ct_res_info(CS_COMMAND * cmd, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
02391 {
02392     TDSSOCKET *tds;
02393     TDSRESULTINFO *resinfo;
02394     TDSCOLUMN *curcol;
02395     CS_INT int_val;
02396     int i;
02397 
02398     tdsdump_log(TDS_DBG_FUNC, "ct_res_info()\n");
02399 
02400     if (!cmd->con || !cmd->con->tds_socket)
02401         return CS_FAIL;
02402 
02403     tds = cmd->con->tds_socket;
02404     resinfo = tds->current_results;
02405 
02406     switch (type) {
02407     case CS_NUMDATA:
02408         int_val = 0;
02409         if (resinfo) {
02410             for (i = 0; i < resinfo->num_cols; i++) {
02411                 curcol = resinfo->columns[i];
02412                 if (!curcol->column_hidden) {
02413                     int_val++;
02414                 }
02415             }
02416         }
02417         tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of columns is %d\n", int_val);
02418         memcpy(buffer, &int_val, sizeof(CS_INT));
02419         break;
02420     case CS_ROW_COUNT:
02421         int_val = tds->rows_affected;
02422         tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of rows is %d\n", int_val);
02423         memcpy(buffer, &int_val, sizeof(CS_INT));
02424         break;
02425     default:
02426         _csclient_msg(cmd->con->ctx, "ct_res_info", 2, 1, 16, 32, "%d", type);
02427         return CS_FAIL;
02428         break;
02429     }
02430     return CS_SUCCEED;
02431 
02432 }
02433 
02434 CS_RETCODE
02435 ct_config(CS_CONTEXT * ctx, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
02436 {
02437     CS_RETCODE ret = CS_SUCCEED;
02438     CS_INT *buf = (CS_INT *) buffer;
02439 
02440     tdsdump_log(TDS_DBG_FUNC, "ct_config() action = %s property = %d\n",
02441             CS_GET ? "CS_GET" : CS_SET ? "CS_SET" : CS_SUPPORTED ? "CS_SUPPORTED" : "CS_CLEAR", property);
02442 
02443     switch (property) {
02444     case CS_EXPOSE_FMTS:
02445         switch (action) {
02446         case CS_SUPPORTED:
02447             *buf = CS_TRUE;
02448             break;
02449         case CS_SET:
02450             if (*buf != CS_TRUE && *buf != CS_FALSE)
02451                 ret = CS_FAIL;
02452             else
02453                 ctx->config.cs_expose_formats = *buf;
02454             break;
02455         case CS_GET:
02456             if (buf)
02457                 *buf = ctx->config.cs_expose_formats;
02458             else
02459                 ret = CS_FAIL;
02460             break;
02461         case CS_CLEAR:
02462             ctx->config.cs_expose_formats = CS_FALSE;
02463             break;
02464         default:
02465             ret = CS_FAIL;
02466         }
02467         break;
02468     case CS_VER_STRING: {
02469         ret = CS_FAIL;
02470         switch (action) {
02471             case CS_GET: {
02472                 if (buffer && buflen > 0 && outlen) {
02473                     const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
02474                     *outlen= snprintf((char*)buffer, buflen, "%s (%s, default tds version=%s)",
02475                         settings->freetds_version,
02476                         (settings->threadsafe ? "threadsafe" : "non-threadsafe"),
02477                         settings->tdsver
02478                     );
02479                     ((char*)buffer)[buflen - 1]= 0;
02480                     if (*outlen < 0)
02481                         *outlen = strlen((char*) buffer);
02482                     ret = CS_SUCCEED;
02483                 }
02484                 break;
02485                 default:
02486                     ret = CS_FAIL;
02487                     break;
02488                 }
02489             }
02490         }
02491         break;
02492     case CS_VERSION:
02493         ret = CS_FAIL;
02494         switch (action) {
02495             case CS_GET: {
02496                 if (buffer && buflen > 0 && outlen) {
02497                     const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
02498                     *outlen= snprintf(buffer, buflen, "%s", settings->freetds_version);
02499                     ((char*)buffer)[buflen - 1]= 0;
02500                     if (*outlen < 0)
02501                         *outlen = strlen((char*) buffer);
02502                     ret = CS_SUCCEED;
02503                 }
02504                 break;
02505             default:
02506                 ret = CS_FAIL;
02507                 break;
02508             }
02509         }
02510         break;
02511     case CS_TIMEOUT:
02512         switch (action) {
02513         case CS_SET:
02514             ctx->query_timeout = *((unsigned int*)buf);
02515             break;
02516         case CS_GET:
02517             *((unsigned int*)buf) = ctx->query_timeout;
02518             break;
02519         case CS_CLEAR:
02520             ctx->query_timeout = -1;
02521             break;
02522         default:
02523             ret = CS_FAIL;
02524             break;
02525         }
02526         break;
02527     case CS_LOGIN_TIMEOUT:
02528         switch (action) {
02529         case CS_SET:
02530             ctx->login_timeout = *((unsigned int*)buf);
02531             break;
02532         case CS_GET:
02533             *((unsigned int*)buf) = ctx->login_timeout;
02534             break;
02535         case CS_CLEAR:
02536             ctx->login_timeout = -1;
02537             break;
02538         default:
02539             ret = CS_FAIL;
02540             break;
02541         }
02542         break;
02543     default:
02544         ret = CS_SUCCEED;
02545         break;
02546     }
02547 
02548     return ret;
02549 }
02550 
02551 CS_RETCODE
02552 ct_cmd_props(CS_COMMAND * cmd, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
02553 {
02554     TDSSOCKET *tds;
02555     TDSCURSOR *cursor;
02556     int maxcp;
02557 
02558     if (!cmd->con || !cmd->con->tds_socket)
02559         return CS_FAIL;
02560 
02561     tds = cmd->con->tds_socket;
02562 
02563     tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property);
02564     if (action == CS_SET) {
02565         switch (property) {
02566         case CS_USERDATA:
02567             if (cmd->userdata)
02568                 free(cmd->userdata);
02569             cmd->userdata = (void *) malloc(buflen + 1);
02570             tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, cmd->userdata);
02571             cmd->userdata_len = buflen;
02572             memcpy(cmd->userdata, buffer, buflen);
02573             break;
02574         default:
02575             break;
02576         }
02577     }
02578     if (action == CS_GET) {
02579         switch (property) {
02580 
02581         case CS_PARENT_HANDLE:
02582             *(CS_CONNECTION **) buffer = cmd->con;
02583             break;
02584 
02585         case CS_CUR_STATUS:
02586         case CS_CUR_ID:
02587         case CS_CUR_NAME:
02588         case CS_CUR_ROWCOUNT:
02589 
02590             cursor = cmd->cursor;
02591 
02592             if (!cursor) {
02593                 tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() : cannot find cursor\n");
02594                 if (property == CS_CUR_STATUS) {
02595                     *(CS_INT *)buffer = (CS_INT) CS_CURSTAT_NONE;
02596                     if (outlen) *outlen = sizeof(CS_INT);
02597                     return CS_SUCCEED;
02598                 } else {
02599                     return CS_FAIL;
02600                 }
02601             }
02602 
02603             if (property == CS_CUR_STATUS) {
02604                 *(CS_INT *)buffer = cursor->srv_status;
02605                 if (outlen) *outlen = sizeof(CS_INT);
02606             }
02607             if (property == CS_CUR_ID) {
02608                 *(CS_INT *)buffer = cursor->cursor_id;
02609                 if (outlen) *outlen = sizeof(CS_INT);
02610             }
02611             if (property == CS_CUR_NAME) {
02612                 size_t len = strlen(cursor->cursor_name);
02613                 if (len >= buflen)
02614                     return CS_FAIL;
02615                 strcpy(buffer, cursor->cursor_name);
02616                 if (outlen) *outlen = len;
02617             }
02618             if (property == CS_CUR_ROWCOUNT) {
02619                 *(CS_INT *)buffer = cursor->cursor_rows;
02620                 if (outlen) *outlen = sizeof(CS_INT);
02621             }
02622             break;
02623 
02624         case CS_USERDATA:
02625             tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", cmd->userdata);
02626             maxcp = cmd->userdata_len;
02627             if (outlen) *outlen = maxcp;
02628             if (maxcp > buflen)
02629                 maxcp = buflen;
02630             memcpy(buffer, cmd->userdata, maxcp);
02631             break;
02632         default:
02633             break;
02634         }
02635     }
02636     return CS_SUCCEED;
02637 }
02638 
02639 CS_RETCODE
02640 ct_compute_info(CS_COMMAND * cmd, CS_INT type, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
02641 {
02642     TDSSOCKET *tds;
02643     TDSRESULTINFO *resinfo;
02644     TDSCOLUMN *curcol;
02645     CS_INT int_val;
02646     CS_SMALLINT *dest_by_col_ptr;
02647     TDS_SMALLINT *src_by_col_ptr;
02648     int i;
02649 
02650     tdsdump_log(TDS_DBG_FUNC, "ct_compute_info() type = %d, colnum = %d\n", type, colnum);
02651 
02652     if (!cmd->con || !cmd->con->tds_socket)
02653         return CS_FAIL;
02654 
02655     tds = cmd->con->tds_socket;
02656     resinfo = tds->current_results;
02657 
02658     switch (type) {
02659     case CS_BYLIST_LEN:
02660         if (!resinfo) {
02661             int_val = 0;
02662         } else {
02663             int_val = resinfo->by_cols;
02664         }
02665         memcpy(buffer, &int_val, sizeof(CS_INT));
02666         if (outlen)
02667             *outlen = sizeof(CS_INT);
02668         break;
02669     case CS_COMP_BYLIST:
02670         if (buflen < (resinfo->by_cols * sizeof(CS_SMALLINT))) {
02671             return CS_FAIL;
02672         } else {
02673             dest_by_col_ptr = (CS_SMALLINT *) buffer;
02674             src_by_col_ptr = resinfo->bycolumns;
02675             for (i = 0; i < resinfo->by_cols; i++) {
02676                 *dest_by_col_ptr = *src_by_col_ptr;
02677                 dest_by_col_ptr++;
02678                 src_by_col_ptr++;
02679             }
02680             if (outlen)
02681                 *outlen = (resinfo->by_cols * sizeof(CS_SMALLINT));
02682         }
02683         break;
02684     case CS_COMP_COLID:
02685         if (!resinfo) {
02686             int_val = 0;
02687         } else {
02688             curcol = resinfo->columns[colnum - 1];
02689             int_val = curcol->column_operand;
02690         }
02691         memcpy(buffer, &int_val, sizeof(CS_INT));
02692         if (outlen)
02693             *outlen = sizeof(CS_INT);
02694         break;
02695     case CS_COMP_ID:
02696         if (!resinfo) {
02697             int_val = 0;
02698         } else {
02699             int_val = resinfo->computeid;
02700         }
02701         memcpy(buffer, &int_val, sizeof(CS_INT));
02702         if (outlen)
02703             *outlen = sizeof(CS_INT);
02704         break;
02705     case CS_COMP_OP:
02706         if (!resinfo) {
02707             int_val = 0;
02708         } else {
02709             curcol = resinfo->columns[colnum - 1];
02710             int_val = curcol->column_operator;
02711         }
02712         memcpy(buffer, &int_val, sizeof(CS_INT));
02713         if (outlen)
02714             *outlen = sizeof(CS_INT);
02715         break;
02716     default:
02717         _csclient_msg(cmd->con->ctx, "ct_compute_info", 2, 1, 16, 32, "%d", type);
02718         return CS_FAIL;
02719         break;
02720     }
02721     return CS_SUCCEED;
02722 }
02723 
02724 CS_RETCODE
02725 ct_get_data(CS_COMMAND * cmd, CS_INT item, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
02726 {
02727     TDSRESULTINFO *resinfo;
02728     TDSCOLUMN *curcol;
02729     unsigned char *src;
02730     TDS_INT srclen;
02731 
02732     tdsdump_log(TDS_DBG_FUNC, "ct_get_data() item = %d buflen = %d\n", item, buflen);
02733 
02734     if (cmd->cancel_state == _CS_CANCEL_PENDING) {
02735         _ct_cancel_cleanup(cmd);
02736         return CS_CANCELED;
02737     }
02738 
02739     /* basic validations... */
02740 
02741     if (!cmd || !cmd->con || !cmd->con->tds_socket || !(resinfo = cmd->con->tds_socket->current_results))
02742         return CS_FAIL;
02743     if (item < 1 || item > resinfo->num_cols)
02744         return CS_FAIL;
02745     if (buffer == NULL)
02746         return CS_FAIL;
02747     if (buflen == CS_UNUSED)
02748         return CS_FAIL;
02749 
02750     /* This is a new column we are being asked to return */
02751 
02752     if (item != cmd->get_data_item) {
02753         TDSBLOB *blob = NULL;
02754         size_t table_namelen, column_namelen;
02755 
02756         /* allocare needed descriptor if needed */
02757         if (cmd->iodesc)
02758             free(cmd->iodesc);
02759         cmd->iodesc = calloc(1, sizeof(CS_IODESC));
02760         if (!cmd->iodesc)
02761             return CS_FAIL;
02762 
02763         /* reset these values */
02764         cmd->get_data_item = item;
02765         cmd->get_data_bytes_returned = 0;
02766 
02767         /* get at the source data and length */
02768         curcol = resinfo->columns[item - 1];
02769 
02770         src = &(resinfo->current_row[curcol->column_offset]);
02771         if (is_blob_type(curcol->column_type)) {
02772             blob = (TDSBLOB *) src;
02773             src = (unsigned char *) blob->textvalue;
02774         }
02775 
02776         /* now populate the io_desc structure for this data item */
02777 
02778         cmd->iodesc->iotype = CS_IODATA;
02779         cmd->iodesc->datatype = curcol->column_type;
02780         cmd->iodesc->locale = cmd->con->locale;
02781         cmd->iodesc->usertype = curcol->column_usertype;
02782         cmd->iodesc->total_txtlen = curcol->column_cur_size;
02783         cmd->iodesc->offset = curcol->column_offset;
02784         cmd->iodesc->log_on_update = CS_FALSE;
02785 
02786         /* TODO quote needed ?? */
02787         /* avoid possible buffer overflow */
02788         table_namelen = curcol->table_namelen;
02789         if (table_namelen + 2 > sizeof(cmd->iodesc->name))
02790             table_namelen = sizeof(cmd->iodesc->name) - 2;
02791         column_namelen = curcol->column_namelen;
02792         if (table_namelen + column_namelen + 2 > sizeof(cmd->iodesc->name))
02793             column_namelen = sizeof(cmd->iodesc->name) - 2 - table_namelen;
02794 
02795         /* Old code ...
02796         sprintf(cmd->iodesc->name, "%*.*s.%*.*s",
02797             (int) table_namelen, (int) table_namelen, curcol->table_name,
02798             (int) column_namelen, (int) column_namelen, curcol->column_name);
02799 
02800         cmd->iodesc->namelen = strlen(cmd->iodesc->name);
02801         */
02802 
02803         /* New code ... */
02804         if (table_namelen) {
02805             memcpy(cmd->iodesc->name, curcol->table_name, table_namelen);
02806             cmd->iodesc->namelen = table_namelen;
02807         } else {
02808             cmd->iodesc->namelen = 0;
02809         }
02810 
02811         cmd->iodesc->name[cmd->iodesc->namelen] = '.';
02812         ++cmd->iodesc->namelen;
02813 
02814         if (column_namelen) {
02815             memcpy(cmd->iodesc->name + cmd->iodesc->namelen, curcol->column_name, column_namelen);
02816             cmd->iodesc->namelen += column_namelen;
02817         }
02818 
02819         cmd->iodesc->name[cmd->iodesc->namelen] = '\0';
02820 
02821         /* End of new code ... */
02822 
02823         if (blob) {
02824             memcpy(cmd->iodesc->timestamp, blob->timestamp, CS_TS_SIZE);
02825             cmd->iodesc->timestamplen = CS_TS_SIZE;
02826             memcpy(cmd->iodesc->textptr, blob->textptr, CS_TP_SIZE);
02827             cmd->iodesc->textptrlen = CS_TP_SIZE;
02828         }
02829     } else {
02830         /* get at the source data */
02831         curcol = resinfo->columns[item - 1];
02832         src = &(resinfo->current_row[curcol->column_offset]);
02833         if (is_blob_type(curcol->column_type))
02834             src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
02835 
02836     }
02837 
02838     /*
02839      * and adjust the data and length based on
02840      * what we may have already returned
02841      */
02842 
02843     srclen = curcol->column_cur_size;
02844     if (srclen < 0) {
02845         /* this is NULL */
02846         if (outlen)
02847             *outlen = srclen;
02848         if (item < resinfo->num_cols)
02849             return CS_END_ITEM;
02850         return CS_END_DATA;
02851     }
02852 
02853     src += cmd->get_data_bytes_returned;
02854     srclen -= cmd->get_data_bytes_returned;
02855 
02856     /* if we have enough buffer to cope with all the data */
02857 
02858     if (buflen >= srclen) {
02859         memcpy(buffer, src, srclen);
02860         cmd->get_data_bytes_returned += srclen;
02861         if (outlen)
02862             *outlen = srclen;
02863         if (item < resinfo->num_cols)
02864             return CS_END_ITEM;
02865         return CS_END_DATA;
02866 
02867     }
02868     memcpy(buffer, src, buflen);
02869     cmd->get_data_bytes_returned += buflen;
02870     if (outlen)
02871         *outlen = buflen;
02872     return CS_SUCCEED;
02873 }
02874 
02875 CS_RETCODE
02876 ct_send_data(CS_COMMAND * cmd, CS_VOID * buffer, CS_INT buflen)
02877 {
02878     TDSSOCKET *tds;
02879     char writetext_cmd[512];
02880 
02881     char textptr_string[35];    /* 16 * 2 + 2 (0x) + 1 */
02882     char timestamp_string[19];  /* 8 * 2 + 2 (0x) + 1 */
02883     char *c;
02884     int s;
02885     char hex2[3];
02886 
02887     tdsdump_log(TDS_DBG_FUNC, "ct_send_data()\n");
02888 
02889     if (!cmd->con || !cmd->con->tds_socket)
02890         return CS_FAIL;
02891 
02892     tds = cmd->con->tds_socket;
02893 
02894     /* basic validations */
02895 
02896     if (cmd->command_type != CS_SEND_DATA_CMD)
02897         return CS_FAIL;
02898 
02899     if (!cmd->iodesc)
02900         return CS_FAIL;
02901 
02902     /* first ct_send_data for this column */
02903 
02904     if (!cmd->send_data_started) {
02905 
02906         /* turn the timestamp and textptr into character format */
02907 
02908         c = textptr_string;
02909 
02910         for (s = 0; s < cmd->iodesc->textptrlen; s++) {
02911             sprintf(hex2, "%02x", cmd->iodesc->textptr[s]);
02912             *c++ = hex2[0];
02913             *c++ = hex2[1];
02914         }
02915         *c = '\0';
02916 
02917         c = timestamp_string;
02918 
02919         for (s = 0; s < cmd->iodesc->timestamplen; s++) {
02920             sprintf(hex2, "%02x", cmd->iodesc->timestamp[s]);
02921             *c++ = hex2[0];
02922             *c++ = hex2[1];
02923         }
02924         *c = '\0';
02925 
02926         /* submit the "writetext bulk" command */
02927 
02928         sprintf(writetext_cmd, "writetext bulk %s 0x%s timestamp = 0x%s%s",
02929             cmd->iodesc->name,
02930             textptr_string, timestamp_string, ((cmd->iodesc->log_on_update == CS_TRUE) ? " with log" : "")
02931             );
02932 
02933         if (tds_submit_query(tds, writetext_cmd) != TDS_SUCCEED) {
02934             return CS_FAIL;
02935         }
02936 
02937         /* FIXME in this case processing all results can bring state to IDLE... not threading safe */
02938         /* read the end token */
02939         if (tds_process_simple_query(tds) != TDS_SUCCEED)
02940             return CS_FAIL;
02941 
02942         if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
02943             return CS_FAIL;
02944 
02945         cmd->send_data_started = 1;
02946         tds->out_flag = TDS_BULK;
02947         tds_put_int(tds, cmd->iodesc->total_txtlen);
02948     }
02949 
02950     tds->out_flag = TDS_BULK;
02951     tds_put_n(tds, buffer, buflen);
02952 
02953     return CS_SUCCEED;
02954 }
02955 
02956 CS_RETCODE
02957 ct_data_info(CS_COMMAND * cmd, CS_INT action, CS_INT colnum, CS_IODESC * iodesc)
02958 {
02959     TDSSOCKET *tds;
02960     TDSRESULTINFO *resinfo;
02961 
02962     if (!cmd->con || !cmd->con->tds_socket)
02963         return CS_FAIL;
02964 
02965     tds = cmd->con->tds_socket;
02966     resinfo = tds->current_results;
02967 
02968     tdsdump_log(TDS_DBG_FUNC, "ct_data_info() colnum %d\n", colnum);
02969 
02970     switch (action) {
02971     case CS_SET:
02972 
02973         if (cmd->iodesc)
02974             free(cmd->iodesc);
02975         cmd->iodesc = malloc(sizeof(CS_IODESC));
02976 
02977         cmd->iodesc->iotype = CS_IODATA;
02978         
02979         /* ssikorsk  */
02980         /* cmd->iodesc->datatype = iodesc->datatype; */
02981         switch (iodesc->datatype) {
02982             case CS_IMAGE_TYPE:
02983                 cmd->iodesc->datatype = SYBIMAGE;
02984                 break;
02985             case CS_TEXT_TYPE:
02986                 cmd->iodesc->datatype = SYBTEXT;
02987                 break;
02988             default:
02989                 cmd->iodesc->datatype = iodesc->datatype;
02990                 break;
02991         };
02992         
02993         cmd->iodesc->locale = cmd->con->locale;
02994         cmd->iodesc->usertype = iodesc->usertype;
02995         cmd->iodesc->total_txtlen = iodesc->total_txtlen;
02996         cmd->iodesc->offset = iodesc->offset;
02997         cmd->iodesc->log_on_update = iodesc->log_on_update;
02998         strcpy(cmd->iodesc->name, iodesc->name);
02999         cmd->iodesc->namelen = iodesc->namelen;
03000         memcpy(cmd->iodesc->timestamp, iodesc->timestamp, CS_TS_SIZE);
03001         cmd->iodesc->timestamplen = CS_TS_SIZE;
03002         memcpy(cmd->iodesc->textptr, iodesc->textptr, CS_TP_SIZE);
03003         cmd->iodesc->textptrlen = CS_TP_SIZE;
03004         break;
03005 
03006     case CS_GET:
03007 
03008         if (colnum < 1 || colnum > resinfo->num_cols)
03009             return CS_FAIL;
03010         if (colnum != cmd->get_data_item)
03011             return CS_FAIL;
03012 
03013         iodesc->iotype = cmd->iodesc->iotype;
03014         
03015         /* ssikorsk  */
03016         /* iodesc->datatype = cmd->iodesc->datatype; */
03017         switch (cmd->iodesc->datatype) {
03018             case SYBIMAGE:
03019                 iodesc->datatype = CS_IMAGE_TYPE;
03020                 break;
03021             case SYBTEXT:
03022                 iodesc->datatype = CS_TEXT_TYPE;
03023                 break;
03024             default:
03025                 iodesc->datatype = cmd->iodesc->datatype;
03026                 break;
03027         };
03028 
03029         iodesc->locale = cmd->iodesc->locale;
03030         iodesc->usertype = cmd->iodesc->usertype;
03031         iodesc->total_txtlen = cmd->iodesc->total_txtlen;
03032         iodesc->offset = cmd->iodesc->offset;
03033         iodesc->log_on_update = CS_FALSE;
03034         strcpy(iodesc->name, cmd->iodesc->name);
03035         iodesc->namelen = cmd->iodesc->namelen;
03036         memcpy(iodesc->timestamp, cmd->iodesc->timestamp, cmd->iodesc->timestamplen);
03037         iodesc->timestamplen = cmd->iodesc->timestamplen;
03038         memcpy(iodesc->textptr, cmd->iodesc->textptr, cmd->iodesc->textptrlen);
03039         iodesc->textptrlen = cmd->iodesc->textptrlen;
03040         break;
03041 
03042     default:
03043         return CS_FAIL;
03044     }
03045 
03046     return CS_SUCCEED;
03047 }
03048 
03049 CS_RETCODE
03050 ct_capability(CS_CONNECTION * con, CS_INT action, CS_INT type, CS_INT capability, CS_VOID * value)
03051 {
03052     TDSLOGIN *login;
03053     int idx = 0;
03054     unsigned char bitmask = 0;
03055     unsigned char *mask;
03056 
03057     tdsdump_log(TDS_DBG_FUNC, "ct_capability()\n");
03058     login = (TDSLOGIN *) con->tds_login;
03059     mask = login->capabilities;
03060 
03061     if (type == CS_CAP_RESPONSE) {
03062         switch (capability) {
03063         case CS_DATA_NOBOUNDARY:
03064             idx = 13;
03065             bitmask = 0x01;
03066             break;
03067         case CS_RES_NOTDSDEBUG:
03068             idx = 13;
03069             bitmask = 0x02;
03070             break;
03071         case CS_RES_NOSTRIPBLANKS:
03072             idx = 13;
03073             bitmask = 0x04;
03074             break;
03075         case CS_DATA_NOINT8:
03076             idx = 13;
03077             bitmask = 0x08;
03078             break;
03079         case CS_DATA_NOINTN:
03080             idx = 14;
03081             bitmask = 0x01;
03082             break;
03083         case CS_DATA_NODATETIMEN:
03084             idx = 14;
03085             bitmask = 0x02;
03086             break;
03087         case CS_DATA_NOMONEYN:
03088             idx = 14;
03089             bitmask = 0x04;
03090             break;
03091         case CS_CON_NOOOB:
03092             idx = 14;
03093             bitmask = 0x08;
03094             break;
03095         case CS_CON_NOINBAND:
03096             idx = 14;
03097             bitmask = 0x10;
03098             break;
03099         case CS_PROTO_NOTEXT:
03100             idx = 14;
03101             bitmask = 0x20;
03102             break;
03103         case CS_PROTO_NOBULK:
03104             idx = 14;
03105             bitmask = 0x40;
03106             break;
03107         case CS_DATA_NOSENSITIVITY:
03108             idx = 14;
03109             bitmask = 0x80;
03110             break;
03111         case CS_DATA_NOFLT4:
03112             idx = 15;
03113             bitmask = 0x01;
03114             break;
03115         case CS_DATA_NOFLT8:
03116             idx = 15;
03117             bitmask = 0x02;
03118             break;
03119         case CS_DATA_NONUM:
03120             idx = 15;
03121             bitmask = 0x04;
03122             break;
03123         case CS_DATA_NOTEXT:
03124             idx = 15;
03125             bitmask = 0x08;
03126             break;
03127         case CS_DATA_NOIMAGE:
03128             idx = 15;
03129             bitmask = 0x10;
03130             break;
03131         case CS_DATA_NODEC:
03132             idx = 15;
03133             bitmask = 0x20;
03134             break;
03135         case CS_DATA_NOLCHAR:
03136             idx = 15;
03137             bitmask = 0x40;
03138             break;
03139         case CS_DATA_NOLBIN:
03140             idx = 15;
03141             bitmask = 0x80;
03142             break;
03143         case CS_DATA_NOCHAR:
03144             idx = 16;
03145             bitmask = 0x01;
03146             break;
03147         case CS_DATA_NOVCHAR:
03148             idx = 16;
03149             bitmask = 0x02;
03150             break;
03151         case CS_DATA_NOBIN:
03152             idx = 16;
03153             bitmask = 0x04;
03154             break;
03155         case CS_DATA_NOVBIN:
03156             idx = 16;
03157             bitmask = 0x08;
03158             break;
03159         case CS_DATA_NOMNY8:
03160             idx = 16;
03161             bitmask = 0x10;
03162             break;
03163         case CS_DATA_NOMNY4:
03164             idx = 16;
03165             bitmask = 0x20;
03166             break;
03167         case CS_DATA_NODATE8:
03168             idx = 16;
03169             bitmask = 0x40;
03170             break;
03171         case CS_DATA_NODATE4:
03172             idx = 16;
03173             bitmask = 0x80;
03174             break;
03175         case CS_RES_NOMSG:
03176             idx = 17;
03177             bitmask = 0x02;
03178             break;
03179         case CS_RES_NOEED:
03180             idx = 17;
03181             bitmask = 0x04;
03182             break;
03183         case CS_RES_NOPARAM:
03184             idx = 17;
03185             bitmask = 0x08;
03186             break;
03187         case CS_DATA_NOINT1:
03188             idx = 17;
03189             bitmask = 0x10;
03190             break;
03191         case CS_DATA_NOINT2:
03192             idx = 17;
03193             bitmask = 0x20;
03194             break;
03195         case CS_DATA_NOINT4:
03196             idx = 17;
03197             bitmask = 0x40;
03198             break;
03199         case CS_DATA_NOBIT:
03200             idx = 17;
03201             bitmask = 0x80;
03202             break;
03203         default:
03204             tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- attempt to set/get a non-existant capability\n");
03205             return CS_FAIL;
03206         }           /* end capability */
03207 
03208         assert(13 <= idx && idx <= 17);
03209         assert(bitmask);
03210 
03211         switch (action) {
03212         case CS_SET:
03213             /* Having established the offset and the bitmask, we can now turn the capability on or off */
03214             switch (*(CS_BOOL *) value) {
03215             case CS_TRUE:
03216                 mask[idx] |= bitmask;
03217                 break;
03218             case CS_FALSE:
03219                 mask[idx] &= ~bitmask;
03220                 break;
03221             default:
03222                 tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown value\n");
03223                 return CS_FAIL;
03224             }
03225             break;
03226         case CS_GET:
03227             *(CS_BOOL *) value = (mask[idx] & bitmask) ? CS_TRUE : CS_FALSE;
03228             break;
03229         default:
03230             tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown action\n");
03231             return CS_FAIL;
03232         }
03233         return CS_SUCCEED;
03234     } /* End handling CS_CAP_RESPONSE (returned) */
03235 
03236     /*
03237      * Begin handling CS_CAP_REQUEST
03238      * These capabilities describe the types of requests that a server can support.
03239      */
03240     switch (capability) {
03241     case CS_PROTO_DYNPROC:
03242         *(CS_BOOL *) value = mask[2] & 0x01 ? CS_TRUE : CS_FALSE;
03243         break;
03244     case CS_DATA_FLTN:
03245         *(CS_BOOL *) value = mask[2] & 0x02 ? CS_TRUE : CS_FALSE;
03246         break;
03247     case CS_DATA_BITN:
03248         *(CS_BOOL *) value = mask[2] & 0x04 ? CS_TRUE : CS_FALSE;
03249         break;
03250     case CS_DATA_INT8:
03251         *(CS_BOOL *) value = mask[2] & 0x08 ? CS_TRUE : CS_FALSE;
03252         break;
03253     case CS_DATA_VOID:
03254         *(CS_BOOL *) value = mask[2] & 0x10 ? CS_TRUE : CS_FALSE;
03255         break;
03256     case CS_CON_INBAND:
03257         *(CS_BOOL *) value = mask[3] & 0x01 ? CS_TRUE : CS_FALSE;
03258         break;
03259     case CS_CON_LOGICAL:
03260         *(CS_BOOL *) value = mask[3] & 0x02 ? CS_TRUE : CS_FALSE;
03261         break;
03262     case CS_PROTO_TEXT:
03263         *(CS_BOOL *) value = mask[3] & 0x04 ? CS_TRUE : CS_FALSE;
03264         break;
03265     case CS_PROTO_BULK:
03266         *(CS_BOOL *) value = mask[3] & 0x08 ? CS_TRUE : CS_FALSE;
03267         break;
03268     case CS_REQ_URGNOTIF:
03269         *(CS_BOOL *) value = mask[3] & 0x10 ? CS_TRUE : CS_FALSE;
03270         break;
03271     case CS_DATA_SENSITIVITY:
03272         *(CS_BOOL *) value = mask[3] & 0x20 ? CS_TRUE : CS_FALSE;
03273         break;
03274     case CS_DATA_BOUNDARY:
03275         *(CS_BOOL *) value = mask[3] & 0x40 ? CS_TRUE : CS_FALSE;
03276         break;
03277     case CS_PROTO_DYNAMIC:
03278         *(CS_BOOL *) value = mask[3] & 0x80 ? CS_TRUE : CS_FALSE;
03279         break;
03280     case CS_DATA_MONEYN:
03281         *(CS_BOOL *) value = mask[4] & 0x01 ? CS_TRUE : CS_FALSE;
03282         break;
03283     case CS_CSR_PREV:
03284         *(CS_BOOL *) value = mask[4] & 0x02 ? CS_TRUE : CS_FALSE;
03285         break;
03286     case CS_CSR_FIRST:
03287         *(CS_BOOL *) value = mask[4] & 0x04 ? CS_TRUE : CS_FALSE;
03288         break;
03289     case CS_CSR_LAST:
03290         *(CS_BOOL *) value = mask[4] & 0x08 ? CS_TRUE : CS_FALSE;
03291         break;
03292     case CS_CSR_ABS:
03293         *(CS_BOOL *) value = mask[4] & 0x10 ? CS_TRUE : CS_FALSE;
03294         break;
03295     case CS_CSR_REL:
03296         *(CS_BOOL *) value = mask[4] & 0x20 ? CS_TRUE : CS_FALSE;
03297         break;
03298     case CS_CSR_MULTI:
03299         *(CS_BOOL *) value = mask[4] & 0x40 ? CS_TRUE : CS_FALSE;
03300         break;
03301     case CS_CON_OOB:
03302         *(CS_BOOL *) value = mask[4] & 0x80 ? CS_TRUE : CS_FALSE;
03303         break;
03304     case CS_DATA_NUM:
03305         *(CS_BOOL *) value = mask[5] & 0x01 ? CS_TRUE : CS_FALSE;
03306         break;
03307     case CS_DATA_TEXT:
03308         *(CS_BOOL *) value = mask[5] & 0x02 ? CS_TRUE : CS_FALSE;
03309         break;
03310     case CS_DATA_IMAGE:
03311         *(CS_BOOL *) value = mask[5] & 0x04 ? CS_TRUE : CS_FALSE;
03312         break;
03313     case CS_DATA_DEC:
03314         *(CS_BOOL *) value = mask[5] & 0x08 ? CS_TRUE : CS_FALSE;
03315         break;
03316     case CS_DATA_LCHAR:
03317         *(CS_BOOL *) value = mask[5] & 0x10 ? CS_TRUE : CS_FALSE;
03318         break;
03319     case CS_DATA_LBIN:
03320         *(CS_BOOL *) value = mask[5] & 0x20 ? CS_TRUE : CS_FALSE;
03321         break;
03322     case CS_DATA_INTN:
03323         *(CS_BOOL *) value = mask[5] & 0x40 ? CS_TRUE : CS_FALSE;
03324         break;
03325     case CS_DATA_DATETIMEN:
03326         *(CS_BOOL *) value = mask[5] & 0x80 ? CS_TRUE : CS_FALSE;
03327         break;
03328     case CS_DATA_BIN:
03329         *(CS_BOOL *) value = mask[6] & 0x01 ? CS_TRUE : CS_FALSE;
03330         break;
03331     case CS_DATA_VBIN:
03332         *(CS_BOOL *) value = mask[6] & 0x02 ? CS_TRUE : CS_FALSE;
03333         break;
03334     case CS_DATA_MNY8:
03335         *(CS_BOOL *) value = mask[6] & 0x04 ? CS_TRUE : CS_FALSE;
03336         break;
03337     case CS_DATA_MNY4:
03338         *(CS_BOOL *) value = mask[6] & 0x08 ? CS_TRUE : CS_FALSE;
03339         break;
03340     case CS_DATA_DATE8:
03341         *(CS_BOOL *) value = mask[6] & 0x10 ? CS_TRUE : CS_FALSE;
03342         break;
03343     case CS_DATA_DATE4:
03344         *(CS_BOOL *) value = mask[6] & 0x20 ? CS_TRUE : CS_FALSE;
03345         break;
03346     case CS_DATA_FLT4:
03347         *(CS_BOOL *) value = mask[6] & 0x40 ? CS_TRUE : CS_FALSE;
03348         break;
03349     case CS_DATA_FLT8:
03350         *(CS_BOOL *) value = mask[6] & 0x80 ? CS_TRUE : CS_FALSE;
03351         break;
03352     case CS_REQ_MSG:
03353         *(CS_BOOL *) value = mask[7] & 0x01 ? CS_TRUE : CS_FALSE;
03354         break;
03355     case CS_REQ_PARAM:
03356         *(CS_BOOL *) value = mask[7] & 0x02 ? CS_TRUE : CS_FALSE;
03357         break;
03358     case CS_DATA_INT1:
03359         *(CS_BOOL *) value = mask[7] & 0x04 ? CS_TRUE : CS_FALSE;
03360         break;
03361     case CS_DATA_INT2:
03362         *(CS_BOOL *) value = mask[7] & 0x08 ? CS_TRUE : CS_FALSE;
03363         break;
03364     case CS_DATA_INT4:
03365         *(CS_BOOL *) value = mask[7] & 0x10 ? CS_TRUE : CS_FALSE;
03366         break;
03367     case CS_DATA_BIT:
03368         *(CS_BOOL *) value = mask[7] & 0x20 ? CS_TRUE : CS_FALSE;
03369         break;
03370     case CS_DATA_CHAR:
03371         *(CS_BOOL *) value = mask[7] & 0x40 ? CS_TRUE : CS_FALSE;
03372         break;
03373     case CS_DATA_VCHAR:
03374         *(CS_BOOL *) value = mask[7] & 0x80 ? CS_TRUE : CS_FALSE;
03375         break;
03376     case CS_REQ_LANG:
03377         *(CS_BOOL *) value = mask[8] & 0x02 ? CS_TRUE : CS_FALSE;
03378         break;
03379     case CS_REQ_RPC:
03380         *(CS_BOOL *) value = mask[8] & 0x04 ? CS_TRUE : CS_FALSE;
03381         break;
03382     case CS_REQ_NOTIF:
03383         *(CS_BOOL *) value = mask[8] & 0x08 ? CS_TRUE : CS_FALSE;
03384         break;
03385     case CS_REQ_MSTMT:
03386         *(CS_BOOL *) value = mask[8] & 0x10 ? CS_TRUE : CS_FALSE;
03387         break;
03388     case CS_REQ_BCP:
03389         *(CS_BOOL *) value = mask[8] & 0x20 ? CS_TRUE : CS_FALSE;
03390         break;
03391     case CS_REQ_CURSOR:
03392         *(CS_BOOL *) value = mask[8] & 0x40 ? CS_TRUE : CS_FALSE;
03393         break;
03394     case CS_REQ_DYN:
03395         *(CS_BOOL *) value = mask[8] & 0x80 ? CS_TRUE : CS_FALSE;
03396         break;
03397     default:
03398         tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- attempt to get a non-existant capability\n");
03399         return CS_FAIL;
03400         break;
03401     }           /* end capability */
03402 
03403     assert(*(CS_BOOL *) value);
03404 
03405     /* CS_CAP_RESPONSE is read-only */
03406     if (type == CS_CAP_REQUEST && action == CS_GET) {
03407         tdsdump_log(TDS_DBG_INFO1, "ct_capability returns success, value %s\n",
03408             *(CS_BOOL *)value == CS_TRUE ? "TRUE" : "FALSE");
03409         return CS_SUCCEED;
03410     }
03411 
03412     tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- attempt to set a read-only capability (type %d, action %d)\n",
03413         type, action);
03414     return CS_FAIL;
03415 }               /* end ct_capability( */
03416 
03417 
03418 CS_RETCODE
03419 ct_dynamic(CS_COMMAND * cmd, CS_INT type, CS_CHAR * id, CS_INT idlen, CS_CHAR * buffer, CS_INT buflen)
03420 {
03421     int query_len;
03422     CS_CONNECTION *con;
03423     CS_DYNAMIC *dyn;
03424 
03425     if (!cmd->con)
03426         return CS_FAIL;
03427 
03428     cmd->command_type = CS_DYNAMIC_CMD;
03429     cmd->dynamic_cmd = type;
03430 
03431     tdsdump_log(TDS_DBG_FUNC, "ct_dynamic(%d)\n", type);
03432     con = cmd->con;
03433 
03434     switch (type) {
03435     case CS_PREPARE:
03436 
03437         dyn = _ct_allocate_dynamic(con, id, idlen);
03438 
03439         if (dyn == NULL) {
03440             return CS_FAIL;
03441         }
03442 
03443         /* now the query */
03444         if (buflen == CS_NULLTERM) {
03445             query_len = strlen(buffer);
03446         } else {
03447             query_len = buflen;
03448         }
03449         dyn->stmt = (char *) malloc(query_len + 1);
03450         strncpy(dyn->stmt, (char *) buffer, query_len);
03451         dyn->stmt[query_len] = '\0';
03452 
03453         cmd->dyn = dyn;
03454 
03455         break;
03456     case CS_DEALLOC:
03457         cmd->dyn = _ct_locate_dynamic(con, id, idlen);
03458         if (cmd->dyn == NULL)
03459             return CS_FAIL;
03460         break;
03461     case CS_DESCRIBE_INPUT:
03462     case CS_DESCRIBE_OUTPUT:
03463         cmd->dyn = _ct_locate_dynamic(con, id, idlen);
03464         if (cmd->dyn == NULL)
03465             return CS_FAIL;
03466         break;
03467     case CS_EXECUTE:
03468         cmd->dyn = _ct_locate_dynamic(con, id, idlen);
03469         if (cmd->dyn == NULL)
03470             return CS_FAIL;
03471 
03472         tdsdump_log(TDS_DBG_FUNC, "ct_dynamic() calling param_clear\n");
03473         param_clear(cmd->dyn->param_list);
03474         cmd->dyn->param_list = NULL;
03475         break;
03476     }
03477 
03478     ct_set_command_state(cmd, _CS_COMMAND_READY);
03479     return CS_SUCCEED;
03480 }
03481 
03482 CS_RETCODE
03483 ct_param(CS_COMMAND * cmd, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT datalen, CS_SMALLINT indicator)
03484 {
03485     CSREMOTE_PROC *rpc;
03486     CS_DYNAMIC *dyn;
03487     CS_PARAM **pparam;
03488     CS_PARAM *param;
03489 
03490 
03491     tdsdump_log(TDS_DBG_FUNC, "ct_param()\n");
03492     tdsdump_log(TDS_DBG_INFO1, "ct_param() data addr = %p data length = %d\n", data, datalen);
03493 
03494     if (cmd == NULL  ||  cmd->con == NULL)
03495         return CS_FAIL;
03496 
03497     if (datafmt->datatype == CS_VARCHAR_TYPE  &&  IS_TDS7_PLUS(cmd->con->tds_socket))
03498         datafmt->datatype = CS_NVARCHAR_TYPE;
03499     if (datafmt->datatype == CS_LONGCHAR_TYPE  &&  IS_TDS7_PLUS(cmd->con->tds_socket))
03500         datafmt->datatype = CS_NLONGCHAR_TYPE;
03501 
03502     switch (cmd->command_type) {
03503     case CS_RPC_CMD:
03504         if (cmd->rpc == NULL) {
03505             fprintf(stdout, "RPC is NULL ct_param\n");
03506             return CS_FAIL;
03507         }
03508 
03509         param = (CSREMOTE_PROC_PARAM *) malloc(sizeof(CSREMOTE_PROC_PARAM));
03510         if (!param)
03511             return CS_FAIL;
03512         memset(param, 0, sizeof(CSREMOTE_PROC_PARAM));
03513 
03514         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
03515             tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add rpc param\n");
03516             tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add input value\n");
03517             free(param);
03518             return CS_FAIL;
03519         }
03520 
03521         rpc = cmd->rpc;
03522         pparam = &rpc->param_list;
03523         while (*pparam) {
03524             pparam = &(*pparam)->next;
03525         }
03526 
03527         *pparam = param;
03528         tdsdump_log(TDS_DBG_INFO1, " ct_param() added rpc parameter %s \n", (*param).name);
03529         return CS_SUCCEED;
03530         break;
03531 
03532     case CS_LANG_CMD:
03533         /* only accept CS_INPUTVALUE as the status */
03534         if (CS_INPUTVALUE != datafmt->status) {
03535             tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_param()\n", datafmt->status);
03536             return CS_FAIL;
03537         }
03538 
03539         param = (CSREMOTE_PROC_PARAM *) malloc(sizeof(CSREMOTE_PROC_PARAM));
03540         memset(param, 0, sizeof(CSREMOTE_PROC_PARAM));
03541 
03542         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
03543             free(param);
03544             return CS_FAIL;
03545         }
03546 
03547         if (NULL == cmd->input_params)
03548             cmd->input_params = param;
03549         else {
03550             pparam = &cmd->input_params;
03551             while ((*pparam)->next)
03552                 pparam = &(*pparam)->next;
03553             (*pparam)->next = param;
03554         }
03555         tdsdump_log(TDS_DBG_INFO1, "ct_param() added input value\n");
03556         return CS_SUCCEED;
03557         break;
03558 
03559     case CS_DYNAMIC_CMD:
03560         if (cmd->dyn == NULL) {
03561             tdsdump_log(TDS_DBG_INFO1, "cmd->dyn is NULL ct_param\n");
03562             return CS_FAIL;
03563         }
03564 
03565         param = (CS_DYNAMIC_PARAM *) malloc(sizeof(CS_DYNAMIC_PARAM));
03566         if (!param)
03567             return CS_FAIL;
03568         memset(param, 0, sizeof(CS_DYNAMIC_PARAM));
03569 
03570         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
03571             tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add CS_DYNAMIC param\n");
03572             free(param);
03573             return CS_FAIL;
03574         }
03575 
03576         dyn = cmd->dyn;
03577         pparam = &dyn->param_list;
03578         while (*pparam) {
03579             pparam = &(*pparam)->next;
03580         }
03581 
03582         *pparam = param;
03583         return CS_SUCCEED;
03584         break;
03585     }
03586     return CS_FAIL;
03587 }
03588 
03589 CS_RETCODE
03590 ct_setparam(CS_COMMAND * cmd, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT * datalen, CS_SMALLINT * indicator)
03591 {
03592     CSREMOTE_PROC *rpc;
03593     CS_PARAM **pparam;
03594     CS_PARAM *param;
03595     CS_DYNAMIC *dyn;
03596 
03597     tdsdump_log(TDS_DBG_FUNC, "ct_setparam() command type = %d, data type = %d\n", cmd->command_type, datafmt->datatype);
03598 
03599     /* Code changed for RPC functionality - SUHA */
03600     /* RPC code changes starts here */
03601 
03602     if (cmd == NULL)
03603         return CS_FAIL;
03604 
03605     switch (cmd->command_type) {
03606 
03607     case CS_RPC_CMD:
03608 
03609         if (cmd->rpc == NULL) {
03610             fprintf(stdout, "RPC is NULL ct_param\n");
03611             return CS_FAIL;
03612         }
03613 
03614         param = (CSREMOTE_PROC_PARAM *) malloc(sizeof(CSREMOTE_PROC_PARAM));
03615         memset(param, 0, sizeof(CSREMOTE_PROC_PARAM));
03616 
03617         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
03618             tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add rpc param\n");
03619             tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add input value\n");
03620             free(param);
03621             return CS_FAIL;
03622         }
03623 
03624         rpc = cmd->rpc;
03625         pparam = &rpc->param_list;
03626         tdsdump_log(TDS_DBG_INFO1, " ct_setparam() reached here\n");
03627         if (*pparam != NULL) {
03628             while ((*pparam)->next != NULL) {
03629                 pparam = &(*pparam)->next;
03630             }
03631 
03632             pparam = &(*pparam)->next;
03633         }
03634         *pparam = param;
03635         param->next = NULL;
03636         tdsdump_log(TDS_DBG_INFO1, " ct_setparam() added parameter %s \n", (*param).name);
03637         return CS_SUCCEED;
03638         break;
03639 
03640     case CS_DYNAMIC_CMD :
03641 
03642         if (cmd->dyn == NULL) {
03643             fprintf(stdout, "cmd->dyn is NULL ct_param\n");
03644             return CS_FAIL;
03645         }
03646 
03647         param = (CS_DYNAMIC_PARAM *) malloc(sizeof(CS_DYNAMIC_PARAM));
03648         memset(param, 0, sizeof(CS_DYNAMIC_PARAM));
03649 
03650         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
03651             tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add dynamic param\n");
03652             free(param);
03653             return CS_FAIL;
03654         }
03655 
03656         dyn = cmd->dyn;
03657         pparam = &dyn->param_list;
03658         if (*pparam != NULL) {
03659             while ((*pparam)->next != NULL) {
03660                 pparam = &(*pparam)->next;
03661             }
03662 
03663             pparam = &(*pparam)->next;
03664         }
03665         *pparam = param;
03666         param->next = NULL;
03667         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added dynamic parameter\n");
03668         return CS_SUCCEED;
03669         break;
03670 
03671     case CS_LANG_CMD:
03672 
03673         /* only accept CS_INPUTVALUE as the status */
03674         if (CS_INPUTVALUE != datafmt->status) {
03675             tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_setparam()\n", datafmt->status);
03676             return CS_FAIL;
03677         }
03678 
03679         param = (CSREMOTE_PROC_PARAM *) malloc(sizeof(CSREMOTE_PROC_PARAM));
03680         memset(param, 0, sizeof(CSREMOTE_PROC_PARAM));
03681 
03682         if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
03683             tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add language param\n");
03684             free(param);
03685             return CS_FAIL;
03686         }
03687 
03688         if (NULL == cmd->input_params)
03689             cmd->input_params = param;
03690         else {
03691             pparam = &cmd->input_params;
03692             while ((*pparam)->next)
03693                 pparam = &(*pparam)->next;
03694             (*pparam)->next = param;
03695         }
03696         tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added language parameter\n");
03697         return CS_SUCCEED;
03698         break;
03699     }
03700     return CS_FAIL;
03701 }
03702 
03703 CS_RETCODE
03704 ct_options(CS_CONNECTION * con, CS_INT action, CS_INT option, CS_VOID * param, CS_INT paramlen, CS_INT * outlen)
03705 {
03706     TDS_OPTION_CMD tds_command = 0;
03707     TDS_OPTION tds_option = 0;
03708     TDS_OPTION_ARG tds_argument;
03709     TDS_INT tds_argsize = 0;
03710     TDSSOCKET *tds;
03711 
03712     const char *action_string = NULL;
03713     int i;
03714 
03715     /* boolean options can all be treated the same way */
03716     static const struct TDS_BOOL_OPTION_MAP
03717     {
03718         CS_INT option;
03719         TDS_OPTION tds_option;
03720     } tds_bool_option_map[] = {
03721           { CS_OPT_ANSINULL,       TDS_OPT_ANSINULL       }
03722         , { CS_OPT_CHAINXACTS,     TDS_OPT_CHAINXACTS     }
03723         , { CS_OPT_CURCLOSEONXACT, TDS_OPT_CURCLOSEONXACT }
03724         , { CS_OPT_FIPSFLAG,       TDS_OPT_FIPSFLAG       }
03725         , { CS_OPT_FORCEPLAN,      TDS_OPT_FORCEPLAN      }
03726         , { CS_OPT_FORMATONLY,     TDS_OPT_FORMATONLY     }
03727         , { CS_OPT_GETDATA,        TDS_OPT_GETDATA        }
03728         , { CS_OPT_NOCOUNT,        TDS_OPT_NOCOUNT        }
03729         , { CS_OPT_NOEXEC,         TDS_OPT_NOEXEC         }
03730         , { CS_OPT_PARSEONLY,      TDS_OPT_PARSEONLY      }
03731         , { CS_OPT_QUOTED_IDENT,   TDS_OPT_QUOTED_IDENT   }
03732         , { CS_OPT_RESTREES,       TDS_OPT_RESTREES       }
03733         , { CS_OPT_SHOWPLAN,       TDS_OPT_SHOWPLAN       }
03734         , { CS_OPT_STATS_IO,       TDS_OPT_STAT_IO        }
03735         , { CS_OPT_STATS_TIME,     TDS_OPT_STAT_TIME      }
03736     };
03737 
03738     if (param == NULL)
03739         return CS_FAIL;
03740 
03741     tds = con->tds_socket;
03742 
03743     /*
03744      * Set the tds command
03745      */
03746     switch (action) {
03747     case CS_GET:
03748         tds_command = TDS_OPT_LIST; /* will be acknowledged by TDS_OPT_INFO */
03749         action_string = "CS_GET";
03750         tds_argsize = 0;
03751         break;
03752     case CS_SET:
03753         tds_command = TDS_OPT_SET;
03754         action_string = "CS_SET";
03755         break;
03756     case CS_CLEAR:
03757         tds_command = TDS_OPT_DEFAULT;
03758         action_string = "CS_CLEAR";
03759         tds_argsize = 0;
03760         break;
03761     default:
03762         tdsdump_log(TDS_DBG_FUNC, "ct_options: invalid action = %d\n", action);
03763         return CS_FAIL;
03764     }
03765 
03766     assert(tds_command && action_string);
03767 
03768     tdsdump_log(TDS_DBG_FUNC, "ct_options: %s, option = %d\n", action_string, option);
03769 
03770     /*
03771      * Set the tds option
03772      *      The following TDS options apparently cannot be set with this function.
03773      *      TDS_OPT_CHARSET
03774      *      TDS_OPT_CURREAD
03775      *      TDS_OPT_IDENTITYOFF
03776      *      TDS_OPT_IDENTITYON
03777      *      TDS_OPT_CURWRITE
03778      *      TDS_OPT_NATLANG
03779      *      TDS_OPT_ROWCOUNT
03780      *      TDS_OPT_TEXTSIZE
03781      */
03782 
03783     /*
03784      * First, take care of the easy cases, the booleans.
03785      */
03786     for (i = 0; i < TDS_VECTOR_SIZE(tds_bool_option_map); i++) {
03787         if (tds_bool_option_map[i].option == option) {
03788             tds_option = tds_bool_option_map[i].tds_option;
03789             break;
03790         }
03791     }
03792 
03793     if (tds_option != 0) {  /* found a boolean */
03794         if (action == CS_SET) {
03795             switch (*(CS_BOOL *) param) {
03796             case CS_TRUE:
03797                 tds_argument.ti = 1;
03798                 break;
03799             case CS_FALSE:
03800                 tds_argument.ti = 0;
03801                 break;
03802             default:
03803                 return CS_FAIL;
03804             }
03805             tds_argsize = 1;
03806         }
03807         if (action == CS_GET) {
03808             tds_argsize = 0;
03809         }
03810         goto SEND_OPTION;
03811     }
03812 
03813     /*
03814      * Non-booleans are more complicated.
03815      */
03816     switch (option) {
03817     case CS_OPT_ANSIPERM:
03818     case CS_OPT_STR_RTRUNC:
03819         /* no documented tds option */
03820         switch (*(CS_BOOL *) param) {
03821         case CS_TRUE:
03822         case CS_FALSE:
03823             break;  /* end valid choices */
03824         default:
03825             if (action == CS_SET)
03826                 return CS_FAIL;
03827         }
03828         break;
03829     case CS_OPT_ARITHABORT:
03830         switch (*(CS_BOOL *) param) {
03831         case CS_TRUE:
03832             tds_option = TDS_OPT_ARITHABORTON;
03833             break;
03834         case CS_FALSE:
03835             tds_option = TDS_OPT_ARITHABORTOFF;
03836             break;
03837         default:
03838             if (action == CS_SET)
03839                 return CS_FAIL;
03840             tds_option = TDS_OPT_ARITHABORTON;
03841         }
03842         tds_argument.ti = TDS_OPT_ARITHOVERFLOW | TDS_OPT_NUMERICTRUNC;
03843         tds_argsize = (action == CS_SET) ? 1 : 0;
03844         break;
03845     case CS_OPT_ARITHIGNORE:
03846         switch (*(CS_BOOL *) param) {
03847         case CS_TRUE:
03848             tds_option = TDS_OPT_ARITHIGNOREON;
03849             break;
03850         case CS_FALSE:
03851             tds_option = TDS_OPT_ARITHIGNOREOFF;
03852             break;
03853         default:
03854             if (action == CS_SET)
03855                 return CS_FAIL;
03856         }
03857         tds_argument.i = TDS_OPT_ARITHOVERFLOW | TDS_OPT_NUMERICTRUNC;
03858         tds_argsize = (action == CS_SET) ? 4 : 0;
03859         break;
03860     case CS_OPT_AUTHOFF:
03861         tds_option = TDS_OPT_AUTHOFF;
03862         tds_argument.c = (TDS_CHAR *) param;
03863         tds_argsize = (action == CS_SET) ? paramlen : 0;
03864         break;
03865     case CS_OPT_AUTHON:
03866         tds_option = TDS_OPT_AUTHON;
03867         tds_argument.c = (TDS_CHAR *) param;
03868         tds_argsize = (action == CS_SET) ? paramlen : 0;
03869         break;
03870 
03871     case CS_OPT_DATEFIRST:
03872         tds_option = TDS_OPT_DATEFIRST;
03873         switch (*(CS_INT *) param) {
03874         case CS_OPT_SUNDAY:
03875             tds_argument.ti = TDS_OPT_SUNDAY;
03876             break;
03877         case CS_OPT_MONDAY:
03878             tds_argument.ti = TDS_OPT_MONDAY;
03879             break;
03880         case CS_OPT_TUESDAY:
03881             tds_argument.ti = TDS_OPT_TUESDAY;
03882             break;
03883         case CS_OPT_WEDNESDAY:
03884             tds_argument.ti = TDS_OPT_WEDNESDAY;
03885             break;
03886         case CS_OPT_THURSDAY:
03887             tds_argument.ti = TDS_OPT_THURSDAY;
03888             break;
03889         case CS_OPT_FRIDAY:
03890             tds_argument.ti = TDS_OPT_FRIDAY;
03891             break;
03892         case CS_OPT_SATURDAY:
03893             tds_argument.ti = TDS_OPT_SATURDAY;
03894             break;
03895         default:
03896             if (action == CS_SET)
03897                 return CS_FAIL;
03898         }
03899         tds_argsize = (action == CS_SET) ? 1 : 0;
03900         break;
03901     case CS_OPT_DATEFORMAT:
03902         tds_option = TDS_OPT_DATEFORMAT;
03903         switch (*(CS_INT *) param) {
03904         case CS_OPT_FMTMDY:
03905             tds_argument.ti = TDS_OPT_FMTMDY;
03906             break;
03907         case CS_OPT_FMTDMY:
03908             tds_argument.ti = TDS_OPT_FMTDMY;
03909             break;
03910         case CS_OPT_FMTYMD:
03911             tds_argument.ti = TDS_OPT_FMTYMD;
03912             break;
03913         case CS_OPT_FMTYDM:
03914             tds_argument.ti = TDS_OPT_FMTYDM;
03915             break;
03916         case CS_OPT_FMTMYD:
03917             tds_argument.ti = TDS_OPT_FMTMYD;
03918             break;
03919         case CS_OPT_FMTDYM:
03920             tds_argument.ti = TDS_OPT_FMTDYM;
03921             break;
03922         default:
03923             if (action == CS_SET)
03924                 return CS_FAIL;
03925         }
03926         tds_argsize = (action == CS_SET) ? 1 : 0;
03927         break;
03928     case CS_OPT_ISOLATION:
03929         tds_option = TDS_OPT_ISOLATION;
03930         switch (*(char *) param) {
03931         case CS_OPT_LEVEL0: /* CS_OPT_LEVEL0 requires SQL Server version 11.0 or later or Adaptive Server. */
03932             /* no documented value */
03933             tds_option = 0;
03934             tds_argument.ti = 0;
03935             break;
03936         case CS_OPT_LEVEL1:
03937             tds_argument.ti = TDS_OPT_LEVEL1;
03938         case CS_OPT_LEVEL3:
03939             tds_argument.ti = TDS_OPT_LEVEL3;
03940             break;
03941         default:
03942             if (action == CS_SET)
03943                 return CS_FAIL;
03944         }
03945         tds_argsize = (action == CS_SET) ? 1 : 0;
03946         break;
03947     case CS_OPT_TRUNCIGNORE:
03948         tds_option = TDS_OPT_TRUNCABORT;    /* note inverted sense */
03949         switch (*(CS_BOOL *) param) {
03950         case CS_TRUE:
03951         case CS_FALSE:
03952             break;
03953         default:
03954             if (action == CS_SET)
03955                 return CS_FAIL;
03956         }
03957         tds_argument.ti = !*(char *) param;
03958         tds_argsize = (action == CS_SET) ? 1 : 0;
03959         break;
03960     default:
03961         return CS_FAIL; /* invalid option */
03962     }
03963 
03964 SEND_OPTION:
03965 
03966     tdsdump_log(TDS_DBG_FUNC, "\ttds_submit_optioncmd will be action(%s) option(%d) arg(%x) arglen(%d)\n",
03967                 action_string, tds_option, tds_argsize == 1 ? tds_argument.ti : (tds_argsize == 4 ? tds_argument.i : 0), tds_argsize);
03968 
03969     if (tds_submit_optioncmd(tds, tds_command, tds_option, &tds_argument, tds_argsize) == TDS_FAIL) {
03970         return CS_FAIL;
03971     }
03972 
03973     if (action == CS_GET) {
03974         switch (option) {
03975         case CS_OPT_ANSINULL :
03976         case CS_OPT_CHAINXACTS :
03977         case CS_OPT_CURCLOSEONXACT :
03978         case CS_OPT_NOCOUNT :
03979         case CS_OPT_QUOTED_IDENT :
03980             *(CS_BOOL *)param = tds->option_value;
03981             break;
03982         case CS_OPT_DATEFIRST:
03983             switch (tds->option_value) {
03984             case TDS_OPT_SUNDAY: *(CS_INT *)param = CS_OPT_SUNDAY; break;
03985             case TDS_OPT_MONDAY: *(CS_INT *)param = CS_OPT_MONDAY; break;
03986             case TDS_OPT_TUESDAY: *(CS_INT *)param = CS_OPT_TUESDAY; break;
03987             case TDS_OPT_WEDNESDAY: *(CS_INT *)param = CS_OPT_WEDNESDAY; break;
03988             case TDS_OPT_THURSDAY: *(CS_INT *)param = CS_OPT_THURSDAY; break;
03989             case TDS_OPT_FRIDAY: *(CS_INT *)param = CS_OPT_FRIDAY; break;
03990             case TDS_OPT_SATURDAY: *(CS_INT *)param = CS_OPT_SATURDAY; break;
03991             default: return CS_FAIL;
03992             }
03993             break;
03994         case CS_OPT_DATEFORMAT:
03995             switch (tds->option_value) {
03996             case TDS_OPT_FMTDMY: *(CS_INT *)param = CS_OPT_FMTDMY; break;
03997             case TDS_OPT_FMTDYM: *(CS_INT *)param = CS_OPT_FMTDYM; break;
03998             case TDS_OPT_FMTMDY: *(CS_INT *)param = CS_OPT_FMTMDY; break;
03999             case TDS_OPT_FMTMYD: *(CS_INT *)param = CS_OPT_FMTMYD; break;
04000             case TDS_OPT_FMTYMD: *(CS_INT *)param = CS_OPT_FMTYMD; break;
04001             case TDS_OPT_FMTYDM: *(CS_INT *)param = CS_OPT_FMTYDM; break;
04002             default: return CS_FAIL;
04003             }
04004             break;
04005         case CS_OPT_ARITHABORT :
04006         case CS_OPT_ARITHIGNORE :
04007             *(CS_BOOL *)param = tds->option_value;
04008             break;
04009         case CS_OPT_TRUNCIGNORE :
04010             break;
04011         }
04012     }
04013 
04014     return CS_SUCCEED;
04015 }               /* end ct_options() */
04016 
04017 CS_RETCODE
04018 ct_poll(CS_CONTEXT * ctx, CS_CONNECTION * connection, CS_INT milliseconds, CS_CONNECTION ** compconn, CS_COMMAND ** compcmd,
04019     CS_INT * compid, CS_INT * compstatus)
04020 {
04021     tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED ct_poll()\n");
04022     return CS_FAIL;
04023 }
04024 
04025 static
04026 int str_icmp(char* s1, char* s2, int len)
04027 {
04028     int i;
04029 
04030     for (i = 0; i < len; ++i) {
04031         char c1 = s1[i];
04032         char c2 = s2[i];
04033 
04034         if (c1 >= 'a' && c1 <= 'z') {
04035             c1 -= 'a'-'A';
04036         }
04037 
04038         if (c2 >= 'a' && c2 <= 'z') {
04039             c2 -= 'a'-'A';
04040         }
04041 
04042         if (c1 == c2) {
04043             if (c1 == '\0') {
04044                 return 0;
04045             }
04046         } else {
04047             if (c1 < c2) {
04048                 return -1;
04049             } else {
04050                 return 1;
04051             }
04052         }
04053     }
04054 
04055     return 0;
04056 }
04057 
04058 static
04059 char* get_next_tok(char* str, char* delimiter, char **ptrptr)
04060 {
04061     char* result = NULL;
04062     *ptrptr = NULL;
04063 
04064     if (str && delimiter) {
04065         size_t str_len = strlen(str);
04066 
04067         size_t pos = strspn(str, delimiter);
04068 
04069         if (pos == 0) {
04070             *ptrptr = strpbrk(str, delimiter);
04071             return str;
04072         } else {
04073             if (pos != str_len) {
04074                 result = str + pos;
04075                 *ptrptr = strpbrk(result, delimiter);
04076             }
04077         }
04078     }
04079 
04080     return result;
04081 }
04082 
04083 CS_RETCODE
04084 ct_cursor(CS_COMMAND * cmd, CS_INT type, CS_CHAR * name, CS_INT namelen, CS_CHAR * text, CS_INT tlen, CS_INT option)
04085 {
04086     TDSSOCKET *tds;
04087     TDSCURSOR *cursor;
04088 
04089     if (!cmd->con || !cmd->con->tds_socket)
04090         return CS_FAIL;
04091 
04092     tds = cmd->con->tds_socket;
04093     cmd->command_type = CS_CUR_CMD;
04094 
04095     tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : type = %d \n", type);
04096 
04097     switch (type) {
04098     case CS_CURSOR_DECLARE:
04099 
04100         cursor = tds_alloc_cursor(tds, name, namelen == CS_NULLTERM ? strlen(name) + 1 : namelen,
04101                         text, tlen == CS_NULLTERM ? strlen(text) + 1 : tlen);
04102         if (!cursor)
04103             return CS_FAIL;
04104 
04105         cursor->cursor_rows = 1;
04106         cursor->options = option;
04107         cursor->status.declare    = _CS_CURS_TYPE_REQUESTED;
04108         cursor->status.cursor_row = _CS_CURS_TYPE_UNACTIONED;
04109         cursor->status.open       = _CS_CURS_TYPE_UNACTIONED;
04110         cursor->status.fetch      = _CS_CURS_TYPE_UNACTIONED;
04111         cursor->status.close      = _CS_CURS_TYPE_UNACTIONED;
04112         cursor->status.dealloc    = _CS_CURS_TYPE_UNACTIONED;
04113 
04114         /* ssikorsk */
04115         if (option == CS_UNUSED || (option & CS_END) != 0) {
04116             /* Try to figure out type of the cursor. */
04117             char delimiter[] = "\n\t,.[]() ";
04118             int state = 0;
04119             char* savept = NULL;
04120             char* s = text;
04121 
04122             char* tok = get_next_tok(s, delimiter, &savept);
04123             while (tok != NULL) {
04124                 s = savept;
04125 
04126                 if (str_icmp(tok, "FOR", 3) == 0) {
04127                     state = 1;
04128                 } else if (str_icmp(tok, "UPDATE", 6) == 0) {
04129                     if (state == 1) {
04130                         state = 2;
04131                         break;
04132                     }
04133                 } else {
04134                     state = 0;
04135                 }
04136 
04137                 tok = get_next_tok(s, delimiter, &savept);
04138             }
04139 
04140             if (state == 2) {
04141                 /* FOR UPDATE */
04142                 cursor->type = 0x4; /* Forward-only cursor. */
04143             } else {
04144                 /* readonly */
04145                 cursor->type = 0x1; /* Keyset-driven cursor. Default value. */
04146             }
04147         } else if ((option & CS_FOR_UPDATE) != 0) {
04148             cursor->type = 0x4; /* Forward-only cursor. */
04149         } else {
04150             cursor->type = 0x1; /* Keyset-driven cursor. Default value. */
04151         }
04152 
04153         cursor->concurrency = 0x2000 | 0x4; /* Optimistic. Checks timestamps and, when not available, values. */
04154 
04155         cmd->cursor = cursor;
04156         ct_set_command_state(cmd, _CS_COMMAND_READY);
04157         return CS_SUCCEED;
04158         break;
04159 
04160     case CS_CURSOR_ROWS:
04161 
04162         cursor = cmd->cursor;
04163         if (!cursor) {
04164             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
04165             return CS_FAIL;
04166         }
04167 
04168         if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
04169             cursor->status.declare == _CS_CURS_TYPE_SENT) {
04170 
04171             cursor->cursor_rows = option;
04172             cursor->status.cursor_row = _CS_CURS_TYPE_REQUESTED;
04173 
04174             ct_set_command_state(cmd, _CS_COMMAND_READY);
04175             return CS_SUCCEED;
04176         }
04177         else {
04178             cursor->status.cursor_row  = _CS_CURS_TYPE_UNACTIONED;
04179             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
04180             return CS_FAIL;
04181         }
04182         break;
04183 
04184     case CS_CURSOR_OPEN:
04185 
04186         cursor = cmd->cursor;
04187         if (!cursor) {
04188             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
04189             return CS_FAIL;
04190         }
04191 
04192         if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
04193             cursor->status.declare == _CS_CURS_TYPE_SENT ) {
04194 
04195             cursor->status.open  = _CS_CURS_TYPE_REQUESTED;
04196 
04197             return CS_SUCCEED;
04198             ct_set_command_state(cmd, _CS_COMMAND_READY);
04199         }
04200         else {
04201             cursor->status.open = _CS_CURS_TYPE_UNACTIONED;
04202             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
04203             return CS_FAIL;
04204         }
04205 
04206         break;
04207 
04208     case CS_CURSOR_CLOSE:
04209 
04210         cursor = cmd->cursor;
04211         if (!cursor) {
04212             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
04213             return CS_FAIL;
04214         }
04215 
04216         cursor->status.cursor_row = _CS_CURS_TYPE_UNACTIONED;
04217         cursor->status.open       = _CS_CURS_TYPE_UNACTIONED;
04218         cursor->status.fetch      = _CS_CURS_TYPE_UNACTIONED;
04219         cursor->status.close      = _CS_CURS_TYPE_REQUESTED;
04220         if (option == CS_DEALLOC) {
04221             cursor->status.dealloc   = _CS_CURS_TYPE_REQUESTED;
04222         }
04223         ct_set_command_state(cmd, _CS_COMMAND_READY);
04224         return CS_SUCCEED;
04225 
04226     case CS_CURSOR_DEALLOC:
04227 
04228         cursor = cmd->cursor;
04229         if (!cursor) {
04230             tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
04231             return CS_FAIL;
04232         }
04233         cursor->status.dealloc   = _CS_CURS_TYPE_REQUESTED;
04234         ct_set_command_state(cmd, _CS_COMMAND_READY);
04235         return CS_SUCCEED;
04236 
04237     case CS_IMPLICIT_CURSOR:
04238         tdsdump_log(TDS_DBG_INFO1, "CS_IMPLICIT_CURSOR: Option not implemented\n");
04239         return CS_FAIL;
04240     case CS_CURSOR_OPTION:
04241         tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_OPTION: Option not implemented\n");
04242         return CS_FAIL;
04243     case CS_CURSOR_UPDATE:
04244         tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_UPDATE: Option not implemented\n");
04245         return CS_FAIL;
04246     case CS_CURSOR_DELETE:
04247         tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_DELETE: Option not implemented\n");
04248         return CS_FAIL;
04249 
04250     }
04251 
04252     return CS_FAIL;
04253 }
04254 
04255 static int
04256 _ct_fetchable_results(CS_COMMAND * cmd)
04257 {
04258     switch (cmd->curr_result_type) {
04259     case CS_COMPUTE_RESULT:
04260     case CS_CURSOR_RESULT:
04261     case CS_PARAM_RESULT:
04262     case CS_ROW_RESULT:
04263     case CS_STATUS_RESULT:
04264         return 1;
04265     }
04266     return 0;
04267 }
04268 
04269 static int
04270 _ct_process_return_status(TDSSOCKET * tds)
04271 {
04272     TDSRESULTINFO *info;
04273     TDSCOLUMN *curcol;
04274     TDS_INT saved_status;
04275 
04276     enum
04277     { num_cols = 1 };
04278 
04279     assert(tds);
04280     saved_status = tds->ret_status;
04281     tds_free_all_results(tds);
04282 
04283     /* allocate the columns structure */
04284     tds->current_results = tds->res_info = tds_alloc_results(num_cols);
04285 
04286     if (!tds->res_info)
04287         return TDS_FAIL;
04288 
04289     info = tds->res_info;
04290 
04291     curcol = info->columns[0];
04292 
04293     tds_set_column_type(tds, curcol, SYBINT4);
04294 
04295     tdsdump_log(TDS_DBG_INFO1, "generating return status row. type = %d(%s), varint_size %d\n",
04296             curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
04297 
04298     tds_add_row_column_size(info, curcol);
04299 
04300     info->current_row = tds_alloc_row(info);
04301 
04302     if (!info->current_row)
04303         return TDS_FAIL;
04304 
04305     assert(0 <= curcol->column_offset && curcol->column_offset < info->row_size);
04306 
04307     *(TDS_INT *) (info->current_row + curcol->column_offset) = saved_status;
04308 
04309     return TDS_SUCCEED;
04310 }
04311 
04312 /* Code added for RPC functionality  - SUHA */
04313 /* RPC code changes starts here */
04314 
04315 static const unsigned char *
04316 paramrowalloc(TDSPARAMINFO * params, TDSCOLUMN * curcol, int param_num, void *value, int size)
04317 {
04318     const unsigned char *row = tds_alloc_param_row(params, curcol);
04319 
04320     tdsdump_log(TDS_DBG_INFO1, "paramrowalloc, size = %d, offset = %d, row_size = %d\n",
04321                 size, curcol->column_offset,
04322                 params->row_size);
04323     if (!row)
04324         return NULL;
04325 
04326     if (value) {
04327         /* TODO check for BLOB and numeric */
04328         if (size > curcol->column_size)
04329             size = curcol->column_size;
04330 
04331         if (is_blob_type(curcol->column_type)) {
04332             TDSBLOB *blob = &params->current_row[curcol->column_offset];
04333             blob->textvalue = (TDS_CHAR *) malloc(size);
04334             memcpy(blob->textvalue, value, size);
04335         }
04336         else {
04337             memcpy(&params->current_row[curcol->column_offset], value, size);
04338         }
04339         curcol->column_cur_size = size;
04340     } else {
04341         tdsdump_log(TDS_DBG_FUNC, "paramrowalloc(): setting parameter #%d to NULL\n", param_num);
04342         curcol->column_cur_size = -1;
04343     }
04344 
04345     return row;
04346 }
04347 
04348 /**
04349  * Allocate memory and copy the rpc information into a TDSPARAMINFO structure.
04350  */
04351 static TDSPARAMINFO *
04352 paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param)
04353 {
04354     int i;
04355     CS_PARAM *p;
04356     TDSCOLUMN *pcol;
04357     TDSPARAMINFO *params = NULL;
04358 
04359     int temp_type;
04360     CS_BYTE *temp_value;
04361     CS_INT temp_datalen;
04362     int param_is_null;
04363 
04364 
04365     /* sanity */
04366     if (first_param == NULL)
04367         return NULL;
04368 
04369     for (i = 0, p = first_param; p != NULL; p = p->next, i++) {
04370         const unsigned char *prow;
04371 
04372         if (!(params = tds_alloc_param_result(params))) {
04373             _csclient_msg(((CS_CONNECTION*)tds->parent)->ctx, "paraminfoalloc", 2, 1, 17, 33, "");
04374             return NULL;
04375         }
04376 
04377         /* The parameteter data has been passed by reference */
04378         /* i.e. using ct_setparam rather than ct_param       */
04379 
04380         if (p->param_by_value == 0) {
04381 
04382             param_is_null = 0;
04383             temp_datalen = 0;
04384             temp_value = NULL;
04385             temp_type = p->type;
04386 
04387             /* here's one way of passing a null parameter */
04388 
04389             if (*(p->ind) == -1) {
04390                 temp_value = NULL;
04391                 temp_datalen = 0;
04392                 param_is_null = 1;
04393             } else {
04394 
04395                 /* and here's another... */
04396                 if ((*(p->datalen) == 0 || *(p->datalen) == CS_UNUSED) && p->value == NULL) {
04397                     temp_value = NULL;
04398                     temp_datalen = 0;
04399                     param_is_null = 1;
04400                 } else {
04401 
04402                     /* datafmt.datalen is ignored for fixed length types */
04403 
04404                     if (is_fixed_type(temp_type)) {
04405                         temp_datalen = tds_get_size_by_type(temp_type);
04406                     } else {
04407                         temp_datalen = (*(p->datalen) == CS_UNUSED) ? 0 : *(p->datalen);
04408                     }
04409 
04410                     if (temp_datalen && p->value) {
04411                         temp_value = p->value;
04412                     } else {
04413                         temp_value = NULL;
04414                         temp_datalen = 0;
04415                         param_is_null = 1;
04416                     }
04417                 }
04418             }
04419 
04420             if (param_is_null) {
04421                 switch (temp_type) {
04422                 case SYBINT1:
04423                 case SYBINT2:
04424                 case SYBINT4:
04425                 /* TODO check if supported ?? */
04426                 case SYBINT8:
04427                     temp_type = SYBINTN;
04428                     break;
04429                 case SYBDATETIME:
04430                 case SYBDATETIME4:
04431                     temp_type = SYBDATETIMN;
04432                     break;
04433                 case SYBFLT8:
04434                     temp_type = SYBFLTN;
04435                     break;
04436                 case SYBBIT:
04437                     temp_type = SYBBITN;
04438                     break;
04439                 case SYBMONEY:
04440                 case SYBMONEY4:
04441                     temp_type = SYBMONEYN;
04442                     break;
04443                 default:
04444                     break;
04445                 }
04446             }
04447         } else {
04448             temp_type = p->type;
04449             temp_value = p->value;
04450             temp_datalen = *(p->datalen);
04451         }
04452 
04453         pcol = params->columns[i];
04454 
04455         /* meta data */
04456         pcol->column_namelen = 0;
04457         if (p->name) {
04458             tds_strlcpy(pcol->column_name, p->name, sizeof(pcol->column_name));
04459             pcol->column_namelen = strlen(pcol->column_name);
04460         }
04461 
04462         if (p->status == CS_RETURN)
04463             pcol->column_output = 1;
04464         else
04465             pcol->column_output = 0;
04466 
04467         tds_set_param_type(tds, pcol, temp_type);
04468 
04469         if (temp_datalen == CS_NULLTERM && temp_value)
04470             temp_datalen = strlen((const char*) temp_value);
04471 
04472         pcol->column_prec = p->precision;
04473         pcol->column_scale = p->scale;
04474         if (pcol->column_varint_size) {
04475             if (p->maxlen < 0)
04476                 return NULL;
04477             pcol->on_server.column_size = pcol->column_size = p->maxlen;
04478             pcol->column_cur_size = temp_datalen;
04479             if (temp_datalen > 0 && temp_datalen > p->maxlen)
04480                 pcol->on_server.column_size = pcol->column_size = temp_datalen;
04481         } else {
04482             pcol->column_cur_size = pcol->column_size;
04483         }
04484 
04485         /* actual data */
04486         tdsdump_log(TDS_DBG_FUNC, "paraminfoalloc: status = %d, maxlen %d \n", p->status, p->maxlen);
04487         tdsdump_log(TDS_DBG_FUNC,
04488                 "paraminfoalloc: name = %*.*s, varint size %d column_type %d size %d, %d column_cur_size %d column_output = %d\n",
04489                 pcol->column_namelen, pcol->column_namelen, pcol->column_name,
04490                 pcol->column_varint_size, pcol->column_type,
04491                 pcol->on_server.column_size, pcol->column_size,
04492                 pcol->column_cur_size, pcol->column_output);
04493         prow = paramrowalloc(params, pcol, i, temp_value, temp_datalen);
04494         if (!prow) {
04495             _csclient_msg(((CS_CONNECTION*)tds->parent)->ctx, "paraminfoalloc", 2, 1, 17, 33, "");
04496             return NULL;
04497         }
04498     }
04499 
04500     return params;
04501 
04502 }
04503 
04504 static void
04505 rpc_clear(CSREMOTE_PROC * rpc)
04506 {
04507     if (rpc == NULL)
04508         return;
04509 
04510     param_clear(rpc->param_list);
04511 
04512     assert(rpc->name);
04513     free(rpc->name);
04514     free(rpc);
04515 }
04516 
04517 /**
04518  * recursively erase the parameter list
04519  */
04520 static void
04521 param_clear(CS_PARAM * pparam)
04522 {
04523     if (pparam == NULL)
04524         return;
04525 
04526     if (pparam->next) {
04527         param_clear(pparam->next);
04528         pparam->next = NULL;
04529     }
04530 
04531     /* free self after clearing children */
04532 
04533     if (pparam->name)
04534         free(pparam->name);
04535     if (pparam->param_by_value)
04536         free(pparam->value);
04537 
04538     /*
04539      * DO NOT free datalen or ind, they are just pointer
04540      * to client data or private structure
04541      */
04542 
04543     free(pparam);
04544 }
04545 
04546 /* RPC Code changes ends here */
04547 
04548 
04549 static int
04550 _ct_fill_param(CS_INT cmd_type, CS_PARAM * param, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT * datalen, CS_SMALLINT * indicator, CS_BYTE byvalue)
04551 {
04552     int param_is_null = 0;
04553 
04554     if (cmd_type == CS_DYNAMIC_CMD) {
04555         param->name = NULL;
04556     } else {
04557         if (datafmt->namelen == CS_NULLTERM) {
04558             param->name = strdup(datafmt->name);
04559             if (param->name == NULL)
04560                 return CS_FAIL;
04561         } else if (datafmt->namelen > 0) {
04562             param->name = malloc(datafmt->namelen + 1);
04563             if (param->name == NULL)
04564                 return CS_FAIL;
04565             memset(param->name, 0, datafmt->namelen + 1);
04566             strncpy(param->name, datafmt->name, datafmt->namelen);
04567         } else {
04568             param->name = NULL;
04569         }
04570     }
04571 
04572     param->status = datafmt->status;
04573     tdsdump_log(TDS_DBG_INFO1, " _ct_fill_param() status = %d \n", param->status);
04574 
04575     /*
04576      * translate datafmt.datatype, e.g. CS_SMALLINT_TYPE
04577      * to Server type, e.g. SYBINT2
04578      */
04579     param->type = _ct_get_server_type(datafmt->datatype);
04580 
04581     if (is_numeric_type(param->type)) {
04582         param->scale = datafmt->scale;
04583         param->precision = datafmt->precision;
04584         if (param->scale < 0 || param->precision < 0
04585             || param->precision > 77 || param->scale > param->precision)
04586             return CS_FAIL;
04587     }
04588 
04589     param->maxlen = datafmt->maxlength;
04590 
04591     if (is_fixed_type(param->type)) {
04592         param->maxlen = tds_get_size_by_type(param->type);
04593     }
04594 
04595     param->param_by_value = byvalue;
04596 
04597     if (byvalue) {
04598         param->datalen = &param->datalen_value;
04599         *(param->datalen) = *datalen;
04600 
04601         param->ind = &param->indicator_value;
04602         *(param->ind) = *indicator;
04603 
04604         /* here's one way of passing a null parameter */
04605 
04606         if (*indicator == -1) {
04607             param->value = NULL;
04608             *(param->datalen) = 0;
04609             param_is_null = 1;
04610         } else {
04611 
04612             /* and here's another... */
04613             if ((*datalen == 0 || *datalen == CS_UNUSED) && data == NULL) {
04614                 param->value = NULL;
04615                 *(param->datalen) = 0;
04616                 param_is_null = 1;
04617             } else {
04618 
04619                 /* datafmt.datalen is ignored for fixed length types */
04620 
04621                 if (is_fixed_type(param->type)) {
04622                     *(param->datalen) = tds_get_size_by_type(param->type);
04623                 } else {
04624                     *(param->datalen) = (*datalen == CS_UNUSED) ? 0 : *datalen;
04625                 }
04626 
04627                 if (data) {
04628                     if (*(param->datalen) == CS_NULLTERM) {
04629                         tdsdump_log(TDS_DBG_INFO1, " _ct_fill_param() about to strdup string %u bytes long\n",
04630                                 (unsigned int) strlen(data));
04631                         *(param->datalen) = strlen(data);
04632                     } else if (*(param->datalen) < 0) {
04633                         return CS_FAIL;
04634                     }
04635                     param->value = malloc(*(param->datalen));
04636                     if (param->value == NULL)
04637                         return CS_FAIL;
04638                     memcpy(param->value, data, *(param->datalen));
04639                     param->param_by_value = 1;
04640                 } else {
04641                     param->value = NULL;
04642                     *(param->datalen) = 0;
04643                     param_is_null = 1;
04644                 }
04645             }
04646         }
04647 
04648         if (param_is_null) {
04649             switch (param->type) {
04650             case SYBINT1:
04651             case SYBINT2:
04652             case SYBINT4:
04653             /* TODO check if supported ?? */
04654             case SYBINT8:
04655                 param->type = SYBINTN;
04656                 break;
04657             case SYBDATETIME:
04658             case SYBDATETIME4:
04659                 param->type = SYBDATETIMN;
04660                 break;
04661             case SYBFLT8:
04662                 param->type = SYBFLTN;
04663                 break;
04664             case SYBBIT:
04665                 param->type = SYBBITN;
04666                 break;
04667             case SYBMONEY:
04668             case SYBMONEY4:
04669                 param->type = SYBMONEYN;
04670                 break;
04671             default:
04672                 break;
04673             }
04674         }
04675     } else {        /* not by value, i.e. by reference */
04676         param->datalen = datalen;
04677         param->ind = indicator;
04678         param->value = data;
04679     }
04680     return CS_SUCCEED;
04681 }
04682 
04683 /* Code added for ct_diag implementation */
04684 /* Code changes start here - CT_DIAG - 02*/
04685 
04686 CS_RETCODE
04687 ct_diag(CS_CONNECTION * conn, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
04688 {
04689     switch (operation) {
04690     case CS_INIT:
04691         if (conn->ctx->cs_errhandletype == _CS_ERRHAND_CB) {
04692             /* contrary to the manual page you don't seem to */
04693             /* be able to turn on inline message handling    */
04694             /* using cs_diag, once a callback is installed!  */
04695             return CS_FAIL;
04696         }
04697 
04698         conn->ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
04699 
04700         if (conn->ctx->cs_diag_msglimit_client == 0)
04701             conn->ctx->cs_diag_msglimit_client = CS_NO_LIMIT;
04702 
04703         if (conn->ctx->cs_diag_msglimit_server == 0)
04704             conn->ctx->cs_diag_msglimit_server = CS_NO_LIMIT;
04705 
04706         if (conn->ctx->cs_diag_msglimit_total == 0)
04707             conn->ctx->cs_diag_msglimit_total = CS_NO_LIMIT;
04708 
04709         conn->ctx->_clientmsg_cb = (CS_CLIENTMSG_FUNC) ct_diag_storeclientmsg;
04710         conn->ctx->_servermsg_cb = (CS_SERVERMSG_FUNC) ct_diag_storeservermsg;
04711 
04712         break;
04713 
04714     case CS_MSGLIMIT:
04715         if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
04716             return CS_FAIL;
04717 
04718         if (type == CS_CLIENTMSG_TYPE)
04719             conn->ctx->cs_diag_msglimit_client = *(CS_INT *) buffer;
04720 
04721         if (type == CS_SERVERMSG_TYPE)
04722             conn->ctx->cs_diag_msglimit_server = *(CS_INT *) buffer;
04723 
04724         if (type == CS_ALLMSG_TYPE)
04725             conn->ctx->cs_diag_msglimit_total = *(CS_INT *) buffer;
04726 
04727         break;
04728 
04729     case CS_CLEAR:
04730         if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
04731             return CS_FAIL;
04732         return _ct_diag_clearmsg(conn->ctx, type);
04733         break;
04734 
04735     case CS_GET:
04736         if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
04737             return CS_FAIL;
04738 
04739         if (buffer == NULL)
04740             return CS_FAIL;
04741 
04742         if (type == CS_CLIENTMSG_TYPE) {
04743             if (idx == 0
04744                 || (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_client))
04745                 return CS_FAIL;
04746 
04747             return (ct_diag_getclientmsg(conn->ctx, idx, (CS_CLIENTMSG *) buffer));
04748         }
04749 
04750         if (type == CS_SERVERMSG_TYPE) {
04751             if (idx == 0
04752                 || (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_server))
04753                 return CS_FAIL;
04754             return (ct_diag_getservermsg(conn->ctx, idx, (CS_SERVERMSG *) buffer));
04755         }
04756 
04757         break;
04758 
04759     case CS_STATUS:
04760         if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
04761             return CS_FAIL;
04762         if (buffer == NULL)
04763             return CS_FAIL;
04764 
04765         return (ct_diag_countmsg(conn->ctx, type, (CS_INT *) buffer));
04766         break;
04767     }
04768     return CS_SUCCEED;
04769 }
04770 
04771 static CS_INT
04772 ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message)
04773 {
04774     struct cs_diag_msg_client **curptr;
04775     struct cs_diag_msg_svr **scurptr;
04776 
04777     CS_INT msg_count = 0;
04778 
04779     curptr = &(conn->ctx->clientstore);
04780 
04781     scurptr = &(conn->ctx->svrstore);
04782 
04783     /* if we already have a list of messages, */
04784     /* go to the end of the list...           */
04785 
04786     while (*curptr != NULL) {
04787         msg_count++;
04788         curptr = &((*curptr)->next);
04789     }
04790 
04791     /* messages over and above the agreed limit */
04792     /* are simply discarded...                  */
04793 
04794     if (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_client) {
04795         return CS_FAIL;
04796     }
04797 
04798     /* messages over and above the agreed TOTAL limit */
04799     /* are simply discarded */
04800 
04801     if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
04802         while (*scurptr != NULL) {
04803             msg_count++;
04804             scurptr = &((*scurptr)->next);
04805         }
04806         if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
04807             return CS_FAIL;
04808         }
04809     }
04810 
04811     *curptr = (struct cs_diag_msg_client *) malloc(sizeof(struct cs_diag_msg_client));
04812     if (*curptr == NULL) {
04813         return CS_FAIL;
04814     } else {
04815         (*curptr)->next = NULL;
04816         (*curptr)->clientmsg = malloc(sizeof(CS_CLIENTMSG));
04817         if ((*curptr)->clientmsg == NULL) {
04818             return CS_FAIL;
04819         } else {
04820             memcpy((*curptr)->clientmsg, message, sizeof(CS_CLIENTMSG));
04821         }
04822     }
04823 
04824     return CS_SUCCEED;
04825 }
04826 
04827 static CS_INT
04828 ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message)
04829 {
04830     struct cs_diag_msg_svr **curptr;
04831     struct cs_diag_msg_client **ccurptr;
04832 
04833     CS_INT msg_count = 0;
04834 
04835     curptr = &(conn->ctx->svrstore);
04836     ccurptr = &(conn->ctx->clientstore);
04837 
04838     /* if we already have a list of messages, */
04839     /* go to the end of the list...           */
04840 
04841     while (*curptr != NULL) {
04842         msg_count++;
04843         curptr = &((*curptr)->next);
04844     }
04845 
04846     /* messages over and above the agreed limit */
04847     /* are simply discarded...                  */
04848 
04849     if (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_server) {
04850         return CS_FAIL;
04851     }
04852 
04853     /* messages over and above the agreed TOTAL limit */
04854     /* are simply discarded...                  */
04855 
04856     if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
04857         while (*ccurptr != NULL) {
04858             msg_count++;
04859             ccurptr = &((*ccurptr)->next);
04860         }
04861         if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
04862             return CS_FAIL;
04863         }
04864     }
04865 
04866     *curptr = (struct cs_diag_msg_svr *) malloc(sizeof(struct cs_diag_msg_svr));
04867     if (*curptr == NULL) {
04868         return CS_FAIL;
04869     } else {
04870         (*curptr)->next = NULL;
04871         (*curptr)->servermsg = malloc(sizeof(CS_SERVERMSG));
04872         if ((*curptr)->servermsg == NULL) {
04873             return CS_FAIL;
04874         } else {
04875             memcpy((*curptr)->servermsg, message, sizeof(CS_SERVERMSG));
04876         }
04877     }
04878 
04879     return CS_SUCCEED;
04880 }
04881 
04882 static CS_INT
04883 ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message)
04884 {
04885     struct cs_diag_msg_client *curptr;
04886     CS_INT msg_count = 0, msg_found = 0;
04887 
04888     curptr = context->clientstore;
04889 
04890     /* if we already have a list of messages, */
04891     /* go to the end of the list...           */
04892 
04893     while (curptr != NULL) {
04894         msg_count++;
04895         if (msg_count == idx) {
04896             msg_found++;
04897             break;
04898         }
04899         curptr = curptr->next;
04900     }
04901 
04902     if (msg_found) {
04903         memcpy(message, curptr->clientmsg, sizeof(CS_CLIENTMSG));
04904         return CS_SUCCEED;
04905     }
04906     return CS_NOMSG;
04907 }
04908 
04909 static CS_INT
04910 ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message)
04911 {
04912     struct cs_diag_msg_svr *curptr;
04913     CS_INT msg_count = 0, msg_found = 0;
04914 
04915     curptr = context->svrstore;
04916 
04917     /* if we already have a list of messages, */
04918     /* go to the end of the list...           */
04919 
04920     while (curptr != NULL) {
04921         msg_count++;
04922         if (msg_count == idx) {
04923             msg_found++;
04924             break;
04925         }
04926         curptr = curptr->next;
04927     }
04928 
04929     if (msg_found) {
04930         memcpy(message, curptr->servermsg, sizeof(CS_SERVERMSG));
04931         return CS_SUCCEED;
04932     } else {
04933         return CS_NOMSG;
04934     }
04935 }
04936 
04937 CS_INT
04938 _ct_diag_clearmsg(CS_CONTEXT * context, CS_INT type)
04939 {
04940     struct cs_diag_msg_client *curptr, *freeptr;
04941     struct cs_diag_msg_svr *scurptr, *sfreeptr;
04942 
04943     if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
04944         curptr = context->clientstore;
04945         context->clientstore = NULL;
04946 
04947         while (curptr != NULL) {
04948             freeptr = curptr;
04949             curptr = freeptr->next;
04950             if (freeptr->clientmsg)
04951                 free(freeptr->clientmsg);
04952             free(freeptr);
04953         }
04954     }
04955 
04956     if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
04957         scurptr = context->svrstore;
04958         context->svrstore = NULL;
04959 
04960         while (scurptr != NULL) {
04961             sfreeptr = scurptr;
04962             scurptr = sfreeptr->next;
04963             if (sfreeptr->servermsg)
04964                 free(sfreeptr->servermsg);
04965             free(sfreeptr);
04966         }
04967     }
04968     return CS_SUCCEED;
04969 }
04970 
04971 static CS_INT
04972 ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count)
04973 {
04974     struct cs_diag_msg_client *curptr;
04975     struct cs_diag_msg_svr *scurptr;
04976 
04977     CS_INT msg_count = 0;
04978 
04979     if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
04980         curptr = context->clientstore;
04981 
04982         while (curptr != NULL) {
04983             msg_count++;
04984             curptr = curptr->next;
04985         }
04986     }
04987 
04988     if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
04989         scurptr = context->svrstore;
04990 
04991         while (scurptr != NULL) {
04992             msg_count++;
04993             scurptr = scurptr->next;
04994         }
04995     }
04996     *count = msg_count;
04997 
04998     return CS_SUCCEED;
04999 }
05000 
05001 /* Code changes ends here - CT_DIAG - 02*/
05002 
05003 static CS_DYNAMIC *
05004 _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen)
05005 {
05006     CS_DYNAMIC *dyn;
05007     CS_DYNAMIC **pdyn;
05008     int id_len;
05009 
05010     dyn = (CS_DYNAMIC *) malloc(sizeof(CS_DYNAMIC));
05011 
05012     if (idlen == CS_NULLTERM)
05013         id_len = strlen(id);
05014     else
05015         id_len = idlen;
05016 
05017     if (dyn != NULL) {
05018         memset(dyn, '\0', sizeof(CS_DYNAMIC));
05019         dyn->id = malloc(id_len + 1);
05020         strncpy(dyn->id, id, id_len);
05021         dyn->id[id_len] = '\0';
05022 
05023         if (con->dynlist == NULL) {
05024             tdsdump_log(TDS_DBG_INFO1, "_ct_allocate_dynamic() attaching dynamic command to head\n");
05025             con->dynlist = dyn;
05026         } else {
05027             pdyn = &con->dynlist;
05028             while (*pdyn) {
05029                 pdyn = &(*pdyn)->next;
05030             }
05031 
05032             *pdyn = dyn;
05033         }
05034     }
05035     return (dyn);
05036 }
05037 
05038 static CS_DYNAMIC *
05039 _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen)
05040 {
05041     CS_DYNAMIC *dyn;
05042     int id_len;
05043 
05044     if (idlen == CS_NULLTERM)
05045         id_len = strlen(id);
05046     else
05047         id_len = idlen;
05048 
05049     tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() looking for %s\n", (char *) id);
05050 
05051     for (dyn = con->dynlist; dyn != NULL; dyn = dyn->next) {
05052         tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() matching with %s\n", (char *) dyn->id);
05053         if (strncmp(dyn->id, id, id_len) == 0)
05054             break;
05055     }
05056 
05057     return (dyn);
05058 }
05059 
05060 static CS_INT
05061 _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn)
05062 {
05063     CS_DYNAMIC_LIST *victim = NULL;
05064     CS_DYNAMIC_LIST *prev = NULL;
05065     CS_DYNAMIC_LIST *next = NULL;
05066     TDSDYNAMIC *tdsdyn;
05067     char myid[256];
05068 
05069     strcpy(myid,"");
05070 
05071     victim = con->dynlist;
05072 
05073     for (;;) {
05074         if (victim == dyn)
05075             break;
05076         prev = victim;
05077         victim = victim->next;
05078         if (victim == NULL) {
05079             tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : cannot find entry in list\n");
05080             return CS_FAIL;
05081         }
05082     }
05083 
05084     tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : command entry found in list\n");
05085 
05086     next = victim->next;
05087 
05088     if (victim->id) {
05089         strcpy(myid, victim->id);
05090         free(victim->id);
05091     }
05092     if (victim->stmt) free(victim->stmt);
05093     param_clear(victim->param_list);
05094 
05095     free(victim);
05096 
05097     tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinking list\n");
05098 
05099     if (prev)
05100         prev->next = next;
05101     else
05102         con->dynlist = next;
05103 
05104     tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinked list\n");
05105 
05106     if (strlen(myid) > 0) {
05107         tdsdyn = tds_lookup_dynamic(con->tds_socket, myid);
05108         if (tdsdyn) {
05109             tds_free_dynamic(con->tds_socket, tdsdyn);
05110         }
05111     }
05112 
05113     return CS_SUCCEED;
05114 
05115 }
05116 
05117 

Generated on Wed Dec 9 04:15:40 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:17:56 2009 by modify_doxy.py rev. 173732