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