NCBI C++ ToolKit
ct.c
Go to the documentation of this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

Go to the SVN repository for this file.

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