NCBI C++ ToolKit
query.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, 2002, 2003, 2004, 2005 Brian Bruns
3  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 
26 #if HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif /* HAVE_STDLIB_H */
29 
30 #if HAVE_STRING_H
31 #include <string.h>
32 #endif /* HAVE_STRING_H */
33 
34 #include <ctype.h>
35 
36 #include <freetds/tds.h>
37 #include <freetds/enum_cap.h>
38 #include <freetds/iconv.h>
39 #include <freetds/convert.h>
40 #include <freetds/utils/string.h>
41 #include <freetds/checks.h>
42 #include <freetds/stream.h>
43 #include <freetds/bytes.h>
44 #include <freetds/replacements.h>
45 
46 #include <assert.h>
47 
49 static void tds7_put_query_params(TDSSOCKET * tds, const char *query, size_t query_len);
50 static TDSRET tds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags);
51 static inline TDSRET tds_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol);
52 static TDSRET tds7_write_param_def_from_query(TDSSOCKET * tds, const char* converted_query,
53  size_t converted_query_len, TDSPARAMINFO * params) TDS_WUR;
54 static TDSRET tds7_write_param_def_from_params(TDSSOCKET * tds, const char* query, size_t query_len,
55  TDSPARAMINFO * params) TDS_WUR;
56 
57 static TDSRET tds_put_param_as_string(TDSSOCKET * tds, TDSPARAMINFO * params, int n);
58 static TDSRET tds_send_emulated_execute(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params);
59 static int tds_count_placeholders_ucs2le(const char *query, const char *query_end);
60 
61 #define TDS_PUT_DATA_USE_NAME 1
62 #define TDS_PUT_DATA_PREFIX_NAME 2
63 #define TDS_PUT_DATA_LONG_STATUS 4
64 
65 #undef MIN
66 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
67 #undef MAX
68 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
69 
70 /* All manner of client to server submittal functions */
71 
72 /**
73  * \ingroup libtds
74  * \defgroup query Query
75  * Function to handle query.
76  */
77 
78 /**
79  * \addtogroup query
80  * @{
81  */
82 
83 /**
84  * Accept an ASCII string, convert it to UCS2-LE
85  * The input is NUL-terminated, but the output does not contains the NUL.
86  * \param buffer buffer where to store output
87  * \param buf string to write
88  * \return bytes written
89  */
90 static size_t
91 tds_ascii_to_ucs2(char *buffer, const char *buf)
92 {
93  char *s;
94  assert(buffer && buf && *buf); /* This is an internal function. Call it correctly. */
95 
96  for (s = buffer; *buf != '\0'; ++buf) {
97  *s++ = *buf;
98  *s++ = '\0';
99  }
100 
101  return s - buffer;
102 }
103 
104 /**
105  * Utility to convert a constant ascii string to ucs2 and send to server.
106  * Used to send internal store procedure names to server.
107  * \tds
108  * \param s constanst string to send
109  */
110 #define TDS_PUT_N_AS_UCS2(tds, s) do { \
111  char buffer[sizeof(s)*2-2]; \
112  tds_put_smallint(tds, sizeof(buffer)/2); \
113  tds_put_n(tds, buffer, tds_ascii_to_ucs2(buffer, s)); \
114 } while(0)
115 
116 /**
117  * Convert a string in an allocated buffer
118  * \param tds state information for the socket and the TDS protocol
119  * \param char_conv information about the encodings involved
120  * \param s input string
121  * \param len input string length (in bytes), -1 for NUL-terminated
122  * \param out_len returned output length (in bytes)
123  * \return string allocated (or input pointer if no conversion required) or NULL if error
124  */
125 const char *
126 tds_convert_string(TDSSOCKET * tds, TDSICONV * char_conv, const char *s,
127  ssize_t len, size_t *out_len)
128 {
129  char *buf;
130 
131  const char *ib;
132  char *ob;
133  size_t il, ol;
134 
135  /* char_conv is only mostly const */
136  TDS_ERRNO_MESSAGE_FLAGS *suppress = (TDS_ERRNO_MESSAGE_FLAGS*) &char_conv->suppress;
137 
139 
140  il = len < 0 ? strlen(s) : (size_t) len;
141  if (char_conv->flags == TDS_ENCODING_MEMCPY) {
142  *out_len = il;
143  return s;
144  }
145 
146  /* allocate needed buffer (+1 is to exclude 0 case) */
147  ol = il * char_conv->to.charset.max_bytes_per_char / char_conv->from.charset.min_bytes_per_char + 1;
148  buf = tds_new(char, ol);
149  if (buf == NULL) {
150  *out_len = 0;
151  return NULL;
152  }
153 
154  ib = s;
155  ob = buf;
156  memset(suppress, 0, sizeof(char_conv->suppress));
157  if (tds_iconv(tds, char_conv, to_server, &ib, &il, &ob, &ol) == (size_t)-1) {
158  free(buf);
159  return NULL;
160  }
161  *out_len = ob - buf;
162  return buf;
163 }
164 
165 #if ENABLE_EXTRA_CHECKS
166 void
167 tds_convert_string_free(const char *original, const char *converted)
168 {
169  if (original != converted)
170  free((char *) converted);
171 }
172 #endif
173 
174 /**
175  * Flush query packet.
176  * Used at the end of packet write to really send packet to server.
177  * This also changes the state to TDS_PENDING.
178  * \tds
179  */
180 static TDSRET
182 {
183  TDSRET ret = tds_flush_packet(tds);
184  /* TODO depend on result ?? */
186  return ret;
187 }
188 
189 /**
190  * Set current dynamic.
191  * \tds
192  * \param dyn dynamic to set
193  */
194 void
196 {
197  if (dyn)
198  ++dyn->ref_count;
200  tds->cur_dyn = dyn;
201 }
202 
203 /**
204  * Sends a language string to the database server for
205  * processing. TDS 4.2 is a plain text message with a packet type of 0x01,
206  * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a
207  * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f.
208  * \tds
209  * \param query language query to submit
210  * \return TDS_FAIL or TDS_SUCCESS
211  */
212 TDSRET
214 {
216 }
217 
218 /**
219  * Substitute ?-style placeholders with named (\@param) ones.
220  * Sybase does not support ?-style placeholders so convert them.
221  * Also the function replace parameter names.
222  * \param query query string
223  * \param[in,out] query_len pointer to query length.
224  * On input length of input query, on output length
225  * of output query
226  * \param params parameters to send to server
227  * \returns new query or NULL on error
228  */
229 static char *
230 tds5_fix_dot_query(const char *query, size_t *query_len, TDSPARAMINFO * params)
231 {
232  int i;
233  size_t len, pos;
234  const char *e, *s;
235  size_t size = *query_len + 30;
236  char colname[32];
237  char *out;
238 
239  out = tds_new(char, size);
240  if (!out)
241  goto memory_error;
242  pos = 0;
243 
244  s = query;
245  for (i = 0;; ++i) {
246  e = tds_next_placeholder(s);
247  len = e ? e - s : strlen(s);
248  if (pos + len + 12 >= size) {
249  size = pos + len + 30;
250  if (!TDS_RESIZE(out, size))
251  goto memory_error;
252  }
253  memcpy(out + pos, s, len);
254  pos += len;
255  if (!e)
256  break;
257  pos += sprintf(out + pos, "@P%d", i + 1);
258  if (!params || i >= params->num_cols)
259  goto memory_error;
260  sprintf(colname, "@P%d", i + 1);
261  if (!tds_dstr_copy(&params->columns[i]->column_name, colname))
262  goto memory_error;
263 
264  s = e + 1;
265  }
266  out[pos] = 0;
267  *query_len = pos;
268  return out;
269 
270 memory_error:
271  free(out);
272  return NULL;
273 }
274 
275 /**
276  * Write data to wire
277  * \tds
278  * \param curcol column where store column information
279  * \return TDS_FAIL on error or TDS_SUCCESS
280  */
281 static inline TDSRET
283 {
284  return curcol->funcs->put_data(tds, curcol, 0);
285 }
286 
287 /**
288  * Start query packet of a given type
289  * \tds
290  * \param packet_type packet type
291  * \param head extra information to put in a TDS7 header
292  */
293 static TDSRET
294 tds_start_query_head(TDSSOCKET *tds, unsigned char packet_type, TDSHEADERS * head)
295 {
296  tds->out_flag = packet_type;
297  if (IS_TDS72_PLUS(tds->conn)) {
298  TDSFREEZE outer;
299 
300  tds_freeze(tds, &outer, 4); /* total length */
301  tds_put_int(tds, 18); /* length: transaction descriptor */
302  tds_put_smallint(tds, 2); /* type: transaction descriptor */
303  tds_put_n(tds, tds->conn->tds72_transaction, 8); /* transaction */
304  tds_put_int(tds, 1); /* request count */
305  if (head && head->qn_msgtext && head->qn_options) {
307 
308  tds_freeze(tds, &query, 4); /* length: query notification */
309  tds_put_smallint(tds, 1); /* type: query notification */
310 
312  tds_put_string(tds, head->qn_msgtext, -1); /* notifyid */
313  } TDS_END_LEN
314 
316  tds_put_string(tds, head->qn_options, -1); /* ssbdeployment */
317  } TDS_END_LEN
318 
319  if (head->qn_timeout != 0)
320  tds_put_int(tds, head->qn_timeout); /* timeout */
321 
323  }
324  tds_freeze_close_len(&outer, tds_freeze_written(&outer));
325  }
326  return TDS_SUCCESS;
327 }
328 
329 /**
330  * Start query packet of a given type
331  * \tds
332  * \param packet_type packet type
333  */
334 void
335 tds_start_query(TDSSOCKET *tds, unsigned char packet_type)
336 {
337  /* no need to check return value here because tds_start_query_head() cannot
338  fail when given a NULL head parameter */
339  tds_start_query_head(tds, packet_type, NULL);
340 }
341 
342 /**
343  * Sends a language string to the database server for
344  * processing. TDS 4.2 is a plain text message with a packet type of 0x01,
345  * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a
346  * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f.
347  * \tds
348  * \param query language query to submit
349  * \param params parameters of query
350  * \return TDS_FAIL or TDS_SUCCESS
351  */
352 TDSRET
354 {
355  size_t query_len;
356  int num_params = params ? params->num_cols : 0;
357 
359  if (params)
360  CHECK_PARAMINFO_EXTRA(params);
361 
362  if (!query)
363  return TDS_FAIL;
364 
366  return TDS_FAIL;
367 
368  query_len = strlen(query);
369 
370  if (IS_TDS50(tds->conn)) {
371  char *new_query = NULL;
372  /* are there '?' style parameters ? */
374  if ((new_query = tds5_fix_dot_query(query, &query_len, params)) == NULL) {
376  return TDS_FAIL;
377  }
378  query = new_query;
379  }
380 
384  tds_put_byte(tds, params ? 1 : 0); /* 1 if there are params, 0 otherwise */
385  tds_put_n(tds, query, query_len); /* tds_put_string */
386  } TDS_END_LEN
387  if (params) {
388  /* add on parameters */
391  }
392  free(new_query);
393  } else if (!IS_TDS7_PLUS(tds->conn) || !params || !params->num_cols) {
395  return TDS_FAIL;
396  tds_put_string(tds, query, (int)query_len);
397  } else {
398  TDSCOLUMN *param;
399  int count, i;
400  size_t converted_query_len;
401  const char *converted_query;
402  TDSFREEZE outer;
403  TDSRET rc;
404 
405  converted_query = tds_convert_string
407  query, query_len, &converted_query_len);
408  if (!converted_query) {
410  return TDS_FAIL;
411  }
412 
413  count = tds_count_placeholders_ucs2le(converted_query, converted_query + converted_query_len);
414 
416  tds_convert_string_free(query, converted_query);
417  return TDS_FAIL;
418  }
419 
420  tds_freeze(tds, &outer, 0);
421 
422  /* procedure name */
423  if (IS_TDS71_PLUS(tds->conn)) {
424  tds_put_smallint(tds, -1);
426  } else {
427  TDS_PUT_N_AS_UCS2(tds, "sp_executesql");
428  }
429  tds_put_smallint(tds, 0);
430 
431  /* string with sql statement */
432  if (!count) {
433  tds_put_byte(tds, 0);
434  tds_put_byte(tds, 0);
435  tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
436  TDS_PUT_INT(tds, converted_query_len);
437  if (IS_TDS71_PLUS(tds->conn))
438  tds_put_n(tds, tds->conn->collation, 5);
439  TDS_PUT_INT(tds, converted_query_len);
440  tds_put_n(tds, converted_query, converted_query_len);
441 
442  rc = tds7_write_param_def_from_params(tds, converted_query, converted_query_len, params);
443  } else {
444  tds7_put_query_params(tds, converted_query, converted_query_len);
445 
446  rc = tds7_write_param_def_from_query(tds, converted_query, converted_query_len, params);
447  }
448  tds_convert_string_free(query, converted_query);
449  if (TDS_FAILED(rc)) {
450  tds_freeze_abort(&outer);
451  return rc;
452  }
453  tds_freeze_close(&outer);
454 
455  for (i = 0; i < num_params; i++) {
456  param = params->columns[i];
457  TDS_PROPAGATE(tds_put_data_info(tds, param, 0));
458  TDS_PROPAGATE(tds_put_data(tds, param));
459  }
461  }
462  return tds_query_flush_packet(tds);
463 }
464 
465 /**
466  * Format and submit a query
467  * \tds
468  * \param queryf query format. printf like expansion is performed on
469  * this query.
470  */
471 TDSRET
472 tds_submit_queryf(TDSSOCKET * tds, const char *queryf, ...)
473 {
474  va_list ap;
475  char *query = NULL;
476  TDSRET rc = TDS_FAIL;
477 
479 
480  va_start(ap, queryf);
481  if (vasprintf(&query, queryf, ap) >= 0) {
482  rc = tds_submit_query(tds, query);
483  free(query);
484  }
485  va_end(ap);
486  return rc;
487 }
488 
489 /**
490  * Skip a comment in a query
491  * \param s start of the string (or part of it)
492  * \returns pointer to end of comment
493  */
494 const char *
495 tds_skip_comment(const char *s)
496 {
497  const char *p = s;
498 
499  if (*p == '-' && p[1] == '-') {
500  for (;*++p != '\0';)
501  if (*p == '\n')
502  return p + 1;
503  } else if (*p == '/' && p[1] == '*') {
504  ++p;
505  for(;*++p != '\0';)
506  if (*p == '*' && p[1] == '/')
507  return p + 2;
508  } else
509  ++p;
510 
511  return p;
512 }
513 
514 /**
515  * Skip quoting string (like 'sfsf', "dflkdj" or [dfkjd])
516  * \param s pointer to first quoting character. @verbatim Should be ', " or [. @endverbatim
517  * \return character after quoting
518  */
519 const char *
520 tds_skip_quoted(const char *s)
521 {
522  const char *p = s;
523  char quote = (*s == '[') ? ']' : *s;
524 
525  for (; *++p;) {
526  if (*p == quote) {
527  if (*++p != quote)
528  return p;
529  }
530  }
531  return p;
532 }
533 
534 /**
535  * Get position of next placeholder
536  * \param start pointer to part of query to search
537  * \return next placeholder or NULL if not found
538  */
539 const char *
540 tds_next_placeholder(const char *start)
541 {
542  const char *p = start;
543 
544  if (!p)
545  return NULL;
546 
547  for (;;) {
548  switch (*p) {
549  case '\0':
550  return NULL;
551  case '\'':
552  case '\"':
553  case '[':
554  p = tds_skip_quoted(p);
555  break;
556 
557  case '-':
558  case '/':
559  p = tds_skip_comment(p);
560  break;
561 
562  case '?':
563  return p;
564  default:
565  ++p;
566  break;
567  }
568  }
569 }
570 
571 /**
572  * Count the number of placeholders ('?') in a query
573  * \param query query string
574  */
575 int
577 {
578  const char *p = query - 1;
579  int count = 0;
580 
581  for (;; ++count) {
582  if (!(p = tds_next_placeholder(p + 1)))
583  return count;
584  }
585 }
586 
587 /**
588  * Skip a comment in a query
589  * \param s start of the string (or part of it). Encoded in ucs2le
590  * \param end end of string
591  * \returns pointer to end of comment
592  */
593 static const char *
594 tds_skip_comment_ucs2le(const char *s, const char *end)
595 {
596  const char *p = s;
597 
598  if (p+4 <= end && memcmp(p, "-\0-", 4) == 0) {
599  for (;(p+=2) < end;)
600  if (p[0] == '\n' && p[1] == 0)
601  return p + 2;
602  } else if (p+4 <= end && memcmp(p, "/\0*", 4) == 0) {
603  p += 2;
604  end -= 2;
605  for(;(p+=2) < end;)
606  if (memcmp(p, "*\0/", 4) == 0)
607  return p + 4;
608  return end + 2;
609  } else
610  p += 2;
611 
612  return p;
613 }
614 
615 
616 /**
617  * Return pointer to end of a quoted string.
618  * At the beginning pointer should point to delimiter.
619  * \param s start of string to skip encoded in ucs2le
620  * \param end pointer to end of string
621  */
622 static const char *
623 tds_skip_quoted_ucs2le(const char *s, const char *end)
624 {
625  const char *p = s;
626  char quote = (*s == '[') ? ']' : *s;
627 
628  assert(s[1] == 0 && s < end && (end - s) % 2 == 0);
629 
630  for (; (p += 2) != end;) {
631  if (p[0] == quote && !p[1]) {
632  p += 2;
633  if (p == end || p[0] != quote || p[1])
634  return p;
635  }
636  }
637  return p;
638 }
639 
640 /**
641  * Found the next placeholder (? or \@param) in a string.
642  * String must be encoded in ucs2le.
643  * \param start start of the string (or part of it)
644  * \param end end of string
645  * \param named true if named parameters should be returned
646  * \returns either start of next placeholder or end if not found
647  */
648 static const char *
649 tds_next_placeholder_ucs2le(const char *start, const char *end, int named)
650 {
651  const char *p = start;
652  char prev = ' ', c;
653 
654  assert(p && start <= end && (end - start) % 2 == 0);
655 
656  for (; p != end;) {
657  if (p[1]) {
658  prev = ' ';
659  p += 2;
660  continue;
661  }
662  c = p[0];
663  switch (c) {
664  case '\'':
665  case '\"':
666  case '[':
667  p = tds_skip_quoted_ucs2le(p, end);
668  break;
669 
670  case '-':
671  case '/':
672  p = tds_skip_comment_ucs2le(p, end);
673  c = ' ';
674  break;
675 
676  case '?':
677  return p;
678  case '@':
679  if (named && !isalnum((unsigned char) prev))
680  return p;
681  default:
682  p += 2;
683  break;
684  }
685  prev = c;
686  }
687  return end;
688 }
689 
690 /**
691  * Count the number of placeholders ('?') in a query
692  * \param query query encoded in ucs2le
693  * \param query_end end of query
694  * \return number of placeholders found
695  */
696 static int
697 tds_count_placeholders_ucs2le(const char *query, const char *query_end)
698 {
699  const char *p = query - 2;
700  int count = 0;
701 
702  for (;; ++count) {
703  if ((p = tds_next_placeholder_ucs2le(p + 2, query_end, 0)) == query_end)
704  return count;
705  }
706 }
707 
708 static const char*
710 {
711  switch (usertype) {
712  case USER_CHAR_TYPE:
713  return "CHAR(%u)";
714  case USER_VARCHAR_TYPE:
715  return "VARCHAR(%u)";
716  case USER_SYSNAME_TYPE:
717  return "SYSNAME";
718  case USER_NCHAR_TYPE:
719  *p_size /= tds->conn->ncharsize;
720  return "NCHAR(%u)";
721  case USER_NVARCHAR_TYPE:
722  *p_size /= tds->conn->ncharsize;
723  return "NVARCHAR(%u)";
724  }
725  return NULL;
726 }
727 
728 /**
729  * Return declaration for column (like "varchar(20)").
730  *
731  * This depends on:
732  * - on_server.column_type
733  * - varint_size (for varchar(max) distinction)
734  * - column_size
735  * - precision/scale (numeric)
736  *
737  * \tds
738  * \param curcol column
739  * \param out buffer to hold declaration
740  * \return TDS_FAIL or TDS_SUCCESS
741  */
742 TDSRET
744 {
745  const char *fmt = NULL;
746  /* unsigned int is required by printf format, don't use size_t */
747  unsigned int max_len = IS_TDS7_PLUS(tds->conn) ? 8000 : 255;
748  unsigned int size;
749 
751  CHECK_COLUMN_EXTRA(curcol);
752 
753  size = (unsigned int) tds_fix_column_size(tds, curcol);
754 
756  case XSYBCHAR:
757  if (IS_TDS50(tds->conn)) {
758  max_len = 32767;
760  if (fmt != NULL)
761  break;
762  }
763  case SYBCHAR:
764  fmt = "CHAR(%u)";
765  break;
766  case SYBVARCHAR:
767  if (IS_TDS50(tds->conn)) {
769  if (fmt != NULL)
770  break;
771  }
772  case XSYBVARCHAR:
773  if (curcol->column_varint_size == 8)
774  fmt = "VARCHAR(MAX)";
775  else
776  fmt = "VARCHAR(%u)";
777  break;
778  case SYBUINT1:
779  case SYBINT1:
780  fmt = "TINYINT";
781  break;
782  case SYBINT2:
783  fmt = "SMALLINT";
784  break;
785  case SYBINT4:
786  fmt = "INT";
787  break;
788  case SYBINT8:
789  /* TODO even for Sybase ?? */
790  fmt = "BIGINT";
791  break;
792  case SYBFLT8:
793  fmt = "FLOAT";
794  break;
795  case SYBDATETIME:
796  fmt = "DATETIME";
797  break;
798  case SYBDATE:
799  fmt = "DATE";
800  break;
801  case SYBTIME:
802  fmt = "TIME";
803  break;
804  case SYBBIT:
805  fmt = "BIT";
806  break;
807  case SYBTEXT:
808  fmt = "TEXT";
809  break;
810  case SYBLONGBINARY: /* TODO correct ?? */
811  case SYBIMAGE:
812  if (IS_TDS50(tds->conn)) {
813  switch (curcol->column_usertype) {
814  case USER_UNICHAR_TYPE:
815  size /= 2u;
816  max_len = 8192;
817  fmt = "UNICHAR(%u)";
818  break;
820  size /= 2u;
821  max_len = 8192;
822  fmt = "UNIVARCHAR(%u)";
823  break;
824  case USER_UNITEXT_TYPE:
825  fmt = "UNITEXT";
826  break;
827  }
828  if (fmt != NULL)
829  break;
830  }
831  fmt = "IMAGE";
832  break;
833  case SYBMONEY4:
834  fmt = "SMALLMONEY";
835  break;
836  case SYBMONEY:
837  fmt = "MONEY";
838  break;
839  case SYBDATETIME4:
840  fmt = "SMALLDATETIME";
841  break;
842  case SYBREAL:
843  fmt = "REAL";
844  break;
845  case SYBBINARY:
846  case XSYBBINARY:
847  fmt = "BINARY(%u)";
848  break;
849  case SYBVARBINARY:
850  case XSYBVARBINARY:
851  if (curcol->column_varint_size == 8)
852  fmt = "VARBINARY(MAX)";
853  else
854  fmt = "VARBINARY(%u)";
855  break;
856  case SYBNUMERIC:
857  fmt = "NUMERIC(%d,%d)";
858  goto numeric_decimal;
859  case SYBDECIMAL:
860  fmt = "DECIMAL(%d,%d)";
861  numeric_decimal:
862  sprintf(out, fmt, curcol->column_prec, curcol->column_scale);
863  return TDS_SUCCESS;
864  break;
865  case SYBUNIQUE:
866  if (IS_TDS7_PLUS(tds->conn))
867  fmt = "UNIQUEIDENTIFIER";
868  break;
869  case SYBNTEXT:
870  if (IS_TDS7_PLUS(tds->conn))
871  fmt = "NTEXT";
872  break;
873  case SYBNVARCHAR:
874  case XSYBNVARCHAR:
875  if (curcol->column_varint_size == 8) {
876  fmt = "NVARCHAR(MAX)";
877  } else if (IS_TDS7_PLUS(tds->conn)) {
878  fmt = "NVARCHAR(%u)";
879  max_len = 4000;
880  size /= 2u;
881  }
882  break;
883  case XSYBNCHAR:
884  if (IS_TDS7_PLUS(tds->conn)) {
885  fmt = "NCHAR(%u)";
886  max_len = 4000;
887  size /= 2u;
888  }
889  break;
890  case SYBVARIANT:
891  if (IS_TDS7_PLUS(tds->conn))
892  fmt = "SQL_VARIANT";
893  break;
894  /* TODO support scale !! */
895  case SYBMSTIME:
896  fmt = "TIME";
897  break;
898  case SYBMSDATE:
899  fmt = "DATE";
900  break;
901  case SYBMSDATETIME2:
902  fmt = "DATETIME2";
903  break;
904  case SYBMSDATETIMEOFFSET:
905  fmt = "DATETIMEOFFSET";
906  break;
907  case SYB5BIGTIME:
908  fmt = "BIGTIME";
909  break;
910  case SYB5BIGDATETIME:
911  fmt = "BIGDATETIME";
912  break;
913  case SYBUINT2:
914  fmt = "UNSIGNED SMALLINT";
915  break;
916  case SYBUINT4:
917  fmt = "UNSIGNED INT";
918  break;
919  case SYBUINT8:
920  fmt = "UNSIGNED BIGINT";
921  break;
922  /* nullable types should not occur here... */
923  case SYBFLTN:
924  case SYBMONEYN:
925  case SYBDATETIMN:
926  case SYBBITN:
927  case SYBINTN:
928  assert(0);
929  /* TODO... */
930  case SYBVOID:
931  case SYBSINT1:
932  default:
934  break;
935  }
936 
937  if (fmt) {
938  /* fill out */
939  sprintf(out, fmt, size > 0 ? MIN(size, max_len) : 1u);
940  return TDS_SUCCESS;
941  }
942 
943  out[0] = 0;
944  return TDS_FAIL;
945 }
946 
947 /**
948  * Write string with parameters definition, useful for TDS7+.
949  * Looks like "@P1 INT, @P2 VARCHAR(100)"
950  * \param tds state information for the socket and the TDS protocol
951  * \param converted_query query to send to server in ucs2le encoding
952  * \param converted_query_len query length in bytes
953  * \param params parameters to build declaration
954  * \return result of write
955  */
956 /* TODO find a better name for this function */
957 static TDSRET
958 tds7_write_param_def_from_query(TDSSOCKET * tds, const char* converted_query, size_t converted_query_len, TDSPARAMINFO * params)
959 {
960  char declaration[128], *p;
961  int i, count;
962  unsigned int written;
963  TDSFREEZE outer, inner;
964 
966 
968  if (params)
969  CHECK_PARAMINFO_EXTRA(params);
970 
971  count = tds_count_placeholders_ucs2le(converted_query, converted_query + converted_query_len);
972 
973  /* string with parameters types */
974  tds_put_byte(tds, 0);
975  tds_put_byte(tds, 0);
976  tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
977 
978  /* put parameters definitions */
979  tds_freeze(tds, &outer, 4);
980  if (IS_TDS71_PLUS(tds->conn))
981  tds_put_n(tds, tds->conn->collation, 5);
982  tds_freeze(tds, &inner, 4);
983 
984  for (i = 0; i < count; ++i) {
985  p = declaration;
986  if (i)
987  *p++ = ',';
988 
989  /* get this parameter declaration */
990  p += sprintf(p, "@P%d ", i+1);
991  if (!params || i >= params->num_cols) {
992  strcpy(p, "varchar(4000)");
993  } else if (TDS_FAILED(tds_get_column_declaration(tds, params->columns[i], p))) {
994  tds_freeze_abort(&inner);
995  tds_freeze_abort(&outer);
996  return TDS_FAIL;
997  }
998 
999  tds_put_string(tds, declaration, -1);
1000  }
1001 
1002  written = tds_freeze_written(&inner) - 4;
1003  tds_freeze_close_len(&inner, written ? written : -1);
1004  tds_freeze_close_len(&outer, written);
1005  return TDS_SUCCESS;
1006 }
1007 
1008 /**
1009  * Write string with parameters definition, useful for TDS7+.
1010  * Looks like "@P1 INT, @P2 VARCHAR(100)"
1011  * \param tds state information for the socket and the TDS protocol
1012  * \param query query to send to server encoded in ucs2le
1013  * \param query_len query length in bytes
1014  * \param params parameters to build declaration
1015  * \return result of the operation
1016  */
1017 /* TODO find a better name for this function */
1018 static TDSRET
1019 tds7_write_param_def_from_params(TDSSOCKET * tds, const char* query, size_t query_len, TDSPARAMINFO * params)
1020 {
1021  char declaration[40];
1022  int i;
1023  struct tds_ids {
1024  const char *p;
1025  size_t len;
1026  } *ids = NULL;
1027  TDSFREEZE outer, inner;
1028  unsigned int written;
1029 
1031 
1033  if (params)
1034  CHECK_PARAMINFO_EXTRA(params);
1035 
1036  /* string with parameters types */
1037  tds_put_byte(tds, 0);
1038  tds_put_byte(tds, 0);
1039  tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
1040 
1041  /* put parameters definitions */
1042  tds_freeze(tds, &outer, 4);
1043  if (IS_TDS71_PLUS(tds->conn))
1044  tds_put_n(tds, tds->conn->collation, 5);
1045  tds_freeze(tds, &inner, 4);
1046 
1047  if (!params || !params->num_cols) {
1048  tds_freeze_close_len(&inner, -1);
1049  tds_freeze_close_len(&outer, 0);
1050  return TDS_SUCCESS;
1051  }
1052 
1053  /* try to detect missing names */
1054  ids = tds_new0(struct tds_ids, params->num_cols);
1055  if (!ids)
1056  goto Cleanup;
1057  if (tds_dstr_isempty(&params->columns[0]->column_name)) {
1058  const char *s = query, *e, *id_end;
1059  const char *query_end = query + query_len;
1060 
1061  for (i = 0; i < params->num_cols; s = e + 2) {
1062  e = tds_next_placeholder_ucs2le(s, query_end, 1);
1063  if (e == query_end)
1064  break;
1065  if (e[0] != '@')
1066  continue;
1067  /* find end of param name */
1068  for (id_end = e + 2; id_end != query_end; id_end += 2)
1069  if (!id_end[1] && (id_end[0] != '_' && id_end[1] != '#' && !isalnum((unsigned char) id_end[0])))
1070  break;
1071  ids[i].p = e;
1072  ids[i].len = id_end - e;
1073  ++i;
1074  }
1075  }
1076 
1077  for (i = 0; i < params->num_cols; ++i) {
1078  if (i)
1079  tds_put_smallint(tds, ',');
1080 
1081  /* this part of buffer can be not-ascii compatible, use all ucs2... */
1082  if (ids[i].p) {
1083  tds_put_n(tds, ids[i].p, ids[i].len);
1084  } else {
1085  const DSTR *name = &params->columns[i]->column_name;
1087  (int) tds_dstr_len(name));
1088  }
1089  tds_put_smallint(tds, ' ');
1090 
1091  /* get this parameter declaration */
1092  tds_get_column_declaration(tds, params->columns[i], declaration);
1093  if (!declaration[0])
1094  goto Cleanup;
1095  tds_put_string(tds, declaration, -1);
1096  }
1097  free(ids);
1098 
1099  written = tds_freeze_written(&inner) - 4;
1100  tds_freeze_close_len(&inner, written);
1101  tds_freeze_close_len(&outer, written);
1102 
1103  return TDS_SUCCESS;
1104 
1105  Cleanup:
1106  free(ids);
1107  tds_freeze_abort(&inner);
1108  tds_freeze_abort(&outer);
1109  return TDS_FAIL;
1110 }
1111 
1112 
1113 /**
1114  * Output params types and query (required by sp_prepare/sp_executesql/sp_prepexec)
1115  * \param tds state information for the socket and the TDS protocol
1116  * \param query query (encoded in ucs2le)
1117  * \param query_len query length in bytes
1118  */
1119 static void
1120 tds7_put_query_params(TDSSOCKET * tds, const char *query, size_t query_len)
1121 {
1122  size_t len;
1123  int i, num_placeholders;
1124  const char *s, *e;
1125  char buf[24];
1126  const char *const query_end = query + query_len;
1127 
1129 
1131 
1132  /* we use all "@PX" for parameters */
1133  num_placeholders = tds_count_placeholders_ucs2le(query, query_end);
1134  len = num_placeholders * 2;
1135  /* adjust for the length of X */
1136  for (i = 10; i <= num_placeholders; i *= 10) {
1137  len += num_placeholders - i + 1;
1138  }
1139 
1140  /* string with sql statement */
1141  /* replace placeholders with dummy parametes */
1142  tds_put_byte(tds, 0);
1143  tds_put_byte(tds, 0);
1144  tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
1145  len = 2u * len + query_len;
1146  TDS_PUT_INT(tds, len);
1147  if (IS_TDS71_PLUS(tds->conn))
1148  tds_put_n(tds, tds->conn->collation, 5);
1149  TDS_PUT_INT(tds, len);
1150  s = query;
1151  /* TODO do a test with "...?" and "...?)" */
1152  for (i = 1;; ++i) {
1153  e = tds_next_placeholder_ucs2le(s, query_end, 0);
1154  assert(e && query <= e && e <= query_end);
1155  tds_put_n(tds, s, e - s);
1156  if (e == query_end)
1157  break;
1158  sprintf(buf, "@P%d", i);
1159  tds_put_string(tds, buf, -1);
1160  s = e + 2;
1161  }
1162 }
1163 
1164 /**
1165  * Creates a temporary stored procedure in the server.
1166  *
1167  * Under TDS 4.2 dynamic statements are emulated building sql command.
1168  * TDS 5 does not uses parameters type.
1169  * TDS 7+ uses parameter types to prepare the query. You should
1170  * prepare again the query if parameters changes.
1171  * \param tds state information for the socket and the TDS protocol
1172  * \param query language query with given placeholders (?)
1173  * \param id string to identify the dynamic query. Pass NULL for automatic generation.
1174  * \param dyn_out will receive allocated TDSDYNAMIC*. Any older allocated dynamic won't be freed, Can be NULL.
1175  * \param params parameters to use. It can be NULL even if parameters are present. Used only for TDS7+
1176  * \return TDS_FAIL or TDS_SUCCESS
1177  */
1178 /* TODO parse all results ?? */
1179 TDSRET
1180 tds_submit_prepare(TDSSOCKET * tds, const char *query, const char *id, TDSDYNAMIC ** dyn_out, TDSPARAMINFO * params)
1181 {
1182  int query_len;
1183  TDSRET rc = TDS_FAIL;
1184  TDSDYNAMIC *dyn;
1185 
1187  if (params)
1188  CHECK_PARAMINFO_EXTRA(params);
1189 
1190  if (!query || !dyn_out)
1191  return TDS_FAIL;
1192 
1194  return TDS_FAIL;
1195 
1196  /* allocate a structure for this thing */
1197  dyn = tds_alloc_dynamic(tds->conn, id);
1198  if (!dyn)
1199  return TDS_FAIL;
1200  tds_release_dynamic(dyn_out);
1201  *dyn_out = dyn;
1203 
1204  /* TDS5 sometimes cannot accept prepare so we need to store query */
1205  if (!IS_TDS7_PLUS(tds->conn)) {
1206  dyn->query = strdup(query);
1207  if (!dyn->query)
1208  goto failure;
1209  }
1210 
1211  if (!IS_TDS50(tds->conn) && !IS_TDS7_PLUS(tds->conn)) {
1212  dyn->emulated = 1;
1215  return TDS_SUCCESS;
1216  }
1217 
1218  query_len = (int)strlen(query);
1219 
1220  tds_set_cur_dyn(tds, dyn);
1221 
1222  if (IS_TDS7_PLUS(tds->conn)) {
1223  size_t converted_query_len;
1224  const char *converted_query;
1225  TDSFREEZE outer;
1226  TDSRET rc;
1227 
1228  converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, query_len, &converted_query_len);
1229  if (!converted_query)
1230  goto failure;
1231 
1232  tds_freeze(tds, &outer, 0);
1234  /* procedure name */
1235  if (IS_TDS71_PLUS(tds->conn)) {
1236  tds_put_smallint(tds, -1);
1238  } else {
1239  TDS_PUT_N_AS_UCS2(tds, "sp_prepare");
1240  }
1241  tds_put_smallint(tds, 0);
1242 
1243  /* return param handle (int) */
1244  tds_put_byte(tds, 0);
1245  tds_put_byte(tds, 1); /* result */
1247  tds_put_byte(tds, 4);
1248  tds_put_byte(tds, 0);
1249 
1250  rc = tds7_write_param_def_from_query(tds, converted_query, converted_query_len, params);
1251  tds7_put_query_params(tds, converted_query, converted_query_len);
1252  tds_convert_string_free(query, converted_query);
1253  if (TDS_FAILED(rc)) {
1254  tds_freeze_abort(&outer);
1255  return rc;
1256  }
1257  tds_freeze_close(&outer);
1258 
1259  /* options, 1 == RETURN_METADATA */
1260  tds_put_byte(tds, 0);
1261  tds_put_byte(tds, 0);
1263  tds_put_byte(tds, 4);
1264  tds_put_byte(tds, 4);
1265  tds_put_int(tds, 1);
1266 
1268  } else {
1269  tds->out_flag = TDS_NORMAL;
1270 
1274  tds_put_byte(tds, 0x00);
1276  tds_put_string(tds, dyn->id, -1);
1277  } TDS_END_LEN
1278 
1279  /* TODO how to pass parameters type? like store procedures ? */
1282  tds_put_n(tds, "create proc ", 12);
1283  tds_put_string(tds, dyn->id, -1);
1284  tds_put_n(tds, " as ", 4);
1285  }
1286  tds_put_string(tds, query, query_len);
1287  } TDS_END_LEN
1288  } TDS_END_LEN
1289  }
1290 
1292  if (TDS_SUCCEED(rc))
1293  return rc;
1294 
1295 failure:
1296  /* TODO correct if writing fail ?? */
1298 
1299  tds_release_dynamic(dyn_out);
1301  return rc;
1302 }
1303 
1304 /**
1305  * Submit a prepared query with parameters
1306  * \param tds state information for the socket and the TDS protocol
1307  * \param query language query with given placeholders (?)
1308  * \param params parameters to send
1309  * \return TDS_FAIL or TDS_SUCCESS
1310  */
1311 TDSRET
1313 {
1314  size_t query_len;
1315  TDSCOLUMN *param;
1316  TDSDYNAMIC *dyn;
1317  unsigned int id_len;
1318  TDSFREEZE outer;
1319 
1321  CHECK_PARAMINFO_EXTRA(params);
1322 
1323  if (!query)
1324  return TDS_FAIL;
1325  query_len = strlen(query);
1326 
1327  if (IS_TDS7_PLUS(tds->conn)) {
1328  int i;
1329  size_t converted_query_len;
1330  const char *converted_query;
1331  TDSRET rc;
1332 
1334  return TDS_FAIL;
1335 
1336  converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, (int)query_len, &converted_query_len);
1337  if (!converted_query) {
1339  return TDS_FAIL;
1340  }
1341 
1343  tds_convert_string_free(query, converted_query);
1344  return TDS_FAIL;
1345  }
1346  tds_freeze(tds, &outer, 0);
1347  /* procedure name */
1348  if (IS_TDS71_PLUS(tds->conn)) {
1349  tds_put_smallint(tds, -1);
1351  } else {
1352  TDS_PUT_N_AS_UCS2(tds, "sp_executesql");
1353  }
1354  tds_put_smallint(tds, 0);
1355 
1356  tds7_put_query_params(tds, converted_query, converted_query_len);
1357  rc = tds7_write_param_def_from_query(tds, converted_query, converted_query_len, params);
1358  tds_convert_string_free(query, converted_query);
1359  if (TDS_FAILED(rc)) {
1360  tds_freeze_abort(&outer);
1361  return rc;
1362  }
1363  tds_freeze_close(&outer);
1364 
1365  for (i = 0; i < params->num_cols; i++) {
1366  param = params->columns[i];
1367  TDS_PROPAGATE(tds_put_data_info(tds, param, 0));
1368  TDS_PROPAGATE(tds_put_data(tds, param));
1369  }
1370 
1372  return tds_query_flush_packet(tds);
1373  }
1374 
1375  /* allocate a structure for this thing */
1376  dyn = tds_alloc_dynamic(tds->conn, NULL);
1377 
1378  if (!dyn)
1379  return TDS_FAIL;
1380  /* check if no parameters */
1381  if (params && !params->num_cols)
1382  params = NULL;
1383 
1384  /* TDS 4.2, emulate prepared statements */
1385  /*
1386  * TODO Sybase seems to not support parameters in prepared execdirect
1387  * so use language or prepare and then exec
1388  */
1389  if (!IS_TDS50(tds->conn) || params) {
1390  TDSRET ret = TDS_SUCCESS;
1391 
1392  if (!params) {
1393  ret = tds_submit_query(tds, query);
1394  } else {
1395  dyn->emulated = 1;
1396  dyn->params = params;
1397  dyn->query = strdup(query);
1398  if (!dyn->query)
1399  ret = TDS_FAIL;
1400  if (TDS_SUCCEED(ret))
1402  ret = TDS_FAIL;
1403  if (TDS_SUCCEED(ret)) {
1404  ret = tds_send_emulated_execute(tds, dyn->query, dyn->params);
1405  if (TDS_SUCCEED(ret))
1406  ret = tds_query_flush_packet(tds);
1407  }
1408  /* do not free our parameters */
1409  dyn->params = NULL;
1410  }
1412  tds_release_dynamic(&dyn);
1413  return ret;
1414  }
1415 
1417  tds->cur_dyn = dyn;
1418 
1420  return TDS_FAIL;
1421 
1422  tds->out_flag = TDS_NORMAL;
1423 
1424  id_len = (unsigned int) strlen(dyn->id);
1426  tds_freeze(tds, &outer, 2);
1428  tds_put_byte(tds, params ? 0x01 : 0);
1430  tds_put_string(tds, dyn->id, id_len);
1431  } TDS_END_LEN
1432  /* TODO how to pass parameters type? like store procedures ? */
1434  tds_put_n(tds, "create proc ", 12);
1435  tds_put_string(tds, dyn->id, id_len);
1436  tds_put_n(tds, " as ", 4);
1437  tds_put_string(tds, query, query_len);
1438  } TDS_END_LEN
1439  tds_freeze_close(&outer);
1440 
1441  if (params)
1442  TDS_PROPAGATE(tds5_put_params(tds, params, 0));
1443 
1444  return tds_flush_packet(tds);
1445 }
1446 
1447 /**
1448  * Creates a temporary stored procedure in the server and execute it.
1449  * \param tds state information for the socket and the TDS protocol
1450  * \param query language query with given placeholders ('?')
1451  * \param id string to identify the dynamic query. Pass NULL for automatic generation.
1452  * \param dyn_out will receive allocated TDSDYNAMIC*. Any older allocated dynamic won't be freed. Can be NULL.
1453  * \param params parameters to use. It can be NULL even if parameters are present.
1454  * \return TDS_FAIL or TDS_SUCCESS
1455  */
1456 TDSRET
1457 tds71_submit_prepexec(TDSSOCKET * tds, const char *query, const char *id, TDSDYNAMIC ** dyn_out, TDSPARAMINFO * params)
1458 {
1459  int query_len;
1460  TDSRET rc = TDS_FAIL;
1461  TDSDYNAMIC *dyn;
1462  size_t converted_query_len;
1463  const char *converted_query;
1464  TDSFREEZE outer;
1465 
1467  if (params)
1468  CHECK_PARAMINFO_EXTRA(params);
1469 
1470  if (!query || !dyn_out || !IS_TDS7_PLUS(tds->conn))
1471  return TDS_FAIL;
1472 
1474  return TDS_FAIL;
1475 
1476  /* allocate a structure for this thing */
1477  dyn = tds_alloc_dynamic(tds->conn, id);
1478  if (!dyn)
1479  return TDS_FAIL;
1480  tds_release_dynamic(dyn_out);
1481  *dyn_out = dyn;
1482 
1483  tds_set_cur_dyn(tds, dyn);
1484 
1485  query_len = (int)strlen(query);
1486 
1487  converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, query_len, &converted_query_len);
1488  if (!converted_query)
1489  goto failure;
1490 
1491  tds_freeze(tds, &outer, 0);
1493  /* procedure name */
1494  if (IS_TDS71_PLUS(tds->conn)) {
1495  tds_put_smallint(tds, -1);
1497  } else {
1498  TDS_PUT_N_AS_UCS2(tds, "sp_prepexec");
1499  }
1500  tds_put_smallint(tds, 0);
1501 
1502  /* return param handle (int) */
1503  tds_put_byte(tds, 0);
1504  tds_put_byte(tds, 1); /* result */
1506  tds_put_byte(tds, 4);
1507  tds_put_byte(tds, 0);
1508 
1509  rc = tds7_write_param_def_from_query(tds, converted_query, converted_query_len, params);
1510  tds7_put_query_params(tds, converted_query, converted_query_len);
1511  tds_convert_string_free(query, converted_query);
1512  if (TDS_FAILED(rc)) {
1513  tds_freeze_abort(&outer);
1514  return rc;
1515  }
1516  tds_freeze_close(&outer);
1517 
1518  if (params) {
1519  int i;
1520 
1521  for (i = 0; i < params->num_cols; i++) {
1522  TDSCOLUMN *param = params->columns[i];
1523  TDS_PROPAGATE(tds_put_data_info(tds, param, 0));
1524  TDS_PROPAGATE(tds_put_data(tds, param));
1525  }
1526  }
1527 
1529 
1531  if (TDS_SUCCEED(rc))
1532  return rc;
1533 
1534 failure:
1535  /* TODO correct if writing fail ?? */
1537 
1538  tds_release_dynamic(dyn_out);
1540  return rc;
1541 }
1542 
1543 /**
1544  * Get column size for wire
1545  */
1546 size_t
1548 {
1549  size_t size = curcol->on_server.column_size, min;
1550 
1551  if (!size) {
1552  size = curcol->column_size;
1553  if (is_unicode_type(curcol->on_server.column_type))
1554  size *= 2u;
1555  }
1556 
1557  switch (curcol->column_varint_size) {
1558  case 1:
1559  size = MAX(MIN(size, 255), 1);
1560  break;
1561  case 2:
1562  /* note that varchar(max)/varbinary(max) have a varint of 8 */
1563  if (size == 0 && curcol->column_output) {
1564  min = 8000;
1565  } else if (curcol->on_server.column_type == XSYBNVARCHAR
1566  || curcol->on_server.column_type == XSYBNCHAR) {
1567  min = 2;
1568  } else {
1569  min = 1;
1570  }
1571  size = MAX(MIN(size, 8000u), min);
1572  break;
1573  case 4:
1574  if (curcol->on_server.column_type == SYBNTEXT)
1575  size = 0x7ffffffeu;
1576  else
1577  size = 0x7fffffffu;
1578  break;
1579  default:
1580  break;
1581  }
1582  return size;
1583 }
1584 
1585 /**
1586  * Put data information to wire
1587  * \param tds state information for the socket and the TDS protocol
1588  * \param curcol column where to store information
1589  * \param flags bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information)
1590  * \return TDS_SUCCESS or TDS_FAIL
1591  */
1592 static TDSRET
1594 {
1595  int len;
1596 
1598  CHECK_COLUMN_EXTRA(curcol);
1599 
1600  if (flags & TDS_PUT_DATA_USE_NAME) {
1601  len = (int) tds_dstr_len(&curcol->column_name);
1602  tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting param_name \n");
1603 
1604  if (IS_TDS7_PLUS(tds->conn)) {
1605  TDSFREEZE outer;
1606  unsigned int written;
1607 
1608  tds_freeze(tds, &outer, 1);
1609  if ((flags & TDS_PUT_DATA_PREFIX_NAME) != 0)
1610  tds_put_smallint(tds, '@');
1612  written = (tds_freeze_written(&outer) - 1) / 2;
1613  tds_freeze_close_len(&outer, written);
1614  } else {
1615  TDS_START_LEN_TINYINT(tds) { /* param name len */
1617  } TDS_END_LEN
1618  }
1619  } else {
1620  tds_put_byte(tds, 0x00); /* param name len */
1621  }
1622  /*
1623  * TODO support other flags (use defaul null/no metadata)
1624  * bit 1 (2 as flag) in TDS7+ is "default value" bit
1625  * (what's the meaning of "default value" ?)
1626  */
1627 
1628  tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting status \n");
1630  tds_put_int(tds, curcol->column_output); /* status (input) */
1631  else
1632  tds_put_byte(tds, curcol->column_output); /* status (input) */
1633  if (!IS_TDS7_PLUS(tds->conn))
1634  tds_put_int(tds, curcol->column_usertype); /* usertype */
1635  tds_put_byte(tds, (unsigned char) curcol->on_server.column_type);
1636 
1637  if (curcol->funcs->put_info(tds, curcol) != TDS_SUCCESS)
1638  return TDS_FAIL;
1639 
1640  /* TODO needed in TDS4.2 ?? now is called only if TDS >= 5 */
1641  if (!IS_TDS7_PLUS(tds->conn))
1642  tds_put_byte(tds, 0x00); /* locale info length */
1643 
1644  return TDS_SUCCESS;
1645 }
1646 
1647 /**
1648  * Send dynamic request on TDS 7+ to be executed
1649  * \tds
1650  * \param dyn dynamic query to execute
1651  */
1652 static TDSRET
1654 {
1655  TDSCOLUMN *param;
1656  TDSPARAMINFO *info;
1657  int i;
1658 
1659  /* procedure name */
1660  /* NOTE do not call this procedure using integer name (TDS_SP_EXECUTE) on mssql2k, it doesn't work! */
1661  TDS_PUT_N_AS_UCS2(tds, "sp_execute");
1662  tds_put_smallint(tds, 0); /* flags */
1663 
1664  /* id of prepared statement */
1665  tds_put_byte(tds, 0);
1666  tds_put_byte(tds, 0);
1668  tds_put_byte(tds, 4);
1669  tds_put_byte(tds, 4);
1670  tds_put_int(tds, dyn->num_id);
1671 
1672  info = dyn->params;
1673  if (info)
1674  for (i = 0; i < info->num_cols; i++) {
1675  param = info->columns[i];
1676  TDS_PROPAGATE(tds_put_data_info(tds, param, 0));
1677  TDS_PROPAGATE(tds_put_data(tds, param));
1678  }
1679 
1681  return TDS_SUCCESS;
1682 }
1683 
1684 /**
1685  * Sends a previously prepared dynamic statement to the server.
1686  * \param tds state information for the socket and the TDS protocol
1687  * \param dyn dynamic proc to execute. Must build from same tds.
1688  */
1689 TDSRET
1691 {
1693  /* TODO this dynamic should be in tds */
1694  CHECK_DYNAMIC_EXTRA(dyn);
1695 
1696  tdsdump_log(TDS_DBG_FUNC, "tds_submit_execute()\n");
1697 
1699  return TDS_FAIL;
1700 
1701  tds_set_cur_dyn(tds, dyn);
1702 
1703  if (IS_TDS7_PLUS(tds->conn)) {
1704  /* check proper id */
1705  if (dyn->num_id == 0) {
1707  return TDS_FAIL;
1708  }
1709 
1710  /* RPC on sp_execute */
1712 
1713  tds7_send_execute(tds, dyn);
1714 
1715  return tds_query_flush_packet(tds);
1716  }
1717 
1718  if (dyn->emulated) {
1720  return tds_query_flush_packet(tds);
1721  }
1722 
1723  /* query has been prepared successfully, discard original query */
1724  if (dyn->query)
1725  TDS_ZERO_FREE(dyn->query);
1726 
1727  tds->out_flag = TDS_NORMAL;
1728  /* dynamic id */
1731  tds_put_byte(tds, 0x02);
1732  tds_put_byte(tds, dyn->params ? 0x01 : 0);
1734  tds_put_string(tds, dyn->id, -1);
1735  } TDS_END_LEN
1736  tds_put_smallint(tds, 0);
1737  } TDS_END_LEN
1738 
1739  if (dyn->params)
1741 
1742  /* send it */
1743  return tds_query_flush_packet(tds);
1744 }
1745 
1746 /**
1747  * Send parameters to server.
1748  * \tds
1749  * \param info parameters to send
1750  * \param flags 0 or TDS_PUT_DATA_USE_NAME
1751  */
1752 static TDSRET
1754 {
1755  int i;
1756  bool wide = false;
1757 
1760 
1761  /* column descriptions */
1762  for (;;) {
1763  TDSFREEZE outer, inner;
1764 
1765  tds_freeze(tds, &outer, 0);
1766  if (wide) {
1768  tds_freeze(tds, &inner, 4);
1770  } else {
1772  tds_freeze(tds, &inner, 2);
1773  }
1774 
1775  /* number of parameters */
1776  tds_put_smallint(tds, info->num_cols);
1777 
1778  /* column detail for each parameter */
1779  for (i = 0; i < info->num_cols; i++)
1781 
1782  /* if we fits we are fine */
1783  if (wide || tds_freeze_written(&inner) - 2 < 0x10000u) {
1784  tds_freeze_close(&inner);
1785  tds_freeze_close(&outer);
1786  break;
1787  }
1788 
1789  /* try again with wide */
1790  tds_freeze_abort(&inner);
1791  tds_freeze_abort(&outer);
1793  return TDS_FAIL;
1794  wide = true;
1795  }
1796 
1797  /* row data */
1799  for (i = 0; i < info->num_cols; i++)
1800  TDS_PROPAGATE(tds_put_data(tds, info->columns[i]));
1801  return TDS_SUCCESS;
1802 }
1803 
1804 /**
1805  * Check if dynamic request must be unprepared.
1806  * Depending on status and protocol version request should be unprepared
1807  * or not.
1808  * \tds
1809  * \param dyn dynamic request to check
1810  */
1811 int
1813 {
1815  CHECK_DYNAMIC_EXTRA(dyn);
1816 
1817  /* check if statement is prepared */
1818  if (IS_TDS7_PLUS(conn) && !dyn->num_id)
1819  return 0;
1820 
1821  if (dyn->emulated || !dyn->id[0])
1822  return 0;
1823 
1824  return 1;
1825 }
1826 
1827 /**
1828  * Unprepare dynamic on idle.
1829  * This let libTDS close the prepared statement when possible.
1830  * \tds
1831  * \param dyn dynamic request to close
1832  */
1833 TDSRET
1835 {
1837  CHECK_DYNAMIC_EXTRA(dyn);
1838 
1839  if (!tds_needs_unprepare(conn, dyn)) {
1841  return TDS_SUCCESS;
1842  }
1843 
1844  dyn->defer_close = true;
1845  conn->pending_close = 1;
1846 
1847  return TDS_SUCCESS;
1848 }
1849 
1850 /**
1851  * Send a unprepare request for a prepared query
1852  * \param tds state information for the socket and the TDS protocol
1853  * \param dyn dynamic query
1854  * \result TDS_SUCCESS or TDS_FAIL
1855  */
1856 TDSRET
1858 {
1860  /* TODO test dyn in tds */
1861  CHECK_DYNAMIC_EXTRA(dyn);
1862 
1863  if (!dyn)
1864  return TDS_FAIL;
1865 
1866  tdsdump_log(TDS_DBG_FUNC, "tds_submit_unprepare() %s\n", dyn->id);
1867 
1869  return TDS_FAIL;
1870 
1871  tds_set_cur_dyn(tds, dyn);
1872 
1873  if (IS_TDS7_PLUS(tds->conn)) {
1874  /* RPC on sp_execute */
1876 
1877  /* procedure name */
1878  if (IS_TDS71_PLUS(tds->conn)) {
1879  /* save some byte for mssql2k */
1880  tds_put_smallint(tds, -1);
1882  } else {
1883  TDS_PUT_N_AS_UCS2(tds, "sp_unprepare");
1884  }
1885  tds_put_smallint(tds, 0); /* flags */
1886 
1887  /* id of prepared statement */
1888  tds_put_byte(tds, 0);
1889  tds_put_byte(tds, 0);
1891  tds_put_byte(tds, 4);
1892  tds_put_byte(tds, 4);
1893  tds_put_int(tds, dyn->num_id);
1894 
1896  return tds_query_flush_packet(tds);
1897  }
1898 
1899  if (dyn->emulated) {
1901 
1902  /* just a dummy select to return some data */
1903  tds_put_string(tds, "select 1 where 0=1", -1);
1904  return tds_query_flush_packet(tds);
1905  }
1906 
1907  tds->out_flag = TDS_NORMAL;
1908  /* dynamic id */
1912  tds_put_byte(tds, 0x00);
1914  tds_put_string(tds, dyn->id, -1);
1915  } TDS_END_LEN
1916  tds_put_smallint(tds, 0);
1917  } TDS_END_LEN
1918 
1919  /* send it */
1921  return tds_query_flush_packet(tds);
1922 }
1923 
1924 /**
1925  * Send RPC as string query.
1926  * This function is used on old protocol which does not support RPC queries.
1927  * \tds
1928  * \param rpc_name name of RPC to invoke
1929  * \param params parameters to send to server
1930  * \returns TDS_FAIL or TDS_SUCCESS
1931  */
1932 static TDSRET
1933 tds4_send_emulated_rpc(TDSSOCKET * tds, const char *rpc_name, TDSPARAMINFO * params)
1934 {
1935  TDSCOLUMN *param;
1936  int i, n;
1937  int num_params = params ? params->num_cols : 0;
1938  const char *sep = " ";
1939  char buf[80];
1940 
1941  /* create params and set */
1942  for (i = 0, n = 0; i < num_params; ++i) {
1943 
1944  param = params->columns[i];
1945 
1946  /* declare and set output parameters */
1947  if (!param->column_output)
1948  continue;
1949  ++n;
1950  sprintf(buf, " DECLARE @P%d ", n);
1951  tds_get_column_declaration(tds, param, buf + strlen(buf));
1952  sprintf(buf + strlen(buf), " SET @P%d=", n);
1953  tds_put_string(tds, buf, -1);
1954  tds_put_param_as_string(tds, params, i);
1955  }
1956 
1957  /* put exec statement */
1958  tds_put_string(tds, " EXEC ", 6);
1959  tds_put_string(tds, rpc_name, -1);
1960 
1961  /* put arguments */
1962  for (i = 0, n = 0; i < num_params; ++i) {
1963  param = params->columns[i];
1964  tds_put_string(tds, sep, -1);
1965  if (!tds_dstr_isempty(&param->column_name)) {
1967  (int)tds_dstr_len(&param->column_name));
1968  tds_put_string(tds, "=", 1);
1969  }
1970  if (param->column_output) {
1971  ++n;
1972  sprintf(buf, "@P%d OUTPUT", n);
1973  tds_put_string(tds, buf, -1);
1974  } else {
1975  tds_put_param_as_string(tds, params, i);
1976  }
1977  sep = ",";
1978  }
1979 
1980  return tds_query_flush_packet(tds);
1981 }
1982 
1983 /**
1984  * Calls a RPC from server. Output parameters will be stored in tds->param_info.
1985  * \param tds state information for the socket and the TDS protocol
1986  * \param rpc_name name of RPC
1987  * \param params parameters informations. NULL for no parameters
1988  */
1989 TDSRET
1990 tds_submit_rpc(TDSSOCKET * tds, const char *rpc_name, TDSPARAMINFO * params, TDSHEADERS * head)
1991 {
1992  TDSCOLUMN *param;
1993  int rpc_name_len, i;
1994  int num_params = params ? params->num_cols : 0;
1995 
1997  if (params)
1998  CHECK_PARAMINFO_EXTRA(params);
1999 
2000  assert(tds);
2001  assert(rpc_name);
2002 
2004  return TDS_FAIL;
2005 
2006  /* distinguish from dynamic query */
2008 
2009  rpc_name_len = (int)strlen(rpc_name);
2010  if (IS_TDS7_PLUS(tds->conn)) {
2011  TDSFREEZE outer;
2012  unsigned int written;
2013 
2015  return TDS_FAIL;
2016 
2017  /* procedure name */
2018  tds_freeze(tds, &outer, 2);
2019  tds_put_string(tds, rpc_name, rpc_name_len);
2020  written = tds_freeze_written(&outer) / 2 - 1;
2021  tds_freeze_close_len(&outer, written);
2022 
2023  /*
2024  * TODO support flags
2025  * bit 0 (1 as flag) in TDS7/TDS5 is "recompile"
2026  * bit 1 (2 as flag) in TDS7+ is "no metadata" bit
2027  * (I don't know meaning of "no metadata")
2028  */
2029  tds_put_smallint(tds, 0);
2030 
2031  for (i = 0; i < num_params; i++) {
2032  param = params->columns[i];
2034  TDS_PROPAGATE(tds_put_data(tds, param));
2035  }
2036 
2037  return tds_query_flush_packet(tds);
2038  }
2039 
2040  if (IS_TDS50(tds->conn)) {
2041  tds->out_flag = TDS_NORMAL;
2042 
2043  /* DBRPC */
2047  tds_put_string(tds, rpc_name, rpc_name_len);
2048  } TDS_END_LEN
2049  /* TODO flags */
2050  tds_put_smallint(tds, num_params ? 2 : 0);
2051  } TDS_END_LEN
2052 
2053  if (num_params)
2055 
2056  /* send it */
2057  return tds_query_flush_packet(tds);
2058  }
2059 
2060  /* emulate it for TDS4.x, send RPC for mssql */
2061  if (tds->conn->tds_version < 0x500)
2062  return tds4_send_emulated_rpc(tds, rpc_name, params);
2063 
2064  /* TODO continue, support for TDS4?? */
2066  return TDS_FAIL;
2067 }
2068 
2069 /**
2070  * tds_send_cancel() sends an empty packet (8 byte header only)
2071  * tds_process_cancel should be called directly after this.
2072  * \param tds state information for the socket and the TDS protocol
2073  * \remarks
2074  * tcp will either deliver the packet or time out.
2075  * (TIME_WAIT determines how long it waits between retries.)
2076  *
2077  * On sending the cancel, we may get EAGAIN. We then select(2) until we know
2078  * either 1) it succeeded or 2) it didn't. On failure, close the socket,
2079  * tell the app, and fail the function.
2080  *
2081  * On success, we read(2) and wait for a reply with select(2). If we get
2082  * one, great. If the client's timeout expires, we tell him, but all we can
2083  * do is wait some more or give up and close the connection. If he tells us
2084  * to cancel again, we wait some more.
2085  */
2086 TDSRET
2088 {
2089 #if ENABLE_ODBC_MARS
2091 
2092  tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: %sin_cancel and %sidle\n",
2093  (tds->in_cancel? "":"not "), (tds->state == TDS_IDLE? "":"not "));
2094 
2095  /* one cancel is sufficient */
2096  if (tds->in_cancel || tds->state == TDS_IDLE) {
2097  return TDS_SUCCESS;
2098  }
2099 
2100  tds->in_cancel = 1;
2101 
2102  if (tds_mutex_trylock(&tds->conn->list_mtx)) {
2103  /* TODO check */
2104  /* signal other socket */
2105  tds_wakeup_send(&tds->conn->wakeup, 1);
2106  return TDS_SUCCESS;
2107  }
2108  if (tds->conn->in_net_tds) {
2110  /* TODO check */
2111  /* signal other socket */
2112  tds_wakeup_send(&tds->conn->wakeup, 1);
2113  return TDS_SUCCESS;
2114  }
2116 
2117  /*
2118  problem: if we are in in_net and we got a signal ??
2119  on timeout we and a cancel, directly in in_net
2120  if we hold the lock and we get a signal lock create a death lock
2121 
2122  if we use a recursive mutex and we can get the lock there are 2 cases
2123  - same thread, we could add a packet and signal, no try ok
2124  - first thread locking, we could add a packet but are we sure it get processed ??, no try ok
2125  if recursive mutex and we can't get another thread, wait
2126 
2127  if mutex is not recursive and we get the lock (try)
2128  - nobody locked, if in_net it could be same or another
2129  if mutex is not recursive and we can't get the lock
2130  - another thread is locking, sending signal require not exiting and global list (not protected by list_mtx)
2131  - same thread have lock, we can't wait nothing without deathlock, setting a flag in tds and signaling could help
2132 
2133  if a tds is waiting for data or is waiting for a condition or for a signal in poll
2134  pass cancel request on socket ??
2135  */
2136 
2137  tds->out_flag = TDS_CANCEL;
2138  tds->out_pos = 8;
2139  tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: sending cancel packet\n");
2140  return tds_flush_packet(tds);
2141 #else
2142  TDSRET rc;
2143 
2144  /*
2145  * if we are not able to get the lock signal other thread
2146  * this means that either:
2147  * - another thread is processing data
2148  * - we got called from a signal inside processing thread
2149  * - we got called from message handler
2150  */
2151  if (tds_mutex_trylock(&tds->wire_mtx)) {
2152  /* TODO check */
2153  if (!tds->in_cancel)
2154  tds->in_cancel = 1;
2155  /* signal other socket */
2156  tds_wakeup_send(&tds->conn->wakeup, 1);
2157  return TDS_SUCCESS;
2158  }
2159 
2161 
2162  tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: %sin_cancel and %sidle\n",
2163  (tds->in_cancel? "":"not "), (tds->state == TDS_IDLE? "":"not "));
2164 
2165  /* one cancel is sufficient */
2166  if (tds->in_cancel || tds->state == TDS_IDLE) {
2168  return TDS_SUCCESS;
2169  }
2170 
2171  rc = tds_put_cancel(tds);
2173 
2174  return rc;
2175 #endif
2176 }
2177 
2178 /**
2179  * Quote a string properly. Output string is always NUL-terminated
2180  * \param buffer output buffer. If NULL function will just return
2181  * required bytes
2182  * \param quoting quote character (should be one of '\'', '"', ']')
2183  * \param id string to quote
2184  * \param len length of string to quote
2185  * \returns size of output string
2186  */
2187 static size_t
2188 tds_quote(char *buffer, char quoting, const char *id, size_t len)
2189 {
2190  size_t size;
2191  const char *src, *pend;
2192  char *dst;
2193 
2194  pend = id + len;
2195 
2196  /* quote */
2197  src = id;
2198  if (!buffer) {
2199  size = 2u + len;
2200  for (; src != pend; ++src)
2201  if (*src == quoting)
2202  ++size;
2203  return size;
2204  }
2205 
2206  dst = buffer;
2207  *dst++ = (quoting == ']') ? '[' : quoting;
2208  for (; src != pend; ++src) {
2209  if (*src == quoting)
2210  *dst++ = quoting;
2211  *dst++ = *src;
2212  }
2213  *dst++ = quoting;
2214  *dst = 0;
2215  return dst - buffer;
2216 }
2217 
2218 /**
2219  * Quote an id
2220  * \param tds state information for the socket and the TDS protocol
2221  * \param buffer buffer to store quoted id. If NULL do not write anything
2222  * (useful to compute quote length)
2223  * \param id id to quote
2224  * \param idlen id length (< 0 for NUL terminated)
2225  * \result written chars (not including needed terminator)
2226  * \see tds_quote_id_rpc
2227  */
2228 size_t
2229 tds_quote_id(TDSSOCKET * tds, char *buffer, const char *id, ssize_t idlen)
2230 {
2231  size_t i, len;
2232 
2234 
2235  len = idlen < 0 ? strlen(id) : (size_t) idlen;
2236 
2237  /* quote always for mssql */
2238  if (TDS_IS_MSSQL(tds) || tds->conn->product_version >= TDS_SYB_VER(12, 5, 1))
2239  return tds_quote(buffer, ']', id, len);
2240 
2241  /* need quote ?? */
2242  for (i = 0; i < len; ++i) {
2243  char c = id[i];
2244 
2245  if (c >= 'a' && c <= 'z')
2246  continue;
2247  if (c >= 'A' && c <= 'Z')
2248  continue;
2249  if (i > 0 && c >= '0' && c <= '9')
2250  continue;
2251  if (c == '_')
2252  continue;
2253  return tds_quote(buffer, '\"', id, len);
2254  }
2255 
2256  if (buffer) {
2257  memcpy(buffer, id, len);
2258  buffer[len] = '\0';
2259  }
2260  return len;
2261 }
2262 
2263 /**
2264  * Quote an id for a RPC call
2265  * \param tds state information for the socket and the TDS protocol
2266  * \param buffer buffer to store quoted id. If NULL do not write anything
2267  * (useful to compute quote length)
2268  * \param id id to quote
2269  * \param idlen id length (< 0 for NUL terminated)
2270  * \result written chars (not including needed terminator)
2271  * \see tds_quote_id
2272  */
2273 size_t
2274 tds_quote_id_rpc(TDSSOCKET * tds, char *buffer, const char *id, ssize_t idlen)
2275 {
2276  size_t len;
2277  /* We are quoting for RPC calls, not base language queries. For RPC calls Sybase
2278  * servers don't accept '[]' style quoting so don't use them but use normal
2279  * identifier quoting ('""') */
2280  char quote_id_char = TDS_IS_MSSQL(tds) ? ']' : '\"';
2281 
2283 
2284  len = idlen < 0 ? strlen(id) : (size_t) idlen;
2285 
2286  return tds_quote(buffer, quote_id_char, id, len);
2287 }
2288 
2289 /**
2290  * Quote a string
2291  * \param tds state information for the socket and the TDS protocol
2292  * \param buffer buffer to store quoted id. If NULL do not write anything
2293  * (useful to compute quote length)
2294  * \param str string to quote (not necessary NUL-terminated)
2295  * \param len length of string (-1 for NUL-terminated)
2296  * \result written chars (not including needed terminator)
2297  */
2298 size_t
2300 {
2301  return tds_quote(buffer, '\'', str, len < 0 ? strlen(str) : (size_t) len);
2302 }
2303 
2304 /**
2305  * Set current cursor.
2306  * Current cursor is the one will receive output from server.
2307  * \tds
2308  * \param cursor cursor to set as current
2309  */
2310 static inline void
2312 {
2313  ++cursor->ref_count;
2314  if (tds->cur_cursor)
2316  tds->cur_cursor = cursor;
2317 }
2318 
2319 TDSRET
2320 tds_cursor_declare(TDSSOCKET * tds, TDSCURSOR * cursor, TDSPARAMINFO *params, int *something_to_send)
2321 {
2323 
2324  if (!cursor)
2325  return TDS_FAIL;
2326 
2327  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_declare() cursor id = %d\n", cursor->cursor_id);
2328 
2329  if (IS_TDS7_PLUS(tds->conn)) {
2331  cursor->srv_status |= TDS_CUR_ISTAT_CLOSED;
2332  cursor->srv_status |= TDS_CUR_ISTAT_RDONLY;
2333  }
2334 
2335  if (IS_TDS50(tds->conn)) {
2336  if (!*something_to_send) {
2338  return TDS_FAIL;
2339 
2340  tds->out_flag = TDS_NORMAL;
2341  }
2342  if (tds->state != TDS_WRITING || tds->out_flag != TDS_NORMAL)
2343  return TDS_FAIL;
2344 
2346 
2347  /* length of the data stream that follows */
2350  tds_put_string(tds, cursor->cursor_name, -1);
2351  } TDS_END_LEN
2352  tds_put_byte(tds, 1); /* cursor option is read only=1, unused=0 */
2353  tds_put_byte(tds, 0); /* status unused=0 */
2355  tds_put_string(tds, cursor->query, -1);
2356  } TDS_END_LEN
2357  tds_put_tinyint(tds, 0); /* number of columns = 0 , valid value applicable only for updatable cursor */
2358  } TDS_END_LEN
2359  *something_to_send = 1;
2360  }
2361 
2362  return TDS_SUCCESS;
2363 }
2364 
2365 TDSRET
2366 tds_cursor_open(TDSSOCKET * tds, TDSCURSOR * cursor, TDSPARAMINFO *params, int *something_to_send)
2367 {
2369 
2370  if (!cursor)
2371  return TDS_FAIL;
2372 
2373  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_open() cursor id = %d\n", cursor->cursor_id);
2374 
2375  if (!*something_to_send) {
2377  return TDS_FAIL;
2378  }
2379  if (tds->state != TDS_WRITING)
2380  return TDS_FAIL;
2381 
2382  tds_set_cur_cursor(tds, cursor);
2383 
2384  if (IS_TDS50(tds->conn)) {
2385  tds->out_flag = TDS_NORMAL;
2388 
2389  /*tds_put_int(tds, cursor->cursor_id); *//* Only if cursor id is passed as zero, the cursor name need to be sent */
2390 
2391  tds_put_int(tds, 0);
2393  tds_put_string(tds, cursor->cursor_name, -1);
2394  } TDS_END_LEN
2395  tds_put_byte(tds, 0); /* Cursor status : 0 for no arguments */
2396  } TDS_END_LEN
2397  *something_to_send = 1;
2398  }
2399  if (IS_TDS7_PLUS(tds->conn)) {
2400  const char *converted_query;
2401  size_t converted_query_len;
2402  int num_params = params ? params->num_cols : 0;
2403  TDSFREEZE outer;
2404  TDSRET rc = TDS_SUCCESS;
2405 
2406  /* cursor statement */
2407  converted_query = tds_convert_string
2408  (tds, tds->conn->char_convs[client2ucs2], cursor->query,
2409  strlen(cursor->query), &converted_query_len);
2410  if (!converted_query) {
2411  if (!*something_to_send)
2413  return TDS_FAIL;
2414  }
2415 
2416  tds_freeze(tds, &outer, 0);
2417 
2418  /* RPC call to sp_cursoropen */
2420 
2421  /* procedure identifier by number */
2422 
2423  if (IS_TDS71_PLUS(tds->conn)) {
2424  tds_put_smallint(tds, -1);
2426  } else {
2427  TDS_PUT_N_AS_UCS2(tds, "sp_cursoropen");
2428  }
2429 
2430  tds_put_smallint(tds, 0); /* flags */
2431 
2432  /* return cursor handle (int) */
2433 
2434  tds_put_byte(tds, 0); /* no parameter name */
2435  tds_put_byte(tds, 1); /* output parameter */
2437  tds_put_byte(tds, 4);
2438  tds_put_byte(tds, 0);
2439 
2440  if (num_params) {
2441  tds7_put_query_params(tds, converted_query, converted_query_len);
2442  } else {
2443  tds_put_byte(tds, 0);
2444  tds_put_byte(tds, 0);
2445  tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
2446  TDS_PUT_INT(tds, converted_query_len);
2447  if (IS_TDS71_PLUS(tds->conn))
2448  tds_put_n(tds, tds->conn->collation, 5);
2449  TDS_PUT_INT(tds, converted_query_len);
2450  tds_put_n(tds, converted_query, (int)converted_query_len);
2451  }
2452 
2453  /* type */
2454  tds_put_byte(tds, 0); /* no parameter name */
2455  tds_put_byte(tds, 1); /* output parameter */
2457  tds_put_byte(tds, 4);
2458  tds_put_byte(tds, 4);
2459  tds_put_int(tds, num_params ? cursor->type | 0x1000 : cursor->type);
2460 
2461  /* concurrency */
2462  tds_put_byte(tds, 0); /* no parameter name */
2463  tds_put_byte(tds, 1); /* output parameter */
2465  tds_put_byte(tds, 4);
2466  tds_put_byte(tds, 4);
2467  tds_put_int(tds, cursor->concurrency);
2468 
2469  /* row count */
2470  tds_put_byte(tds, 0);
2471  tds_put_byte(tds, 1); /* output parameter */
2473  tds_put_byte(tds, 4);
2474  tds_put_byte(tds, 4);
2475  tds_put_int(tds, 0);
2476 
2477  if (num_params) {
2478  int i;
2479 
2480  rc = tds7_write_param_def_from_query(tds, converted_query, converted_query_len, params);
2481 
2482  for (i = 0; i < num_params; i++) {
2483  TDSCOLUMN *param = params->columns[i];
2484  /* TODO check error */
2485  tds_put_data_info(tds, param, 0);
2486  /* FIXME handle error */
2487  tds_put_data(tds, param);
2488  }
2489  }
2490  tds_convert_string_free(cursor->query, converted_query);
2491  if (TDS_FAILED(rc)) {
2492  tds_freeze_abort(&outer);
2493  if (!*something_to_send)
2495  return rc;
2496  }
2497  tds_freeze_close(&outer);
2498 
2499  *something_to_send = 1;
2501  tdsdump_log(TDS_DBG_ERROR, "tds_cursor_open (): RPC call set up \n");
2502  }
2503 
2504 
2505  tdsdump_log(TDS_DBG_ERROR, "tds_cursor_open (): cursor open completed\n");
2506  return TDS_SUCCESS;
2507 }
2508 
2509 TDSRET
2510 tds_cursor_setrows(TDSSOCKET * tds, TDSCURSOR * cursor, int *something_to_send)
2511 {
2513 
2514  if (!cursor)
2515  return TDS_FAIL;
2516 
2517  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_setrows() cursor id = %d\n", cursor->cursor_id);
2518 
2519  if (IS_TDS7_PLUS(tds->conn)) {
2520  cursor->srv_status &= ~TDS_CUR_ISTAT_DECLARED;
2521  cursor->srv_status |= TDS_CUR_ISTAT_CLOSED;
2522  cursor->srv_status |= TDS_CUR_ISTAT_ROWCNT;
2523  }
2524 
2525  if (IS_TDS50(tds->conn)) {
2526  if (!*something_to_send) {
2528  return TDS_FAIL;
2529 
2530  tds->out_flag = TDS_NORMAL;
2531  }
2532  if (tds->state != TDS_WRITING || tds->out_flag != TDS_NORMAL)
2533  return TDS_FAIL;
2534 
2535  tds_set_cur_cursor(tds, cursor);
2537 
2539  /* length of data stream that follows */
2540 
2541  /* tds_put_int(tds, tds->cursor->cursor_id); */ /* Cursor id */
2542 
2543  tds_put_int(tds, 0);
2545  tds_put_string(tds, cursor->cursor_name, -1);
2546  } TDS_END_LEN
2547  tds_put_byte(tds, 1); /* Command TDS_CUR_CMD_SETCURROWS */
2548  tds_put_byte(tds, 0x00); /* Status - TDS_CUR_ISTAT_ROWCNT 0x0020 */
2549  tds_put_byte(tds, 0x20); /* Status - TDS_CUR_ISTAT_ROWCNT 0x0020 */
2550  tds_put_int(tds, cursor->cursor_rows); /* row count to set */
2551  } TDS_END_LEN
2552  *something_to_send = 1;
2553 
2554  }
2555  return TDS_SUCCESS;
2556 }
2557 
2558 static void
2559 tds7_put_cursor_fetch(TDSSOCKET * tds, TDS_INT cursor_id, TDS_TINYINT fetch_type, TDS_INT i_row, TDS_INT num_rows)
2560 {
2561  if (IS_TDS71_PLUS(tds->conn)) {
2562  tds_put_smallint(tds, -1);
2564  } else {
2565  TDS_PUT_N_AS_UCS2(tds, "sp_cursorfetch");
2566  }
2567 
2568  /* This flag tells the SP only to */
2569  /* output a dummy metadata token */
2570 
2571  tds_put_smallint(tds, 2);
2572 
2573  /* input cursor handle (int) */
2574 
2575  tds_put_byte(tds, 0); /* no parameter name */
2576  tds_put_byte(tds, 0); /* input parameter */
2578  tds_put_byte(tds, 4);
2579  tds_put_byte(tds, 4);
2580  tds_put_int(tds, cursor_id);
2581 
2582  /* fetch type - 2 = NEXT */
2583 
2584  tds_put_byte(tds, 0); /* no parameter name */
2585  tds_put_byte(tds, 0); /* input parameter */
2587  tds_put_byte(tds, 4);
2588  tds_put_byte(tds, 4);
2589  tds_put_int(tds, fetch_type);
2590 
2591  /* row number */
2592  tds_put_byte(tds, 0); /* no parameter name */
2593  tds_put_byte(tds, 0); /* input parameter */
2595  tds_put_byte(tds, 4);
2596  if ((fetch_type & 0x30) != 0) {
2597  tds_put_byte(tds, 4);
2598  tds_put_int(tds, i_row);
2599  } else {
2600  tds_put_byte(tds, 0);
2601  }
2602 
2603  /* number of rows to fetch */
2604  tds_put_byte(tds, 0); /* no parameter name */
2605  tds_put_byte(tds, 0); /* input parameter */
2607  tds_put_byte(tds, 4);
2608  tds_put_byte(tds, 4);
2609  tds_put_int(tds, num_rows);
2610 }
2611 
2612 TDSRET
2614 {
2616 
2617  if (!cursor)
2618  return TDS_FAIL;
2619 
2620  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_fetch() cursor id = %d\n", cursor->cursor_id);
2621 
2623  return TDS_FAIL;
2624 
2625  tds_set_cur_cursor(tds, cursor);
2626 
2627  if (IS_TDS50(tds->conn)) {
2628  size_t len = strlen(cursor->cursor_name);
2629  size_t row_len = 0;
2630 
2631  tds->out_flag = TDS_NORMAL;
2633 
2634  if (len > (255-10))
2635  len = (255-10);
2636  if (fetch_type == TDS_CURSOR_FETCH_ABSOLUTE || fetch_type == TDS_CURSOR_FETCH_RELATIVE)
2637  row_len = 4;
2638 
2639  /*tds_put_smallint(tds, 8); */
2640 
2641  TDS_PUT_SMALLINT(tds, 6 + len + row_len); /* length of the data stream that follows */
2642 
2643  /*tds_put_int(tds, cursor->cursor_id); *//* cursor id returned by the server */
2644 
2645  tds_put_int(tds, 0);
2646  TDS_PUT_BYTE(tds, len);
2647  tds_put_n(tds, cursor->cursor_name, len);
2648  tds_put_tinyint(tds, fetch_type);
2649 
2650  /* optional argument to fetch row at absolute/relative position */
2651  if (row_len)
2652  tds_put_int(tds, i_row);
2653  return tds_query_flush_packet(tds);
2654  }
2655 
2656  if (IS_TDS7_PLUS(tds->conn)) {
2657 
2658  /* RPC call to sp_cursorfetch */
2659  static const unsigned char mssql_fetch[7] = {
2660  0,
2661  2, /* TDS_CURSOR_FETCH_NEXT */
2662  4, /* TDS_CURSOR_FETCH_PREV */
2663  1, /* TDS_CURSOR_FETCH_FIRST */
2664  8, /* TDS_CURSOR_FETCH_LAST */
2665  0x10, /* TDS_CURSOR_FETCH_ABSOLUTE */
2666  0x20 /* TDS_CURSOR_FETCH_RELATIVE */
2667  };
2668 
2670 
2671  /* TODO enum for 2 ... */
2672  if (cursor->type == 2 && fetch_type == TDS_CURSOR_FETCH_ABSOLUTE) {
2673  /* strangely dynamic cursor do not support absolute so emulate it with first + relative */
2674  tds7_put_cursor_fetch(tds, cursor->cursor_id, 1, 0, 0);
2675  /* TODO define constant */
2676  tds_put_byte(tds, IS_TDS72_PLUS(tds->conn) ? 0xff : 0x80);
2677  tds7_put_cursor_fetch(tds, cursor->cursor_id, 0x20, i_row, cursor->cursor_rows);
2678  } else {
2679  /* TODO check fetch_type ?? */
2680  tds7_put_cursor_fetch(tds, cursor->cursor_id, mssql_fetch[fetch_type], i_row, cursor->cursor_rows);
2681  }
2682 
2684  return tds_query_flush_packet(tds);
2685  }
2686 
2688  return TDS_SUCCESS;
2689 }
2690 
2691 TDSRET
2693 {
2694  int done_flags;
2695  TDSRET retcode;
2696  TDS_INT result_type;
2697 
2699 
2700  if (!cursor)
2701  return TDS_FAIL;
2702 
2703  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_get_cursor_info() cursor id = %d\n", cursor->cursor_id);
2704 
2705  /* Assume not known */
2706  assert(prow_number && prow_count);
2707  *prow_number = 0;
2708  *prow_count = 0;
2709 
2710  if (IS_TDS7_PLUS(tds->conn)) {
2711  /* Change state to querying */
2713  return TDS_FAIL;
2714 
2715  /* Remember the server has been sent a command for this cursor */
2716  tds_set_cur_cursor(tds, cursor);
2717 
2718  /* General initialization of server command */
2720 
2721  /* Create and send query to server */
2722  if (IS_TDS71_PLUS(tds->conn)) {
2723  tds_put_smallint(tds, -1);
2725  } else {
2726  TDS_PUT_N_AS_UCS2(tds, "sp_cursorfetch");
2727  }
2728 
2729  /* This flag tells the SP only to */
2730  /* output a dummy metadata token */
2731 
2732  tds_put_smallint(tds, 2);
2733 
2734  /* input cursor handle (int) */
2735 
2736  tds_put_byte(tds, 0); /* no parameter name */
2737  tds_put_byte(tds, 0); /* input parameter */
2739  tds_put_byte(tds, 4);
2740  tds_put_byte(tds, 4);
2741  tds_put_int(tds, cursor->cursor_id);
2742 
2743  tds_put_byte(tds, 0); /* no parameter name */
2744  tds_put_byte(tds, 0); /* input parameter */
2746  tds_put_byte(tds, 4);
2747  tds_put_byte(tds, 4);
2748  tds_put_int(tds, 0x100); /* FETCH_INFO */
2749 
2750  /* row number */
2751  tds_put_byte(tds, 0); /* no parameter name */
2752  tds_put_byte(tds, 1); /* output parameter */
2754  tds_put_byte(tds, 4);
2755  tds_put_byte(tds, 0);
2756 
2757  /* number of rows fetched */
2758  tds_put_byte(tds, 0); /* no parameter name */
2759  tds_put_byte(tds, 1); /* output parameter */
2761  tds_put_byte(tds, 4);
2762  tds_put_byte(tds, 0);
2763 
2764  /* Adjust current state */
2767 
2768  /* Process answer from server */
2769  for (;;) {
2770  retcode = tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_PROC);
2771  tdsdump_log(TDS_DBG_FUNC, "tds_cursor_get_cursor_info: tds_process_tokens returned %d\n", retcode);
2772  tdsdump_log(TDS_DBG_FUNC, " result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
2773  result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
2774  switch (retcode) {
2775  case TDS_NO_MORE_RESULTS:
2776  return TDS_SUCCESS;
2777  case TDS_SUCCESS:
2778  if (result_type==TDS_PARAM_RESULT) {
2779  /* Status is updated when TDS_STATUS_RESULT token arrives, before the params are processed */
2780  if (tds->has_status && tds->ret_status==0) {
2781  TDSPARAMINFO *pinfo = tds->current_results;
2782 
2783  /* Make sure the params retuned have the correct type and size */
2784  if (pinfo && pinfo->num_cols==2
2785  && pinfo->columns[0]->on_server.column_type==SYBINTN
2786  && pinfo->columns[1]->on_server.column_type==SYBINTN
2787  && pinfo->columns[0]->column_size==4
2788  && pinfo->columns[1]->column_size==4) {
2789  /* Take the values */
2790  *prow_number = (TDS_UINT)(*(TDS_INT *) pinfo->columns[0]->column_data);
2791  *prow_count = (TDS_UINT)(*(TDS_INT *) pinfo->columns[1]->column_data);
2792  tdsdump_log(TDS_DBG_FUNC, "----------------> prow_number=%u, prow_count=%u\n",
2793  *prow_count, *prow_number);
2794  }
2795  }
2796  }
2797  break;
2798  default:
2799  return retcode;
2800  }
2801  }
2802  }
2803 
2804  return TDS_SUCCESS;
2805 }
2806 
2807 TDSRET
2809 {
2811 
2812  if (!cursor)
2813  return TDS_FAIL;
2814 
2815  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_close() cursor id = %d\n", cursor->cursor_id);
2816 
2818  return TDS_FAIL;
2819 
2820  tds_set_cur_cursor(tds, cursor);
2821 
2822  if (IS_TDS50(tds->conn)) {
2823  tds->out_flag = TDS_NORMAL;
2825  tds_put_smallint(tds, 5); /* length of the data stream that follows */
2826  tds_put_int(tds, cursor->cursor_id); /* cursor id returned by the server is available now */
2827 
2828  if (cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
2829  tds_put_byte(tds, 0x01); /* Close option: TDS_CUR_COPT_DEALLOC */
2831  }
2832  else
2833  tds_put_byte(tds, 0x00); /* Close option: TDS_CUR_COPT_UNUSED */
2834 
2835  }
2836  if (IS_TDS7_PLUS(tds->conn)) {
2837 
2838  /* RPC call to sp_cursorclose */
2840 
2841  if (IS_TDS71_PLUS(tds->conn)) {
2842  tds_put_smallint(tds, -1);
2844  } else {
2845  TDS_PUT_N_AS_UCS2(tds, "sp_cursorclose");
2846  }
2847 
2848  /* This flag tells the SP to output only a dummy metadata token */
2849 
2850  tds_put_smallint(tds, 2);
2851 
2852  /* input cursor handle (int) */
2853 
2854  tds_put_byte(tds, 0); /* no parameter name */
2855  tds_put_byte(tds, 0); /* input parameter */
2857  tds_put_byte(tds, 4);
2858  tds_put_byte(tds, 4);
2859  tds_put_int(tds, cursor->cursor_id);
2861  }
2862  return tds_query_flush_packet(tds);
2863 
2864 }
2865 
2866 TDSRET
2868 {
2869  TDSFREEZE outer;
2870  unsigned int written;
2871 
2873 
2874  if (!cursor)
2875  return TDS_FAIL;
2876 
2877  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_setname() cursor id = %d\n", cursor->cursor_id);
2878 
2879  if (!IS_TDS7_PLUS(tds->conn))
2880  return TDS_SUCCESS;
2881 
2883  return TDS_FAIL;
2884 
2885  tds_set_cur_cursor(tds, cursor);
2886 
2887  /* RPC call to sp_cursoroption */
2889 
2890  if (IS_TDS71_PLUS(tds->conn)) {
2891  tds_put_smallint(tds, -1);
2893  } else {
2894  TDS_PUT_N_AS_UCS2(tds, "sp_cursoroption");
2895  }
2896 
2897  tds_put_smallint(tds, 0);
2898 
2899  /* input cursor handle (int) */
2900  tds_put_byte(tds, 0); /* no parameter name */
2901  tds_put_byte(tds, 0); /* input parameter */
2903  tds_put_byte(tds, 4);
2904  tds_put_byte(tds, 4);
2905  tds_put_int(tds, cursor->cursor_id);
2906 
2907  /* code, 2 == set cursor name */
2908  tds_put_byte(tds, 0); /* no parameter name */
2909  tds_put_byte(tds, 0); /* input parameter */
2911  tds_put_byte(tds, 4);
2912  tds_put_byte(tds, 4);
2913  tds_put_int(tds, 2);
2914 
2915  /* cursor name */
2916  tds_put_byte(tds, 0);
2917  tds_put_byte(tds, 0);
2919  tds_freeze(tds, &outer, 2);
2920  if (IS_TDS71_PLUS(tds->conn))
2921  tds_put_n(tds, tds->conn->collation, 5);
2923  tds_put_string(tds, cursor->cursor_name, -1);
2924  written = tds_freeze_written(current_freeze) - 2;
2925  } TDS_END_LEN
2926  tds_freeze_close_len(&outer, written);
2927 
2929 
2930  return tds_query_flush_packet(tds);
2931 }
2932 
2933 TDSRET
2935 {
2937 
2938  if (!cursor)
2939  return TDS_FAIL;
2940 
2941  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_update() cursor id = %d\n", cursor->cursor_id);
2942 
2943  /* client must provide parameters for update */
2944  if (op == TDS_CURSOR_UPDATE && (!params || params->num_cols <= 0))
2945  return TDS_FAIL;
2946 
2948  return TDS_FAIL;
2949 
2950  tds_set_cur_cursor(tds, cursor);
2951 
2952  if (IS_TDS50(tds->conn)) {
2953  tds->out_flag = TDS_NORMAL;
2954 
2955  /* FIXME finish*/
2957  return TDS_FAIL;
2958  }
2959  if (IS_TDS7_PLUS(tds->conn)) {
2960 
2961  /* RPC call to sp_cursorclose */
2963 
2964  if (IS_TDS71_PLUS(tds->conn)) {
2965  tds_put_smallint(tds, -1);
2967  } else {
2968  TDS_PUT_N_AS_UCS2(tds, "sp_cursor");
2969  }
2970 
2971  tds_put_smallint(tds, 0);
2972 
2973  /* input cursor handle (int) */
2974  tds_put_byte(tds, 0); /* no parameter name */
2975  tds_put_byte(tds, 0); /* input parameter */
2977  tds_put_byte(tds, 4);
2978  tds_put_byte(tds, 4);
2979  tds_put_int(tds, cursor->cursor_id);
2980 
2981  /* cursor operation */
2982  tds_put_byte(tds, 0); /* no parameter name */
2983  tds_put_byte(tds, 0); /* input parameter */
2985  tds_put_byte(tds, 4);
2986  tds_put_byte(tds, 4);
2987  tds_put_int(tds, 32 | op);
2988 
2989  /* row number */
2990  tds_put_byte(tds, 0); /* no parameter name */
2991  tds_put_byte(tds, 0); /* input parameter */
2993  tds_put_byte(tds, 4);
2994  tds_put_byte(tds, 4);
2995  tds_put_int(tds, i_row);
2996 
2997  /* update require table name */
2998  if (op == TDS_CURSOR_UPDATE) {
2999  TDSCOLUMN *param;
3000  unsigned int n, num_params;
3001  const char *table_name = NULL;
3002  TDSFREEZE outer;
3003  unsigned int written;
3004 
3005  /* empty table name */
3006  tds_put_byte(tds, 0);
3007  tds_put_byte(tds, 0);
3009  num_params = params->num_cols;
3010  for (n = 0; n < num_params; ++n) {
3011  param = params->columns[n];
3012  if (!tds_dstr_isempty(&param->table_name)) {
3013  table_name = tds_dstr_cstr(&param->table_name);
3014  break;
3015  }
3016  }
3017 
3018  tds_freeze(tds, &outer, 2);
3019  if (IS_TDS71_PLUS(tds->conn))
3020  tds_put_n(tds, tds->conn->collation, 5);
3022  if (table_name)
3024  written = tds_freeze_written(current_freeze) - 2;
3025  } TDS_END_LEN
3026  tds_freeze_close_len(&outer, written);
3027 
3028  /* output columns to update */
3029  for (n = 0; n < num_params; ++n) {
3030  param = params->columns[n];
3031  /* TODO check error */
3033  /* FIXME handle error */
3034  tds_put_data(tds, param);
3035  }
3036  }
3037 
3039  }
3040  return tds_query_flush_packet(tds);
3041 }
3042 
3043 /**
3044  * Check if a cursor is allocated into the server.
3045  * If is not allocated it assures is removed from the connection list
3046  * \tds
3047  * \return true if allocated false otherwise
3048  */
3049 static bool
3051 {
3052  if (cursor->srv_status == TDS_CUR_ISTAT_UNUSED || (cursor->srv_status & TDS_CUR_ISTAT_DEALLOC) != 0
3053  || (IS_TDS7_PLUS(conn) && (cursor->srv_status & TDS_CUR_ISTAT_CLOSED) != 0)) {
3054  tds_cursor_deallocated(conn, cursor);
3055  return false;
3056  }
3057 
3058  return true;
3059 }
3060 
3061 /**
3062  * Send a deallocation request to server
3063  */
3064 TDSRET
3066 {
3067  TDSRET res = TDS_SUCCESS;
3068 
3070 
3071  if (!cursor)
3072  return TDS_FAIL;
3073 
3074  if (!tds_cursor_check_allocated(tds->conn, cursor))
3075  return TDS_SUCCESS;
3076 
3077  tdsdump_log(TDS_DBG_INFO1, "tds_cursor_dealloc() cursor id = %d\n", cursor->cursor_id);
3078 
3079  if (IS_TDS50(tds->conn)) {
3081  return TDS_FAIL;
3082  tds_set_cur_cursor(tds, cursor);
3083 
3084  tds->out_flag = TDS_NORMAL;
3086  tds_put_smallint(tds, 5); /* length of the data stream that follows */
3087  tds_put_int(tds, cursor->cursor_id); /* cursor id returned by the server is available now */
3088  tds_put_byte(tds, 0x01); /* Close option: TDS_CUR_COPT_DEALLOC */
3089  res = tds_query_flush_packet(tds);
3090  }
3091 
3092  /*
3093  * in TDS 5 the cursor deallocate function involves
3094  * a server interaction. The cursor will be freed
3095  * when we receive acknowledgement of the cursor
3096  * deallocate from the server. for TDS 7 we do it
3097  * here...
3098  */
3099  if (IS_TDS7_PLUS(tds->conn)) {
3100  if (cursor->status.dealloc == TDS_CURSOR_STATE_SENT ||
3102  tdsdump_log(TDS_DBG_ERROR, "tds_cursor_dealloc(): freeing cursor \n");
3103  }
3104  }
3105 
3106  return res;
3107 }
3108 
3109 /**
3110  * Deallocate cursor on idle.
3111  * This let libTDS close the cursor when possible.
3112  * \tds
3113  * \param cursor cursor to close
3114  */
3115 TDSRET
3117 {
3119  CHECK_CURSOR_EXTRA(cursor);
3120 
3121  /* do not mark if already deallocated */
3122  if (!tds_cursor_check_allocated(conn, cursor))
3123  return TDS_SUCCESS;
3124 
3125  cursor->defer_close = true;
3126  conn->pending_close = 1;
3127 
3128  return TDS_SUCCESS;
3129 }
3130 
3131 /**
3132  * Send a string to server while quoting it.
3133  * \tds
3134  * \param s string start
3135  * \param end string end
3136  */
3137 static void
3138 tds_quote_and_put(TDSSOCKET * tds, const char *s, const char *end)
3139 {
3140  char buf[256];
3141  int i;
3142 
3144 
3145  for (i = 0; s != end; ++s) {
3146  buf[i++] = *s;
3147  if (*s == '\'')
3148  buf[i++] = '\'';
3149  if (i >= 254) {
3150  tds_put_string(tds, buf, i);
3151  i = 0;
3152  }
3153  }
3154  tds_put_string(tds, buf, i);
3155 }
3156 
3157 typedef struct tds_quoteout_stream {
3160  char buffer[2048];
3162 
3163 static int
3165 {
3166  TDSQUOTEOUTSTREAM *s = (TDSQUOTEOUTSTREAM *) stream;
3167  TDSSOCKET *tds = s->tds;
3168  uint16_t buf[sizeof(s->buffer)];
3169 
3170  assert(len <= stream->buf_len);
3171 
3172 #define QUOTE(type, ch) do { \
3173  type *src, *dst = (type *) buf, *end = (type *) (s->buffer + len); \
3174 \
3175  for (src = (type *) s->buffer; src < end; ++src) { \
3176  if (*src == (ch)) \
3177  *dst++ = *src; \
3178  *dst++ = *src; \
3179  } \
3180  tds_put_n(tds, buf, (char *) dst - (char *) buf); \
3181 } while(0)
3182 
3183  if (IS_TDS7_PLUS(tds->conn))
3184  QUOTE(uint16_t, TDS_HOST2LE('\''));
3185  else
3186  QUOTE(char, '\'');
3187 
3188 #undef QUOTE
3189 
3190  return len;
3191 }
3192 
3193 static void
3195 {
3197  stream->stream.buffer = stream->buffer;
3198  stream->stream.buf_len = sizeof(stream->buffer);
3199  stream->tds = tds;
3200 }
3201 
3202 static TDSRET
3204 {
3205  TDS_CHAR *src;
3206  TDSICONV *char_conv = curcol->char_conv;
3207  int from, to;
3210 
3211  src = (TDS_CHAR *) curcol->column_data;
3212  if (is_blob_col(curcol))
3213  src = ((TDSBLOB *)src)->textvalue;
3214 
3215  if (is_unicode_type(curcol->on_server.column_type))
3216  tds_put_string(tds, "N", 1);
3217  tds_put_string(tds, "\'", 1);
3218 
3219  /* Compute proper characted conversion.
3220  * The conversion should be to UTF16/UCS2 for MS SQL.
3221  * Avoid double conversion, convert directly from client to server.
3222  */
3223  from = char_conv ? char_conv->from.charset.canonic : tds->conn->char_convs[client2ucs2]->from.charset.canonic;
3224  to = tds->conn->char_convs[IS_TDS7_PLUS(tds->conn) ? client2ucs2 : client2server_chardata]->to.charset.canonic;
3225  if (!char_conv || char_conv->to.charset.canonic != to)
3226  char_conv = tds_iconv_get_info(tds->conn, from, to);
3227  if (!char_conv)
3228  return TDS_FAIL;
3229 
3230  tds_staticin_stream_init(&r, src, curcol->column_cur_size);
3232 
3233  tds_convert_stream(tds, char_conv, to_server, &r.stream, &w.stream);
3234 
3235  tds_put_string(tds, "\'", 1);
3236  return TDS_SUCCESS;
3237 }
3238 
3239 /**
3240  * Send a parameter to server.
3241  * Parameters are converted to string and sent to server.
3242  * \tds
3243  * \param params parameters structure
3244  * \param n number of parameter to send
3245  * \returns TDS_FAIL or TDS_SUCCESS
3246  */
3247 static TDSRET
3249 {
3250  TDSCOLUMN *curcol = params->columns[n];
3251  CONV_RESULT cr;
3252  TDS_INT res;
3253  TDS_CHAR *src;
3254  int src_len = curcol->column_cur_size;
3255 
3256  int i;
3257  char buf[256];
3258  bool quote = false;
3259 
3261  CHECK_PARAMINFO_EXTRA(params);
3262 
3263  if (src_len < 0) {
3264  /* on TDS 4 TEXT/IMAGE cannot be NULL, use empty */
3266  tds_put_string(tds, "''", 2);
3267  else
3268  tds_put_string(tds, "NULL", 4);
3269  return TDS_SUCCESS;
3270  }
3271 
3272  if (is_char_type(curcol->on_server.column_type))
3273  return tds_put_char_param_as_string(tds, curcol);
3274 
3275  src = (TDS_CHAR *) curcol->column_data;
3276  if (is_blob_col(curcol))
3277  src = ((TDSBLOB *)src)->textvalue;
3278 
3279  /* we could try to use only tds_convert but is not good in all cases */
3280  switch (curcol->on_server.column_type) {
3281  /* binary/char, do conversion in line */
3282  case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY:
3283  tds_put_string(tds, "0x", 2);
3284  for (i=0; src_len; ++src, --src_len) {
3285  buf[i++] = tds_hex_digits[*src >> 4 & 0xF];
3286  buf[i++] = tds_hex_digits[*src & 0xF];
3287  if (i == 256) {
3288  tds_put_string(tds, buf, i);
3289  i = 0;
3290  }
3291  }
3292  tds_put_string(tds, buf, i);
3293  break;
3294  /* TODO date, use iso format */
3295  case SYBDATETIME:
3296  case SYBDATETIME4:
3297  case SYBDATETIMN:
3298  case SYBMSTIME:
3299  case SYBMSDATE:
3300  case SYBMSDATETIME2:
3301  case SYBMSDATETIMEOFFSET:
3302  case SYBTIME:
3303  case SYBDATE:
3304  case SYB5BIGTIME:
3305  case SYB5BIGDATETIME:
3306  /* TODO use an ISO context */
3307  case SYBUNIQUE:
3308  quote = true;
3309  default:
3310  res = tds_convert(tds_get_ctx(tds), tds_get_conversion_type(curcol->on_server.column_type, curcol->column_size), src, src_len, SYBCHAR, &cr);
3311  if (res < 0)
3312  return TDS_FAIL;
3313 
3314  if (quote)
3315  tds_put_string(tds, "\'", 1);
3316  tds_quote_and_put(tds, cr.c, cr.c + res);
3317  if (quote)
3318  tds_put_string(tds, "\'", 1);
3319  free(cr.c);
3320  }
3321  return TDS_SUCCESS;
3322 }
3323 
3324 /**
3325  * Emulate prepared execute traslating to a normal language
3326  */
3327 static TDSRET
3329 {
3330  int num_placeholders, i;
3331  const char *s, *e;
3332 
3334 
3335  assert(query);
3336 
3337  num_placeholders = tds_count_placeholders(query);
3338  if (num_placeholders && num_placeholders > params->num_cols)
3339  return TDS_FAIL;
3340 
3341  /*
3342  * NOTE: even for TDS5 we use this packet so to avoid computing
3343  * entire sql command
3344  */
3345  tds->out_flag = TDS_QUERY;
3346  if (!num_placeholders) {
3347  tds_put_string(tds, query, -1);
3348  return TDS_SUCCESS;
3349  }
3350 
3351  s = query;
3352  for (i = 0;; ++i) {
3353  e = tds_next_placeholder(s);
3354  tds_put_string(tds, s, (int)(e ? e - s : -1));
3355  if (!e)
3356  break;
3357  /* now translate parameter in string */
3358  tds_put_param_as_string(tds, params, i);
3359 
3360  s = e + 1;
3361  }
3362 
3363  return TDS_SUCCESS;
3364 }
3365 
3366 enum { MUL_STARTED = 1 };
3367 
3368 TDSRET
3370 {
3371  unsigned char packet_type;
3372  multiple->type = type;
3373  multiple->flags = 0;
3374 
3376  return TDS_FAIL;
3377 
3378  packet_type = TDS_QUERY;
3379  switch (type) {
3380  case TDS_MULTIPLE_QUERY:
3381  break;
3382  case TDS_MULTIPLE_EXECUTE:
3383  case TDS_MULTIPLE_RPC:
3384  if (IS_TDS7_PLUS(tds->conn))
3385  packet_type = TDS_RPC;
3386  break;
3387  }
3388  if (tds_start_query_head(tds, packet_type, head) != TDS_SUCCESS)
3389  return TDS_FAIL;
3390 
3391  return TDS_SUCCESS;
3392 }
3393 
3394 TDSRET
3396 {
3397  assert(tds && multiple);
3398 
3399  return tds_query_flush_packet(tds);
3400 }
3401 
3402 TDSRET
3403 tds_multiple_query(TDSSOCKET *tds, TDSMULTIPLE *multiple, const char *query, TDSPARAMINFO * params)
3404 {
3405  assert(multiple->type == TDS_MULTIPLE_QUERY);
3406 
3407  if (multiple->flags & MUL_STARTED)
3408  tds_put_string(tds, " ", 1);
3409  multiple->flags |= MUL_STARTED;
3410 
3411  return tds_send_emulated_execute(tds, query, params);
3412 }
3413 
3414 TDSRET
3416 {
3417  assert(multiple->type == TDS_MULTIPLE_EXECUTE);
3418 
3419  if (IS_TDS7_PLUS(tds->conn)) {
3420  if (multiple->flags & MUL_STARTED) {
3421  /* TODO define constant */
3422  tds_put_byte(tds, IS_TDS72_PLUS(tds->conn) ? 0xff : 0x80);
3423  }
3424  multiple->flags |= MUL_STARTED;
3425 
3426  tds7_send_execute(tds, dyn);
3427 
3428  return TDS_SUCCESS;
3429  }
3430 
3431  if (multiple->flags & MUL_STARTED)
3432  tds_put_string(tds, " ", 1);
3433  multiple->flags |= MUL_STARTED;
3434 
3435  return tds_send_emulated_execute(tds, dyn->query, dyn->params);
3436 }
3437 
3438 /**
3439  * Send option commands to server.
3440  * Option commands are used to change server options.
3441  * \tds
3442  * \param command command type.
3443  * \param option option to set/get.
3444  * \param param parameter value
3445  * \param param_size length of parameter value in bytes
3446  */
3447 TDSRET
3449 {
3450  char cmd[128];
3451 
3453 
3454  tdsdump_log(TDS_DBG_FUNC, "tds_submit_optioncmd() \n");
3455 
3456  if (IS_TDS50(tds->conn)) {
3458  return TDS_FAIL;
3459 
3460  tds->out_flag = TDS_NORMAL;
3462 
3463  tds_put_smallint(tds, 3 + param_size);
3466  tds_put_byte(tds, param_size);
3467  if (param_size)
3468  tds_put_n(tds, param, param_size);
3469 
3471 
3473  return TDS_SUCCESS;
3474  }
3475 
3476  if (!IS_TDS7_PLUS(tds->conn))
3477  return TDS_SUCCESS;
3478 
3479  cmd[0] = 0;
3480  if (command == TDS_OPT_SET) {
3481  char datefmt[4];
3482 
3483  switch (option) {
3484  case TDS_OPT_ANSINULL :
3485  sprintf(cmd, "SET ANSI_NULLS %s", param->ti ? "ON" : "OFF");
3486  break;
3487  case TDS_OPT_ARITHABORTON :
3488  strcpy(cmd, "SET ARITHABORT ON");
3489  break;
3490  case TDS_OPT_ARITHABORTOFF :
3491  strcpy(cmd, "SET ARITHABORT OFF");
3492  break;
3493  case TDS_OPT_ARITHIGNOREON :
3494  strcpy(cmd, "SET ARITHIGNORE ON");
3495  break;
3496  case TDS_OPT_ARITHIGNOREOFF :
3497  strcpy(cmd, "SET ARITHIGNORE OFF");
3498  break;
3499  case TDS_OPT_CHAINXACTS :
3500  sprintf(cmd, "SET IMPLICIT_TRANSACTIONS %s", param->ti ? "ON" : "OFF");
3501  break;
3502  case TDS_OPT_CURCLOSEONXACT :
3503  sprintf(cmd, "SET CURSOR_CLOSE_ON_COMMIT %s", param->ti ? "ON" : "OFF");
3504  break;
3505  case TDS_OPT_NOCOUNT :
3506  sprintf(cmd, "SET NOCOUNT %s", param->ti ? "ON" : "OFF");
3507  break;
3508  case TDS_OPT_QUOTED_IDENT :
3509  sprintf(cmd, "SET QUOTED_IDENTIFIER %s", param->ti ? "ON" : "OFF");
3510  break;
3511  case TDS_OPT_TRUNCABORT :
3512  sprintf(cmd, "SET ANSI_WARNINGS %s", param->ti ? "OFF" : "ON");
3513  break;
3514  case TDS_OPT_DATEFIRST :
3515  sprintf(cmd, "SET DATEFIRST %d", param->ti);
3516  break;
3517  case TDS_OPT_DATEFORMAT :
3518  switch (param->ti) {
3519  case TDS_OPT_FMTDMY: strcpy(datefmt,"dmy"); break;
3520  case TDS_OPT_FMTDYM: strcpy(datefmt,"dym"); break;
3521  case TDS_OPT_FMTMDY: strcpy(datefmt,"mdy"); break;
3522  case TDS_OPT_FMTMYD: strcpy(datefmt,"myd"); break;
3523  case TDS_OPT_FMTYDM: strcpy(datefmt,"ydm"); break;
3524  case TDS_OPT_FMTYMD: strcpy(datefmt,"ymd"); break;
3525  }
3526  sprintf(cmd, "SET DATEFORMAT %s", datefmt);
3527  break;
3528  case TDS_OPT_TEXTSIZE:
3529  sprintf(cmd, "SET TEXTSIZE %d", (int) param->i);
3530  break;
3531  /* TODO */
3532  case TDS_OPT_STAT_TIME:
3533  case TDS_OPT_STAT_IO:
3534  case TDS_OPT_ROWCOUNT:
3535  case TDS_OPT_NATLANG:
3536  case TDS_OPT_ISOLATION:
3537  case TDS_OPT_AUTHON:
3538  case TDS_OPT_CHARSET:
3539  case TDS_OPT_SHOWPLAN:
3540  case TDS_OPT_NOEXEC:
3541  case TDS_OPT_PARSEONLY:
3542  case TDS_OPT_GETDATA:
3543  case TDS_OPT_FORCEPLAN:
3544  case TDS_OPT_FORMATONLY:
3545  case TDS_OPT_FIPSFLAG:
3546  case TDS_OPT_RESTREES:
3547  case TDS_OPT_IDENTITYON:
3548  case TDS_OPT_CURREAD:
3549  case TDS_OPT_CURWRITE:
3550  case TDS_OPT_IDENTITYOFF:
3551  case TDS_OPT_AUTHOFF:
3552  break;
3553  }
3556  }
3557  if (command == TDS_OPT_LIST) {
3558  int optionval = 0;
3559  TDS_INT resulttype;
3560 
3561  switch (option) {
3562  case TDS_OPT_ANSINULL :
3563  case TDS_OPT_ARITHABORTON :
3564  case TDS_OPT_ARITHABORTOFF :
3565  case TDS_OPT_ARITHIGNOREON :
3566  case TDS_OPT_ARITHIGNOREOFF :
3567  case TDS_OPT_CHAINXACTS :
3568  case TDS_OPT_CURCLOSEONXACT :
3569  case TDS_OPT_NOCOUNT :
3570  case TDS_OPT_QUOTED_IDENT :
3571  case TDS_OPT_TRUNCABORT :
3572  tdsdump_log(TDS_DBG_FUNC, "SELECT @@options\n");
3573  strcpy(cmd, "SELECT @@options");
3574  break;
3575  case TDS_OPT_DATEFIRST :
3576  strcpy(cmd, "SELECT @@datefirst");
3577  break;
3578  case TDS_OPT_DATEFORMAT :
3579  strcpy(cmd, "SELECT DATEPART(dy,'01/02/03')");
3580  break;
3581  case TDS_OPT_TEXTSIZE:
3582  strcpy(cmd, "SELECT @@textsize");
3583  break;
3584  /* TODO */
3585  case TDS_OPT_STAT_TIME:
3586  case TDS_OPT_STAT_IO:
3587  case TDS_OPT_ROWCOUNT:
3588  case TDS_OPT_NATLANG:
3589  case TDS_OPT_ISOLATION:
3590  case TDS_OPT_AUTHON:
3591  case TDS_OPT_CHARSET:
3592  case TDS_OPT_SHOWPLAN:
3593  case TDS_OPT_NOEXEC:
3594  case TDS_OPT_PARSEONLY:
3595  case TDS_OPT_GETDATA:
3596  case TDS_OPT_FORCEPLAN:
3597  case TDS_OPT_FORMATONLY:
3598  case TDS_OPT_FIPSFLAG:
3599  case TDS_OPT_RESTREES:
3600  case TDS_OPT_IDENTITYON:
3601  case TDS_OPT_CURREAD:
3602  case TDS_OPT_CURWRITE:
3603  case TDS_OPT_IDENTITYOFF:
3604  case TDS_OPT_AUTHOFF:
3605  default:
3606  tdsdump_log(TDS_DBG_FUNC, "what!\n");
3607  }
3609  while (tds_process_tokens(tds, &resulttype, NULL, TDS_TOKEN_RESULTS) == TDS_SUCCESS) {
3610  switch (resulttype) {
3611  case TDS_ROWFMT_RESULT:
3612  break;
3613  case TDS_ROW_RESULT:
3615  TDSCOLUMN *col;
3616  CONV_RESULT dres;
3617  int ctype;
3618  unsigned char* src;
3619  int srclen;
3620 
3621  if (resulttype != TDS_ROW_RESULT)
3622  break;
3623 
3624  if (!tds->current_results)
3625  continue;
3626 
3627  col = tds->current_results->columns[0];
3629 
3630  src = col->column_data;
3631  srclen = col->column_cur_size;
3632 
3633 
3634  tds_convert(tds_get_ctx(tds), ctype, src, srclen, SYBINT4, &dres);
3635  optionval = dres.i;
3636  }
3637  break;
3638  default:
3639  break;
3640  }
3641  }
3642  tdsdump_log(TDS_DBG_FUNC, "optionval = %d\n", optionval);
3643  switch (option) {
3644  case TDS_OPT_CHAINXACTS :
3645  tds->option_value = (optionval & 0x02) > 0;
3646  break;
3647  case TDS_OPT_CURCLOSEONXACT :
3648  tds->option_value = (optionval & 0x04) > 0;
3649  break;
3650  case TDS_OPT_TRUNCABORT :
3651  tds->option_value = (optionval & 0x08) > 0;
3652  break;
3653  case TDS_OPT_ANSINULL :
3654  tds->option_value = (optionval & 0x20) > 0;
3655  break;
3656  case TDS_OPT_ARITHABORTON :
3657  tds->option_value = (optionval & 0x40) > 0;
3658  break;
3659  case TDS_OPT_ARITHABORTOFF :
3660  tds->option_value = (optionval & 0x40) > 0;
3661  break;
3662  case TDS_OPT_ARITHIGNOREON :
3663  tds->option_value = (optionval & 0x80) > 0;
3664  break;
3665  case TDS_OPT_ARITHIGNOREOFF :
3666  tds->option_value = (optionval & 0x80) > 0;
3667  break;
3668  case TDS_OPT_QUOTED_IDENT :
3669  tds->option_value = (optionval & 0x0100) > 0;
3670  break;
3671  case TDS_OPT_NOCOUNT :
3672  tds->option_value = (optionval & 0x0200) > 0;
3673  break;
3674  case TDS_OPT_TEXTSIZE:
3675  case TDS_OPT_DATEFIRST :
3676  tds->option_value = optionval;
3677  break;
3678  case TDS_OPT_DATEFORMAT :
3679  switch (optionval) {
3680  case 61: tds->option_value = TDS_OPT_FMTYDM; break;
3681  case 34: tds->option_value = TDS_OPT_FMTYMD; break;
3682  case 32: tds->option_value = TDS_OPT_FMTDMY; break;
3683  case 60: tds->option_value = TDS_OPT_FMTYDM; break;
3684  case 2: tds->option_value = TDS_OPT_FMTMDY; break;
3685  case 3: tds->option_value = TDS_OPT_FMTMYD; break;
3686  }
3687  break;
3688  /* TODO */
3689  case TDS_OPT_STAT_TIME:
3690  case TDS_OPT_STAT_IO:
3691  case TDS_OPT_ROWCOUNT:
3692  case TDS_OPT_NATLANG:
3693  case TDS_OPT_ISOLATION:
3694  case TDS_OPT_AUTHON:
3695  case TDS_OPT_CHARSET:
3696  case TDS_OPT_SHOWPLAN:
3697  case TDS_OPT_NOEXEC:
3698  case TDS_OPT_PARSEONLY:
3699  case TDS_OPT_GETDATA:
3700  case TDS_OPT_FORCEPLAN:
3701  case TDS_OPT_FORMATONLY:
3702  case TDS_OPT_FIPSFLAG:
3703  case TDS_OPT_RESTREES:
3704  case TDS_OPT_IDENTITYON:
3705  case TDS_OPT_CURREAD:
3706  case TDS_OPT_CURWRITE:
3707  case TDS_OPT_IDENTITYOFF:
3708  case TDS_OPT_AUTHOFF:
3709  break;
3710  }
3711  tdsdump_log(TDS_DBG_FUNC, "tds_submit_optioncmd: returned option_value = %d\n", tds->option_value);
3712  }
3713  return TDS_SUCCESS;
3714 }
3715 
3716 
3717 /**
3718  * Send a rollback request.
3719  * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
3720  * \tds
3721  * \sa tds_submit_commit, tds_submit_rollback
3722  */
3723 TDSRET
3725 {
3727 
3728  if (!IS_TDS72_PLUS(tds->conn))
3729  return tds_submit_query(tds, "BEGIN TRANSACTION");
3730 
3732  return TDS_FAIL;
3733 
3735 
3736  /* begin transaction */
3737  tds_put_smallint(tds, 5);
3738  tds_put_byte(tds, 0); /* new transaction level TODO */
3739  tds_put_byte(tds, 0); /* new transaction name */
3740 
3741  return tds_query_flush_packet(tds);
3742 }
3743 
3744 /**
3745  * Send a rollback request.
3746  * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
3747  * \tds
3748  * \param cont true to start a new transaction
3749  * \sa tds_submit_begin_tran, tds_submit_commit
3750  */
3751 TDSRET
3753 {
3755 
3756  if (!IS_TDS72_PLUS(tds->conn))
3757  return tds_submit_query(tds, cont ? "IF @@TRANCOUNT > 0 ROLLBACK BEGIN TRANSACTION" : "IF @@TRANCOUNT > 0 ROLLBACK");
3758 
3760  return TDS_FAIL;
3761 
3763  tds_put_smallint(tds, 8); /* rollback */
3764  tds_put_byte(tds, 0); /* name */
3765  if (cont) {
3766  tds_put_byte(tds, 1);
3767  tds_put_byte(tds, 0); /* new transaction level TODO */
3768  tds_put_byte(tds, 0); /* new transaction name */
3769  } else {
3770  tds_put_byte(tds, 0); /* do not continue */
3771  }
3772  return tds_query_flush_packet(tds);
3773 }
3774 
3775 /**
3776  * Send a commit request.
3777  * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
3778  * \tds
3779  * \param cont true to start a new transaction
3780  * \sa tds_submit_rollback, tds_submit_begin_tran
3781  */
3782 TDSRET
3784 {
3786 
3787  if (!IS_TDS72_PLUS(tds->conn))
3788  return tds_submit_query(tds, cont ? "IF @@TRANCOUNT > 0 COMMIT BEGIN TRANSACTION" : "IF @@TRANCOUNT > 0 COMMIT");
3789 
3791  return TDS_FAIL;
3792 
3794  tds_put_smallint(tds, 7); /* commit */
3795  tds_put_byte(tds, 0); /* name */
3796  if (cont) {
3797  tds_put_byte(tds, 1);
3798  tds_put_byte(tds, 0); /* new transaction level TODO */
3799  tds_put_byte(tds, 0); /* new transaction name */
3800  } else {
3801  tds_put_byte(tds, 0); /* do not continue */
3802  }
3803  return tds_query_flush_packet(tds);
3804 }
3805 
3806 static const TDSCONTEXT empty_ctx = {0};
3807 
3808 TDSRET
3810 {
3811  TDS_INT old_timeout;
3812  const TDSCONTEXT *old_ctx;
3813 
3815 
3816  tdsdump_log(TDS_DBG_FUNC, "tds_disconnect() \n");
3817 
3818  if (!IS_TDS50(tds->conn))
3819  return TDS_SUCCESS;
3820 
3821  old_timeout = tds->query_timeout;
3822  old_ctx = tds_get_ctx(tds);
3823 
3824  /* avoid to stall forever */
3825  tds->query_timeout = 5;
3826 
3827  /* do not report errors to upper libraries */
3829 
3831  tds->query_timeout = old_timeout;
3832  tds_set_ctx(tds, old_ctx);
3833  return TDS_FAIL;
3834  }
3835 
3836  tds->out_flag = TDS_NORMAL;
3838  tds_put_byte(tds, 0);
3839 
3841 
3842  return tds_process_simple_query(tds);
3843 }
3844 
3845 /*
3846  * TODO add function to return type suitable for param
3847  * ie:
3848  * sybvarchar -> sybvarchar / xsybvarchar
3849  * sybint4 -> sybintn
3850  */
3851 
3852 /** @} */
#define head
Definition: ct_nlmzip_i.h:138
static uch flags
std::ofstream out("events_result.xml")
main entry point for tests
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static int failure
Definition: t0019.c:11
#define TDS_HOST2LE(val)
Definition: bytes.h:153
#define CHECK_COLUMN_EXTRA(column)
Definition: checks.h:34
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
#define CHECK_CURSOR_EXTRA(cursor)
Definition: checks.h:37
#define CHECK_CONN_EXTRA(conn)
Definition: checks.h:39
#define CHECK_DYNAMIC_EXTRA(dynamic)
Definition: checks.h:38
#define CHECK_PARAMINFO_EXTRA(res_info)
Definition: checks.h:36
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
@ TDS_REQ_WIDETABLE
Definition: enum_cap.h:59
@ TDS_REQ_PROTO_DYNPROC
Definition: enum_cap.h:49
@ to_server
Definition: iconv.h:70
#define TDS_ENCODING_MEMCPY
Definition: iconv.h:95
#define TDS_SP_CURSOROPEN
Definition: proto.h:140
#define TDS_SP_PREPEXEC
Definition: proto.h:151
TDS_OPTION_CMD
options that can be sent with a TDS_OPTIONCMD token
Definition: proto.h:263
@ TDS_OPT_LIST
Request current setting of a specific option.
Definition: proto.h:266
@ TDS_OPT_SET
Set an option.
Definition: proto.h:264
#define TDS_CUROPEN_TOKEN
Definition: proto.h:122
@ TDS_CANCEL
Definition: proto.h:337
@ TDS_RPC
Definition: proto.h:335
@ TDS_QUERY
Definition: proto.h:333
@ TDS_NORMAL
Definition: proto.h:340
@ TDS7_TRANS
Definition: proto.h:339
#define TDS_CURINFO_TOKEN
Definition: proto.h:121
#define TDS_LOGOUT_TOKEN
Definition: proto.h:80
#define TDS_CURFETCH_TOKEN
Definition: proto.h:120
#define TDS_SP_UNPREPARE
Definition: proto.h:153
#define TDS_SP_CURSORCLOSE
Definition: proto.h:147
@ SYBVARIANT
Definition: proto.h:200
@ SYBUINT8
Definition: proto.h:215
@ SYBLONGBINARY
Definition: proto.h:211
@ SYBUNIQUE
Definition: proto.h:199
@ XSYBNVARCHAR
Definition: proto.h:195
@ XSYBCHAR
Definition: proto.h:193
@ SYBUINT2
Definition: proto.h:213
@ XSYBVARCHAR
Definition: proto.h:194
@ SYBUINT4
Definition: proto.h:214
@ SYBSINT1
Definition: proto.h:224
@ XSYBVARBINARY
Definition: proto.h:197
@ XSYBNCHAR
Definition: proto.h:196
@ SYB5BIGTIME
Definition: proto.h:231
@ XSYBBINARY
Definition: proto.h:198
@ SYB5BIGDATETIME
Definition: proto.h:230
@ SYBUINT1
Definition: proto.h:212
#define TDS5_PARAMFMT_TOKEN
Definition: proto.h:110
@ TDS_DYN_DEALLOC
Definition: proto.h:440
@ TDS_DYN_PREPARE
Definition: proto.h:438
@ TDS_DYN_EXEC_IMMED
Definition: proto.h:441
#define TDS_SP_CURSOR
Definition: proto.h:139
#define TDS_OPTIONCMD_TOKEN
Definition: proto.h:90
#define TDS_LANGUAGE_TOKEN
Definition: proto.h:76
#define TDS5_PARAMS_TOKEN
Definition: proto.h:103
TDS_OPTION
Definition: proto.h:271
@ TDS_OPT_ROWCOUNT
Definition: proto.h:276
@ TDS_OPT_AUTHOFF
Definition: proto.h:299
@ TDS_OPT_CHARSET
Definition: proto.h:281
@ TDS_OPT_DATEFORMAT
Definition: proto.h:278
@ TDS_OPT_PARSEONLY
Definition: proto.h:286
@ TDS_OPT_CHAINXACTS
Definition: proto.h:291
@ TDS_OPT_CURWRITE
Definition: proto.h:297
@ TDS_OPT_NATLANG
Definition: proto.h:277
@ TDS_OPT_STAT_IO
Definition: proto.h:275
@ TDS_OPT_DATEFIRST
Definition: proto.h:272
@ TDS_OPT_TEXTSIZE
Definition: proto.h:273
@ TDS_OPT_GETDATA
Definition: proto.h:287
@ TDS_OPT_FIPSFLAG
Definition: proto.h:293
@ TDS_OPT_ARITHABORTON
Definition: proto.h:285
@ TDS_OPT_ARITHIGNOREON
Definition: proto.h:284
@ TDS_OPT_FORMATONLY
Definition: proto.h:290
@ TDS_OPT_FORCEPLAN
Definition: proto.h:289
@ TDS_OPT_CURCLOSEONXACT
Definition: proto.h:292
@ TDS_OPT_ANSINULL
Definition: proto.h:300
@ TDS_OPT_IDENTITYOFF
Definition: proto.h:298
@ TDS_OPT_ARITHIGNOREOFF
Definition: proto.h:302
@ TDS_OPT_STAT_TIME
Definition: proto.h:274
@ TDS_OPT_TRUNCABORT
Definition: proto.h:304
@ TDS_OPT_QUOTED_IDENT
Definition: proto.h:301
@ TDS_OPT_IDENTITYON
Definition: proto.h:295
@ TDS_OPT_RESTREES
Definition: proto.h:294
@ TDS_OPT_NOEXEC
Definition: proto.h:283
@ TDS_OPT_ISOLATION
Definition: proto.h:279
@ TDS_OPT_ARITHABORTOFF
Definition: proto.h:303
@ TDS_OPT_AUTHON
Definition: proto.h:280
@ TDS_OPT_NOCOUNT
Definition: proto.h:288
@ TDS_OPT_SHOWPLAN
Definition: proto.h:282
@ TDS_OPT_CURREAD
Definition: proto.h:296
#define TDS5_DYNAMIC_TOKEN
Definition: proto.h:109
#define TDS5_PARAMFMT2_TOKEN
Definition: proto.h:75
#define TDS_DBRPC_TOKEN
Definition: proto.h:108
#define TDS_CURCLOSE_TOKEN
Definition: proto.h:118
@ USER_UNICHAR_TYPE
Definition: proto.h:237
@ USER_UNIVARCHAR_TYPE
Definition: proto.h:238
#define TDS_SP_PREPARE
Definition: proto.h:149
@ TDS_OPT_FMTMYD
Definition: proto.h:320
@ TDS_OPT_FMTDMY
Definition: proto.h:320
@ TDS_OPT_FMTDYM
Definition: proto.h:320
@ TDS_OPT_FMTYMD
Definition: proto.h:320
@ TDS_OPT_FMTMDY
Definition: proto.h:320
@ TDS_OPT_FMTYDM
Definition: proto.h:320
#define TDS_SP_CURSORFETCH
Definition: proto.h:145
#define TDS_SP_CURSOROPTION
Definition: proto.h:146
#define TDS_CURDECLARE_TOKEN
Definition: proto.h:123
#define TDS_SP_EXECUTESQL
Definition: proto.h:148
#define TDS_FAIL
Definition: tds.h:204
#define TDS_WUR
Definition: tds.h:398
#define TDS_IS_MSSQL(x)
Check if product is Microsft SQL Server.
Definition: tds.h:1722
#define tds_new(type, n)
Definition: tds.h:1392
#define TDS_FAILED(rc)
Definition: tds.h:206
@ TDS_OP_CURSORFETCH
Definition: tds.h:882
@ TDS_OP_EXECUTESQL
Definition: tds.h:885
@ TDS_OP_DYN_DEALLOC
Definition: tds.h:893
@ TDS_OP_CURSOROPEN
Definition: tds.h:877
@ TDS_OP_PREPEXEC
Definition: tds.h:888
@ TDS_OP_UNPREPARE
Definition: tds.h:890
@ TDS_OP_CURSORCLOSE
Definition: tds.h:884
@ TDS_OP_CURSOROPTION
Definition: tds.h:883
@ TDS_OP_CURSOR
Definition: tds.h:876
@ TDS_OP_NONE
Definition: tds.h:873
@ TDS_OP_PREPARE
Definition: tds.h:886
@ TDS_OP_EXECUTE
Definition: tds.h:887
#define IS_TDS71_PLUS(x)
Definition: tds.h:1709
#define IS_TDS50_PLUS(x)
Definition: tds.h:1707
enum tds_cursor_operation TDS_CURSOR_OPERATION
#define TDS_ROWFMT_RESULT
Definition: tds.h:224
#define tds_capability_has_req(conn, cap)
Definition: tds.h:1696
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define tds_set_ctx(tds, val)
Definition: tds.h:1295
@ TDS_RETURN_ROW
Definition: tds.h:256
@ TDS_STOPAT_ROWFMT
Definition: tds.h:252
@ TDS_TOKEN_RESULTS
Definition: tds.h:261
@ TDS_RETURN_PROC
Definition: tds.h:258
@ TDS_RETURN_DONE
Definition: tds.h:255
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
#define tdsdump_log
Definition: tds.h:1561
@ TDS_CURSOR_UPDATE
Definition: tds.h:988
#define TDS_DBG_INFO1
Definition: tds.h:900
#define TDS_PUT_BYTE(tds, v)
Definition: tds.h:1744
static void tds_release_cur_dyn(TDSSOCKET *tds)
Definition: tds.h:1366
#define TDS_NO_MORE_RESULTS
Definition: tds.h:202
#define IS_TDS50(x)
Definition: tds.h:1701
#define is_blob_type(x)
Definition: tds.h:443
#define is_unicode_type(x)
Definition: tds.h:457
#define is_blob_col(x)
Definition: tds.h:445
#define IS_TDS72_PLUS(x)
Definition: tds.h:1710
@ TDS_CURSOR_FETCH_RELATIVE
Definition: tds.h:1000
@ TDS_CURSOR_FETCH_ABSOLUTE
Definition: tds.h:999
@ TDS_CURSOR_STATE_REQUESTED
Definition: tds.h:970
@ TDS_CURSOR_STATE_SENT
Definition: tds.h:971
#define TDS_PARAM_RESULT
Definition: tds.h:217
unsigned char TDS_TINYINT
Definition: tds.h:146
@ TDS_PENDING
cilent is waiting for data
Definition: tds.h:866
@ TDS_WRITING
client is writing data
Definition: tds.h:864
@ TDS_IDLE
no data expected
Definition: tds.h:863
#define tds_convert_string_free(original, converted)
Definition: tds.h:1452
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
#define tds_new0(type, n)
Definition: tds.h:1393
#define is_char_type(x)
Definition: tds.h:460
char TDS_CHAR
Definition: tds.h:144
#define TDS_ROW_RESULT
Definition: tds.h:216
@ TDS_DONE_ERROR
error occurred
Definition: tds.h:272
@ TDS_DONE_COUNT
count field in packet is valid
Definition: tds.h:275
int TDSRET
Definition: tds.h:201
#define TDS_DBG_ERROR
Definition: tds.h:903
#define TDS_SUCCESS
Definition: tds.h:203
#define TDS_RESIZE(p, n_elem)
Definition: tds.h:1390
enum tds_cursor_fetch TDS_CURSOR_FETCH
#define TDS_SYB_VER(maj, min, x)
Calc a version number for Sybase.
Definition: tds.h:1731
#define TDS_PUT_INT(tds, v)
Definition: tds.h:1742
TDS_MULTIPLE_TYPE
Definition: tds.h:1082
@ TDS_MULTIPLE_EXECUTE
Definition: tds.h:1084
@ TDS_MULTIPLE_RPC
Definition: tds.h:1085
@ TDS_MULTIPLE_QUERY
Definition: tds.h:1083
#define TDS_SUCCEED(rc)
Definition: tds.h:207
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
#define tds_put_tinyint(tds, ti)
Output a tinyint value.
Definition: tds.h:1504
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define tds_get_ctx(tds)
Definition: tds.h:1294
#define TDS_PUT_SMALLINT(tds, v)
Definition: tds.h:1743
#define TDS_DBG_FUNC
Definition: tds.h:898
@ TDS_CUR_ISTAT_ROWCNT
Definition: tds.h:339
@ TDS_CUR_ISTAT_UNUSED
Definition: tds.h:333
@ TDS_CUR_ISTAT_CLOSED
Definition: tds.h:336
@ TDS_CUR_ISTAT_DEALLOC
Definition: tds.h:340
@ TDS_CUR_ISTAT_RDONLY
Definition: tds.h:337
@ TDS_CUR_ISTAT_DECLARED
Definition: tds.h:334
#define tds_mutex_trylock(x)
Definition: thread.h:422
#define tds_mutex_unlock(x)
Definition: thread.h:423
static const char table_name[]
Definition: bcp.c:249
static int type
Definition: getdata.c:31
static const char * str(char *buf, int n)
Definition: stats.c:84
#define vasprintf
Definition: replacements.h:60
#define SYBMSDATE
Definition: sybdb.h:222
#define SYBVOID
Definition: sybdb.h:198
#define SYBINT4
Definition: sybdb.h:170
#define SYBNUMERIC
Definition: sybdb.h:202
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBTEXT
Definition: sybdb.h:182
#define SYBNVARCHAR
Definition: sybdb.h:212
#define SYBDATE
Definition: sybdb.h:214
#define SYBINT8
Definition: sybdb.h:172
#define SYBMONEYN
Definition: sybdb.h:208
#define SYBMSDATETIME2
Definition: sybdb.h:226
#define SYBNTEXT
Definition: sybdb.h:184
#define SYBIMAGE
Definition: sybdb.h:186
#define SYBINTN
Definition: sybdb.h:164
#define SYBMSDATETIMEOFFSET
Definition: sybdb.h:228
#define SYBINT1
Definition: sybdb.h:166
#define SYBDATETIME4
Definition: sybdb.h:192
#define SYBDECIMAL
Definition: sybdb.h:204
#define SYBCHAR
Definition: sybdb.h:160
#define SYBREAL
Definition: sybdb.h:194
#define SYBDATETIMN
Definition: sybdb.h:210
#define SYBBITN
Definition: sybdb.h:180
#define SYBBINARY
Definition: sybdb.h:196
#define SYBTIME
Definition: sybdb.h:216
#define SYBMSTIME
Definition: sybdb.h:224
#define SYBDATETIME
Definition: sybdb.h:176
#define SYBVARBINARY
Definition: sybdb.h:200
#define SYBMONEY
Definition: sybdb.h:190
#define SYBMONEY4
Definition: sybdb.h:188
#define SYBFLT8
Definition: sybdb.h:174
#define SYBFLTN
Definition: sybdb.h:206
#define SYBINT2
Definition: sybdb.h:168
#define SYBBIT
Definition: sybdb.h:178
#define option
static TDSSOCKET * tds
Definition: collations.c:37
#define tds_put_string
#define tds_put_n
#define tds_hex_digits
#define tds_staticin_stream_init
#define tds_convert_stream
#define tds_alloc_dynamic
#define tds_iconv
#define tds_put_int
#define tds_release_dynamic
#define tds_put_smallint
#define tds_dynamic_deallocated
#define tds_release_cursor
#define tds_process_simple_query
#define tds_flush_packet
#define tds_cursor_deallocated
#define tds_set_state
#define tds_wakeup_send
#define tds_put_byte
#define tds_get_conversion_type
#define tds_put_cancel
#define tds_convert
#define tds_process_tokens
TDSICONV * tds_iconv_get_info(TDSCONNECTION *conn, int canonic_client, int canonic_server)
Get a iconv info structure, allocate and initialize if needed.
Definition: iconv.c:769
@ USER_VARCHAR_TYPE
Definition: proto.h:239
@ USER_CHAR_TYPE
Definition: proto.h:238
@ USER_NVARCHAR_TYPE
Definition: proto.h:242
@ USER_UNITEXT_TYPE
Definition: proto.h:245
@ USER_SYSNAME_TYPE
Definition: proto.h:240
@ USER_NCHAR_TYPE
Definition: proto.h:241
#define TDS_PROPAGATE(rc)
Definition: tds.h:203
#define TDS_END_LEN
Definition: tds.h:1671
#define TDS_START_LEN_UINT(tds_socket)
Definition: tds.h:1675
#define TDS_START_LEN_USMALLINT(tds_socket)
Definition: tds.h:1674
#define TDS_START_LEN_TINYINT(tds_socket)
Definition: tds.h:1673
#define TDS_PUT_DATA_USE_NAME
Definition: query.c:61
#define TDS_PUT_DATA_LONG_STATUS
Definition: query.c:63
#define MIN(a, b)
Definition: query.c:66
#define TDS_PUT_DATA_PREFIX_NAME
Definition: query.c:62
#define QUOTE(type, ch)
#define MAX(a, b)
Definition: query.c:68
static TDSRET tds_send_emulated_execute(TDSSOCKET *tds, const char *query, TDSPARAMINFO *params)
Emulate prepared execute traslating to a normal language.
Definition: query.c:3328
static TDSRET tds7_send_execute(TDSSOCKET *tds, TDSDYNAMIC *dyn)
Send dynamic request on TDS 7+ to be executed \tds.
Definition: query.c:1653
static int tds_count_placeholders_ucs2le(const char *query, const char *query_end)
Count the number of placeholders ('?') in a query.
Definition: query.c:697
static TDSRET tds_put_param_as_string(TDSSOCKET *tds, TDSPARAMINFO *params, int n)
Send a parameter to server.
Definition: query.c:3248
static const char * tds_skip_quoted_ucs2le(const char *s, const char *end)
Return pointer to end of a quoted string.
Definition: query.c:623
static void tds_quote_and_put(TDSSOCKET *tds, const char *s, const char *end)
Send a string to server while quoting it.
Definition: query.c:3138
static bool tds_cursor_check_allocated(TDSCONNECTION *conn, TDSCURSOR *cursor)
Check if a cursor is allocated into the server.
Definition: query.c:3050
static void tds_set_cur_cursor(TDSSOCKET *tds, TDSCURSOR *cursor)
Set current cursor.
Definition: query.c:2311
static char * tds5_fix_dot_query(const char *query, size_t *query_len, TDSPARAMINFO *params)
Substitute ?-style placeholders with named (@param) ones.
Definition: query.c:230
static void tds7_put_cursor_fetch(TDSSOCKET *tds, TDS_INT cursor_id, TDS_TINYINT fetch_type, TDS_INT i_row, TDS_INT num_rows)
Definition: query.c:2559
static void tds7_put_query_params(TDSSOCKET *tds, const char *query, size_t query_len)
Output params types and query (required by sp_prepare/sp_executesql/sp_prepexec)
Definition: query.c:1120
static TDSRET tds_start_query_head(TDSSOCKET *tds, unsigned char packet_type, TDSHEADERS *head)
Start query packet of a given type \tds.
Definition: query.c:294
static TDSRET tds_put_data(TDSSOCKET *tds, TDSCOLUMN *curcol)
Write data to wire \tds.
Definition: query.c:282
static const char * tds_next_placeholder_ucs2le(const char *start, const char *end, int named)
Found the next placeholder (? or @param) in a string.
Definition: query.c:649
static const char * tds_skip_comment_ucs2le(const char *s, const char *end)
Skip a comment in a query.
Definition: query.c:594
static size_t tds_ascii_to_ucs2(char *buffer, const char *buf)
Accept an ASCII string, convert it to UCS2-LE The input is NUL-terminated, but the output does not co...
Definition: query.c:91
static TDSRET tds_query_flush_packet(TDSSOCKET *tds)
Flush query packet.
Definition: query.c:181
static TDSRET tds_put_data_info(TDSSOCKET *tds, TDSCOLUMN *curcol, int flags)
Put data information to wire.
Definition: query.c:1593
Uint2 uint16_t
#define tds_freeze_written
#define tds_freeze_close
#define tds_freeze
#define tds_freeze_abort
#define tds_freeze_close_len
#define NULL
Definition: ncbistd.hpp:225
static const char * tds_dstr_cstr(DSTR *s)
Returns a C version (NUL terminated string) of dstr.
Definition: string.h:66
DSTR * tds_dstr_copy(DSTR *s, const char *src) TDS_WUR
copy a string from another
Definition: tdsstring.c:123
static int tds_dstr_isempty(DSTR *s)
test if string is empty
Definition: string.h:48
static size_t tds_dstr_len(DSTR *s)
Returns the length of the string in bytes.
Definition: string.h:73
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
size_t tds_quote_id_rpc(TDSSOCKET *tds, char *buffer, const char *id, ssize_t idlen)
Quote an id for a RPC call.
Definition: query.c:2274
int tds_needs_unprepare(TDSCONNECTION *conn, TDSDYNAMIC *dyn)
Check if dynamic request must be unprepared.
Definition: query.c:1871
TDSRET tds71_submit_prepexec(TDSSOCKET *tds, const char *query, const char *id, TDSDYNAMIC **dyn_out, TDSPARAMINFO *params)
tds71_submit_prepexec() creates a temporary stored procedure in the server.
Definition: query.c:1478
void tds_start_query(TDSSOCKET *tds, unsigned char packet_type)
Start query packet of a given type \tds.
Definition: query.c:351
TDSRET tds_send_cancel(TDSSOCKET *tds)
tds_send_cancel() sends an empty packet (8 byte header only) tds_process_cancel should be called dire...
Definition: query.c:2159
static TDSRET tds7_write_param_def_from_query(TDSSOCKET *tds, const char *converted_query, size_t converted_query_len, TDSPARAMINFO *params) TDS_WUR
Write string with parameters definition, useful for TDS7+.
Definition: query.c:958
TDSRET tds_multiple_query(TDSSOCKET *tds, TDSMULTIPLE *multiple, const char *query, TDSPARAMINFO *params)
Definition: query.c:3410
TDSRET tds_cursor_get_cursor_info(TDSSOCKET *tds, TDSCURSOR *cursor, TDS_UINT *prow_number, TDS_UINT *prow_count)
Definition: query.c:2738
static TDSRET tds4_send_emulated_rpc(TDSSOCKET *tds, const char *rpc_name, TDSPARAMINFO *params)
Send RPC as string query.
Definition: query.c:1933
TDSRET tds_disconnect(TDSSOCKET *tds)
Definition: query.c:3823
TDSRET tds_submit_execute(TDSSOCKET *tds, TDSDYNAMIC *dyn)
tds_submit_execute() sends a previously prepared dynamic statement to the server.
Definition: query.c:1753
size_t tds_fix_column_size(TDSSOCKET *tds, TDSCOLUMN *curcol)
Get column size for wire.
Definition: query.c:1573
static TDSRET tds5_put_params(TDSSOCKET *tds, TDSPARAMINFO *info, int flags) TDS_WUR
Send parameters to server.
Definition: query.c:1753
TDSRET tds_get_column_declaration(TDSSOCKET *tds, TDSCOLUMN *curcol, char *out)
Return declaration for column (like "varchar(20)") \tds.
Definition: query.c:743
TDSRET tds_submit_commit(TDSSOCKET *tds, int cont)
Send a commit request.
Definition: query.c:3797
TDSRET tds_deferred_cursor_dealloc(TDSCONNECTION *conn, TDSCURSOR *cursor)
Deallocate cursor on idle.
Definition: query.c:3168
TDSRET tds_submit_query(TDSSOCKET *tds, const char *query)
tds_submit_query() sends a language string to the database server for processing.
Definition: query.c:212
const char * tds_skip_quoted(const char *s)
Skip quoting string (like 'sfsf', "dflkdj" or [dfkjd])
Definition: query.c:548
</