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