NCBI C++ ToolKit
token.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) 2005-2015 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 /**
22  * \file
23  * \brief Contains all routines to get replies from server
24  */
25 #include <config.h>
26 
27 #if HAVE_STRING_H
28 #include <string.h>
29 #endif /* HAVE_STRING_H */
30 
31 #if HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif /* HAVE_STDLIB_H */
34 
35 #include <assert.h>
36 
37 #if HAVE_MALLOC_H
38 #include <malloc.h>
39 #endif /* HAVE_MALLOC_H */
40 
41 #include <freetds/tds.h>
42 #include <freetds/string.h>
43 #include <freetds/convert.h>
44 #include <freetds/iconv.h>
45 #include <freetds/checks.h>
46 #include <freetds/bytes.h>
47 #include <freetds/alloca.h>
48 #include "replacements.h"
49 
50 /** \cond HIDDEN_SYMBOLS */
51 #define USE_ICONV (tds->conn->use_iconv)
52 
53 #define TDS_GET_COLUMN_TYPE(col) do { \
54  TDS_TINYINT _tds_type = tds_get_byte(tds); \
55  if (!is_tds_type_valid(_tds_type)) \
56  return TDS_FAIL; \
57  tds_set_column_type(tds->conn, col, (TDS_SERVER_TYPE) _tds_type); \
58 } while(0)
59 
60 #define TDS_GET_COLUMN_INFO(tds, col) do { \
61  TDSRET _tds_rc = col->funcs->get_info(tds, col); \
62  if (TDS_FAILED(_tds_rc)) \
63  return _tds_rc; \
64 } while(0)
65 
66 /** \endcond */
67 
68 static TDSRET tds_process_info(TDSSOCKET * tds, int marker);
76 static TDSRET tds_process_colinfo(TDSSOCKET * tds, char **names, int num_names);
92 static TDSRET tds_process_default_tokens(TDSSOCKET * tds, int marker);
94 static TDSRET tds_process_end(TDSSOCKET * tds, int marker, /*@out@*/ int *flags_parm);
95 
96 static TDSRET tds_get_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int is_param);
97 static /*@observer@*/ const char *tds_token_name(unsigned char marker);
98 static void adjust_character_column_size(TDSSOCKET * tds, TDSCOLUMN * curcol);
99 int determine_adjusted_size(const TDSICONV * char_conv, int size);
100 static /*@observer@*/ const char *tds_pr_op(int op);
101 static int tds_alloc_get_string(TDSSOCKET * tds, /*@special@*/ char **string, size_t len) /*allocates *string*/;
102 
103 /**
104  * \ingroup libtds
105  * \defgroup token Results processing
106  * Handle tokens in packets. Many PDU (packets data unit) contain tokens.
107  * (like result description, rows, data, errors and many other).
108  */
109 
110 
111 /**
112  * \addtogroup token
113  * @{
114  */
115 
116 /**
117  * tds_process_default_tokens() is a catch all function that is called to
118  * process tokens not known to other tds_process_* routines
119  * @tds
120  * @param marker Token type
121  */
122 static TDSRET
124 {
125  int tok_size;
126  int done_flags;
127  TDS_INT ret_status;
128  TDS_CAPABILITY_TYPE *cap;
129 
131 
132  tdsdump_log(TDS_DBG_FUNC, "tds_process_default_tokens() marker is %x(%s)\n", marker, tds_token_name(marker));
133 
134  if (IS_TDSDEAD(tds)) {
135  tdsdump_log(TDS_DBG_FUNC, "leaving tds_process_default_tokens() connection dead\n");
137  return TDS_FAIL;
138  }
139 
140  switch (marker) {
141  case TDS_AUTH_TOKEN:
142  return tds_process_auth(tds);
143  break;
144  case TDS_ENVCHANGE_TOKEN:
145  return tds_process_env_chg(tds);
146  break;
147  case TDS_DONE_TOKEN:
148  case TDS_DONEPROC_TOKEN:
150  return tds_process_end(tds, marker, &done_flags);
151  break;
152  case TDS_PROCID_TOKEN:
153  tds_get_n(tds, NULL, 8);
154  break;
156  ret_status = tds_get_int(tds);
157  marker = tds_peek(tds);
158  if (marker != TDS_PARAM_TOKEN && marker != TDS_DONEPROC_TOKEN
159  && marker != TDS_DONE_TOKEN
160  && marker != TDS5_PARAMFMT_TOKEN)
161  break;
162  tds->has_status = 1;
163  tds->ret_status = ret_status;
164  tdsdump_log(TDS_DBG_INFO1, "tds_process_default_tokens: return status is %d\n", tds->ret_status);
165  break;
166  case TDS_ERROR_TOKEN:
167  case TDS_INFO_TOKEN:
168  case TDS_EED_TOKEN:
169  return tds_process_info(tds, marker);
170  break;
172  tok_size = tds_get_usmallint(tds);
173  cap = tds->conn->capabilities.types;
174  memset(cap, 0, 2*sizeof(*cap));
175  cap[0].type = 1;
176  cap[0].len = sizeof(cap[0].values);
177  cap[1].type = 2;
178  cap[1].len = sizeof(cap[1].values);
179  while (tok_size > 1) {
180  unsigned char type, size, *p;
181 
182  type = tds_get_byte(tds);
183  size = tds_get_byte(tds);
184  tok_size -= 2 + size;
185  if (type != 1 && type != 2) {
186  tds_get_n(tds, NULL, size);
187  continue;
188  }
189  if (size > sizeof(cap->values)) {
190  tds_get_n(tds, NULL, size - sizeof(cap->values));
191  size = sizeof(cap->values);
192  }
193  p = (unsigned char *) &cap[type];
194  if (tds_get_n(tds, p-size, size) == NULL)
195  return TDS_FAIL;
196  /*
197  * Sybase 11.0 servers return the wrong length in the capability packet,
198  * causing us to read past the done packet.
199  */
200  if (tds->conn->product_version < TDS_SYB_VER(12, 0, 0) && type == 2)
201  break;
202  }
203  break;
204  /* PARAM_TOKEN can be returned inserting text in db, to return new timestamp */
205  case TDS_PARAM_TOKEN:
208  break;
209  case TDS7_RESULT_TOKEN:
210  return tds7_process_result(tds);
211  break;
212  case TDS_OPTIONCMD_TOKEN:
213  return tds5_process_optioncmd(tds);
214  break;
215  case TDS_RESULT_TOKEN:
216  return tds5_process_result(tds);
217  break;
218  case TDS_ROWFMT2_TOKEN:
219  return tds5_process_result2(tds);
220  break;
221  case TDS_COLNAME_TOKEN:
222  return tds_process_col_name(tds);
223  break;
224  case TDS_COLFMT_TOKEN:
225  return tds_process_col_fmt(tds);
226  break;
227  case TDS_ROW_TOKEN:
228  return tds_process_row(tds);
229  break;
230  case TDS5_PARAMFMT_TOKEN:
231  /* store discarded parameters in param_info, not in old dynamic */
233  return tds_process_dyn_result(tds);
234  break;
238  break;
239  case TDS5_PARAMS_TOKEN:
240  /* save params */
242  break;
243  case TDS_CURINFO_TOKEN:
245  break;
247  if (IS_TDS74_PLUS(tds->conn))
249  /* fall through */
250  case TDS5_DYNAMIC_TOKEN:
251  case TDS_LOGINACK_TOKEN:
252  case TDS_ORDERBY_TOKEN:
253  tdsdump_log(TDS_DBG_WARN, "Eating %s token\n", tds_token_name(marker));
255  break;
256  case TDS_MSG_TOKEN:
257  tok_size = tds_get_byte(tds);
258  if (tok_size >= 3) {
259  tds_get_byte(tds);
261  tok_size -= 3;
262  }
263  tds_get_n(tds, NULL, tok_size);
264  break;
265  case TDS_TABNAME_TOKEN: /* used for FOR BROWSE query */
266  return tds_process_tabname(tds);
267  break;
268  case TDS_COLINFO_TOKEN:
269  return tds_process_colinfo(tds, NULL, 0);
270  break;
272  case TDS_ORDERBY2_TOKEN:
273  tdsdump_log(TDS_DBG_WARN, "Eating %s token\n", tds_token_name(marker));
275  break;
276  case TDS_NBC_ROW_TOKEN:
277  return tds_process_nbcrow(tds);
278  break;
279  default:
282  tdsdump_log(TDS_DBG_ERROR, "Unknown marker: %d(%x)!!\n", marker, (unsigned char) marker);
283  return TDS_FAIL;
284  }
285  return TDS_SUCCESS;
286 }
287 
288 /**
289  * tds_process_login_tokens() is called after sending the login packet
290  * to the server. It returns the success or failure of the login
291  * dependent on the protocol version. 4.2 sends an ACK token only when
292  * successful, TDS 5.0 sends it always with a success byte within
293  * @tds
294  */
295 TDSRET
297 {
298  TDSRET succeed = TDS_FAIL;
299  int marker;
300  unsigned int len;
301  int memrc = 0;
302  unsigned char ack;
303  TDS_UINT product_version;
304 
306 
307  tdsdump_log(TDS_DBG_FUNC, "tds_process_login_tokens()\n");
308  do {
309  struct { unsigned char major, minor, tiny[2];
310  unsigned int reported;
311  const char *name;
312  } ver;
313 
314  marker = tds_get_byte(tds);
315  tdsdump_log(TDS_DBG_FUNC, "looking for login token, got %x(%s)\n", marker, tds_token_name(marker));
316 
317  switch (marker) {
318  case TDS_LOGINACK_TOKEN:
319  /* TODO function */
320  tds->conn->tds71rev1 = 0;
322  if (len < 10)
323  return TDS_FAIL;
324  ack = tds_get_byte(tds);
325 
326  ver.major = tds_get_byte(tds);
327  ver.minor = tds_get_byte(tds);
328  ver.tiny[0] = tds_get_byte(tds);
329  ver.tiny[1] = tds_get_byte(tds);
330  ver.reported = (ver.major << 24) | (ver.minor << 16) | (ver.tiny[0] << 8) | ver.tiny[1];
331 
332  if (ver.reported == 0x07010000)
333  tds->conn->tds71rev1 = 1;
334 
335  /* Log reported server product name, cf. MS-TDS LOGINACK documentation. */
336  switch(ver.reported) {
337  case 0x07000000:
338  ver.name = "7.0"; break;
339  case 0x07010000:
340  ver.name = "2000"; break;
341  case 0x71000001:
342  ver.name = "2000 SP1"; break;
343  case 0x72090002:
344  ver.name = "2005"; break;
345  case 0x730A0003:
346  ver.name = "2008 (no NBCROW or fSparseColumnSet)"; break;
347  case 0x730B0003:
348  ver.name = "2008"; break;
349  default:
350  ver.name = "unknown"; break;
351  }
352 
353  tdsdump_log(TDS_DBG_FUNC, "server reports TDS version %x.%x.%x.%x\n",
354  ver.major, ver.minor, ver.tiny[0], ver.tiny[1]);
355  tdsdump_log(TDS_DBG_FUNC, "Product name for 0x%x is %s\n", ver.reported, ver.name);
356 
357  /* Get server product name. */
358  /* Ignore product name length; some servers seem to set it incorrectly. */
359  tds_get_byte(tds);
360  product_version = 0;
361  /* Compute product name length from packet length. */
362  len -= 10;
364  if (ver.major >= 7u) {
365  product_version = 0x80000000u;
366  memrc += tds_alloc_get_string(tds, &tds->conn->product_name, len / 2);
367  } else if (ver.major >= 5) {
369  } else {
371  if (tds->conn->product_name != NULL && strstr(tds->conn->product_name, "Microsoft") != NULL)
372  product_version = 0x80000000u;
373  }
374 
375  product_version |= ((TDS_UINT) tds_get_byte(tds)) << 24;
376  product_version |= ((TDS_UINT) tds_get_byte(tds)) << 16;
377  product_version |= ((TDS_UINT) tds_get_byte(tds)) << 8;
378  product_version |= tds_get_byte(tds);
379 
380  /*
381  * MSSQL 6.5 and 7.0 seem to return strange values for this
382  * using TDS 4.2, something like 5F 06 32 FF for 6.50
383  */
384  if (ver.major == 4 && ver.minor == 2 && (product_version & 0xff0000ffu) == 0x5f0000ffu)
385  product_version = ((product_version & 0xffff00u) | 0x800000u) << 8;
386  tds->conn->product_version = product_version;
387  tdsdump_log(TDS_DBG_FUNC, "Product version %lX\n", (unsigned long) product_version);
388 
389  /*
390  * TDS 5.0 reports 5 on success 6 on failure
391  * TDS 4.2 reports 1 on success and is not
392  * present on failure
393  */
394  if (ack == 5 || ack == 1) {
395  succeed = TDS_SUCCESS;
396  /* authentication is now useless */
397  if (tds->conn->authentication) {
400  }
401  }
402  break;
403  default:
405  return TDS_FAIL;
406  break;
407  }
408  if (marker == TDS_DONE_TOKEN && IS_TDS50(tds->conn) && tds->conn->authentication) {
410  if (TDS_SUCCEED(auth->handle_next(tds, auth, 0))) {
411  marker = 0;
412  continue;
413  }
414  }
415  } while (marker != TDS_DONE_TOKEN);
416 
417  /* set the spid */
418  if (memrc == 0 && TDS_IS_MSSQL(tds))
420 
421  if (memrc != 0)
422  succeed = TDS_FAIL;
423 
424  tdsdump_log(TDS_DBG_FUNC, "tds_process_login_tokens() returning %s\n",
425  (succeed == TDS_SUCCESS)? "TDS_SUCCESS" : "TDS_FAIL");
426 
427  return succeed;
428 }
429 
430 /**
431  * Process authentication token.
432  * This token is only TDS 7.0+.
433  * \tds
434  */
435 static TDSRET
437 {
438  unsigned int pdu_size;
439 
441 
442 #if ENABLE_EXTRA_CHECKS
443  if (!IS_TDS7_PLUS(tds->conn))
444  tdsdump_log(TDS_DBG_ERROR, "Called auth on TDS version < 7\n");
445 #endif
446 
447  pdu_size = tds_get_usmallint(tds);
448  tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN PDU size %u\n", pdu_size);
449 
450  if (!tds->conn->authentication)
451  return TDS_FAIL;
452 
453  return tds->conn->authentication->handle_next(tds, tds->conn->authentication, pdu_size);
454 }
455 
456 /**
457  * process all streams.
458  * tds_process_tokens() is called after submitting a query with
459  * tds_submit_query() and is responsible for calling the routines to
460  * populate tds->res_info if appropriate (some query have no result sets)
461  * @tds
462  * @param result_type A pointer to an integer variable which
463  * tds_process_tokens sets to indicate the current type of result.
464  * @par
465  * <b>Values that indicate command status</b>
466  * <table>
467  * <tr><td>TDS_DONE_RESULT</td><td>The results of a command have been completely processed.
468  * This command returned no rows.</td></tr>
469  * <tr><td>TDS_DONEPROC_RESULT</td><td>The results of a command have been completely processed.
470  * This command returned rows.</td></tr>
471  * <tr><td>TDS_DONEINPROC_RESULT</td><td>The results of a command have been completely processed.
472  * This command returned rows.</td></tr>
473  * </table>
474  * <b>Values that indicate results information is available</b>
475  * <table><tr>
476  * <td>TDS_ROWFMT_RESULT</td><td>Regular Data format information</td>
477  * <td>tds->res_info now contains the result details ; tds->current_results now points to that data</td>
478  * </tr><tr>
479  * <td>TDS_COMPUTEFMT_ RESULT</td><td>Compute data format information</td>
480  * <td>tds->comp_info now contains the result data; tds->current_results now points to that data</td>
481  * </tr><tr>
482  * <td>TDS_DESCRIBE_RESULT</td><td></td>
483  * <td></td>
484  * </tr></table>
485  * <b>Values that indicate data is available</b>
486  * <table><tr>
487  * <td><b>Value</b></td><td><b>Meaning</b></td><td><b>Information returned</b></td>
488  * </tr><tr>
489  * <td>TDS_ROW_RESULT</td><td>Regular row results</td>
490  * <td>1 or more rows of regular data can now be retrieved</td>
491  * </tr><tr>
492  * <td>TDS_COMPUTE_RESULT</td><td>Compute row results</td>
493  * <td>A single row of compute data can now be retrieved</td>
494  * </tr><tr>
495  * <td>TDS_PARAM_RESULT</td><td>Return parameter results</td>
496  * <td>param_info or cur_dyn->params contain returned parameters</td>
497  * </tr><tr>
498  * <td>TDS_STATUS_RESULT</td><td>Stored procedure status results</td>
499  * <td>tds->ret_status contain the returned code</td>
500  * </tr></table>
501  * @param done_flags Flags contained in the TDS_DONE*_TOKEN readed
502  * @param flag Flags to select token type to stop/return
503  * @todo Complete TDS_DESCRIBE_RESULT description
504  * @retval TDS_SUCCESS if a result set is available for processing.
505  * @retval TDS_FAIL on error.
506  * @retval TDS_NO_MORE_RESULTS if all results have been completely processed.
507  * @retval anything returned by one of the many functions it calls. :-(
508  */
509 TDSRET
510 tds_process_tokens(TDSSOCKET *tds, TDS_INT *result_type, int *done_flags, unsigned flag)
511 {
512  int marker;
513  TDSPARAMINFO *pinfo = NULL;
514  TDSCOLUMN *curcol;
515  TDSRET rc;
516  TDS_INT8 saved_rows_affected = tds->rows_affected;
517  TDS_INT ret_status;
518  int cancel_seen = 0;
519  unsigned return_flag = 0;
520 
521 /** \cond HIDDEN_SYMBOLS */
522 #define SET_RETURN(ret, f) do { \
523  *result_type = ret; \
524  return_flag = TDS_RETURN_##f | TDS_STOPAT_##f; \
525  if (flag & TDS_STOPAT_##f) {\
526  tds_unget_byte(tds); \
527  tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens::SET_RETURN stopping on current token\n"); \
528  goto set_return_exit; \
529  } } while(0)
530 /** \endcond */
531 
533 
534  tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens(%p, %p, %p, 0x%x)\n", tds, result_type, done_flags, flag);
535 
536  if (tds->state == TDS_IDLE || tds->state == TDS_SENDING) {
537  tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens() state is COMPLETED\n");
538  *result_type = TDS_DONE_RESULT;
539  return TDS_NO_MORE_RESULTS;
540  }
541 
543  return TDS_FAIL;
544 
545  rc = TDS_SUCCESS;
546  for (;;) {
547 
548  marker = tds_get_byte(tds);
549  tdsdump_log(TDS_DBG_INFO1, "processing result tokens. marker is %x(%s)\n", marker, tds_token_name(marker));
550 
551  switch (marker) {
552  case TDS7_RESULT_TOKEN:
553 
554  /*
555  * If we're processing the results of a cursor fetch
556  * from sql server we don't want to pass back the
557  * TDS_ROWFMT_RESULT to the calling API
558  */
560  SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
561 
562  rc = tds7_process_result(tds);
563  if (TDS_FAILED(rc))
564  break;
565  /* handle browse information (if present) */
566  marker = tds_get_byte(tds);
567  if (marker != TDS_TABNAME_TOKEN)
569  else
570  rc = tds_process_tabname(tds);
571  break;
572  case TDS_RESULT_TOKEN:
573  SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
574  rc = tds5_process_result(tds);
575  break;
576  case TDS_ROWFMT2_TOKEN:
577  SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
579  break;
580  case TDS_COLNAME_TOKEN:
582  break;
583  case TDS_COLFMT_TOKEN:
584  SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
585  rc = tds_process_col_fmt(tds);
586  if (TDS_FAILED(rc))
587  break;
588  /* handle browse information (if present) */
589  marker = tds_get_byte(tds);
590  if (marker != TDS_TABNAME_TOKEN)
592  else
593  rc = tds_process_tabname(tds);
594  break;
595  case TDS_PARAM_TOKEN:
597  if (tds->current_op) {
598  tdsdump_log(TDS_DBG_FUNC, "processing parameters for op %d\n", tds->current_op);
599  while ((marker = tds_get_byte(tds)) == TDS_PARAM_TOKEN) {
600  tdsdump_log(TDS_DBG_INFO1, "calling tds_process_param_result\n");
601  rc = tds_process_param_result(tds, &pinfo);
602  if (TDS_FAILED(rc))
603  goto set_return_exit;
604  }
606  tdsdump_log(TDS_DBG_FUNC, "%d hidden return parameters\n", pinfo ? pinfo->num_cols : -1);
607  if (pinfo && pinfo->num_cols > 0) {
608  curcol = pinfo->columns[0];
610  TDSCURSOR *cursor = tds->cur_cursor;
611 
612  cursor->cursor_id = *(TDS_INT *) curcol->column_data;
613  tdsdump_log(TDS_DBG_FUNC, "stored internal cursor id %d\n", cursor->cursor_id);
616  }
618  && tds->cur_dyn && tds->cur_dyn->num_id == 0 && curcol->column_cur_size > 0) {
619  tds->cur_dyn->num_id = *(TDS_INT *) curcol->column_data;
620  }
623  }
624  tds_free_param_results(pinfo);
625  } else {
626  SET_RETURN(TDS_PARAM_RESULT, PROC);
628  }
629  break;
632  break;
634  SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT);
636  break;
638  SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT);
640  break;
641  case TDS_ROW_TOKEN:
642  case TDS_NBC_ROW_TOKEN:
643  /* overstepped the mark... */
644  if (tds->cur_cursor) {
646  tdsdump_log(TDS_DBG_INFO1, "tds_process_tokens(). set current_results to cursor->res_info\n");
647  } else {
648  /* assure that we point to row, not to compute */
649  if (tds->res_info)
651  }
652  /* I don't know when this it's false but it happened, also server can send garbage... */
653  if (tds->current_results)
655  SET_RETURN(TDS_ROW_RESULT, ROW);
656 
657  switch (marker) {
658  case TDS_ROW_TOKEN:
659  rc = tds_process_row(tds);
660  break;
661  case TDS_NBC_ROW_TOKEN:
662  rc = tds_process_nbcrow(tds);
663  break;
664  }
665  break;
666  case TDS_CMP_ROW_TOKEN:
667  /* I don't know when this it's false but it happened, also server can send garbage... */
668  if (tds->res_info)
669  tds->res_info->rows_exist = 1;
670  SET_RETURN(TDS_COMPUTE_RESULT, COMPUTE);
671  rc = tds_process_compute(tds);
672  break;
674  ret_status = tds_get_int(tds);
675  marker = tds_peek(tds);
676  if (marker != TDS_PARAM_TOKEN && marker != TDS_DONEPROC_TOKEN && marker != TDS_DONE_TOKEN && marker != TDS5_PARAMFMT_TOKEN && marker != TDS5_PARAMFMT2_TOKEN)
677  break;
678  if (tds->current_op) {
679  /* TODO perhaps we should use ret_status ?? */
680  } else {
681  /* TODO optimize */
682  flag &= ~TDS_STOPAT_PROC;
683  SET_RETURN(TDS_STATUS_RESULT, PROC);
684  tds->has_status = 1;
685  tds->ret_status = ret_status;
686  tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens: return status is %d\n", tds->ret_status);
687  rc = TDS_SUCCESS;
688  }
689  break;
690  case TDS5_DYNAMIC_TOKEN:
691  /* process acknowledge dynamic */
693  /* special case, prepared statement cannot be prepared */
694  if (!tds->cur_dyn || tds->cur_dyn->emulated)
695  break;
696  marker = tds_get_byte(tds);
697  if (marker != TDS_EED_TOKEN) {
699  break;
700  }
701  tds_process_info(tds, marker);
702  if (!tds->cur_dyn || !tds->cur_dyn->emulated)
703  break;
704  marker = tds_get_byte(tds);
705  if (marker != TDS_DONE_TOKEN) {
707  break;
708  }
709  rc = tds_process_end(tds, marker, done_flags);
710  if (done_flags)
711  *done_flags &= ~TDS_DONE_ERROR;
712  /* FIXME warning to macro expansion */
713  SET_RETURN(TDS_DONE_RESULT, DONE);
714  break;
715  case TDS5_PARAMFMT_TOKEN:
716  SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT);
718  break;
720  SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT);
722  break;
723  case TDS5_PARAMS_TOKEN:
724  SET_RETURN(TDS_PARAM_RESULT, PROC);
726  break;
727  case TDS_CURINFO_TOKEN:
729  break;
730  case TDS_DONE_TOKEN:
731  SET_RETURN(TDS_DONE_RESULT, DONE);
732  rc = tds_process_end(tds, marker, done_flags);
733  switch (tds->current_op) {
734  case TDS_OP_DYN_DEALLOC:
735  if (done_flags && (*done_flags & TDS_DONE_ERROR) == 0)
737  break;
738  default:
739  break;
740  }
741  break;
742  case TDS_DONEPROC_TOKEN:
743  SET_RETURN(TDS_DONEPROC_RESULT, DONE);
744  rc = tds_process_end(tds, marker, done_flags);
745  tds->rows_affected = saved_rows_affected;
746  switch (tds->current_op) {
747  default:
748  break;
749  case TDS_OP_CURSOROPEN:
750  *result_type = TDS_DONE_RESULT;
751  break;
752  case TDS_OP_CURSORCLOSE:
753  tdsdump_log(TDS_DBG_FUNC, "TDS_OP_CURSORCLOSE\n");
754  if (tds->cur_cursor) {
755 
756  TDSCURSOR *cursor = tds->cur_cursor;
757 
758  cursor->srv_status &= ~TDS_CUR_ISTAT_OPEN;
760  if (cursor->status.dealloc == TDS_CURSOR_STATE_SENT) {
761  tds_cursor_deallocated(tds->conn, cursor);
762  }
763  }
764  *result_type = TDS_NO_MORE_RESULTS;
765  rc = TDS_NO_MORE_RESULTS;
766  break;
767  case TDS_OP_UNPREPARE:
768  if (done_flags && (*done_flags & TDS_DONE_ERROR) == 0)
770  *result_type = TDS_NO_MORE_RESULTS;
771  rc = TDS_NO_MORE_RESULTS;
772  break;
773  case TDS_OP_CURSOR:
778  case TDS_OP_CURSORFETCH:
779  case TDS_OP_CURSOROPTION:
780  case TDS_OP_PREPEXECRPC:
781  *result_type = TDS_NO_MORE_RESULTS;
782  rc = TDS_NO_MORE_RESULTS;
783  break;
784  }
785  break;
787  switch(tds->current_op) {
788  case TDS_OP_CURSOROPEN:
789  case TDS_OP_CURSORFETCH:
790  case TDS_OP_PREPARE:
791  case TDS_OP_CURSORCLOSE:
792  rc = tds_process_end(tds, marker, done_flags);
793  if (tds->rows_affected != TDS_NO_COUNT) {
794  saved_rows_affected = tds->rows_affected;
795  }
796  break;
797  default:
798  SET_RETURN(TDS_DONEINPROC_RESULT, DONE);
799  rc = tds_process_end(tds, marker, done_flags);
800  break;
801  }
802  break;
803  case TDS_ERROR_TOKEN:
804  case TDS_INFO_TOKEN:
805  case TDS_EED_TOKEN:
806  SET_RETURN(TDS_MSG_RESULT, MSG);
807  rc = tds_process_default_tokens(tds, marker);
808  break;
809  case TDS_ENVCHANGE_TOKEN:
810  SET_RETURN(TDS_MSG_RESULT, ENV);
811  rc = tds_process_default_tokens(tds, marker);
812  break;
813  default:
814  SET_RETURN(TDS_OTHERS_RESULT, OTHERS);
815  rc = tds_process_default_tokens(tds, marker);
816  break;
817  }
818 
819  set_return_exit:
820  if (TDS_FAILED(rc)) {
821  if (rc == TDS_CANCELLED) {
823  } else {
825  }
826  return rc;
827  }
828 
829  cancel_seen |= tds->in_cancel;
830  if (cancel_seen) {
831  /* during cancel handle all tokens */
832  flag = TDS_HANDLE_ALL;
833  }
834 
835  if ((return_flag & flag) != 0) {
837  return rc;
838  }
839 
840  if (tds->state == TDS_IDLE || tds->state == TDS_SENDING)
841  return cancel_seen ? TDS_CANCELLED : TDS_NO_MORE_RESULTS;
842 
843  if (tds->state == TDS_DEAD) {
844  /* TODO free all results ?? */
845  return TDS_FAIL;
846  }
847  }
848 }
849 
850 /**
851  * Process results for simple query as "SET TEXTSIZE" or "USE dbname"
852  * If the statement returns results, beware they are discarded.
853  *
854  * This function was written to avoid direct calls to tds_process_default_tokens
855  * (which caused problems such as ignoring query errors).
856  * Results are read until idle state or severe failure (do not stop for
857  * statement failure).
858  * @return see tds_process_tokens for results (TDS_NO_MORE_RESULTS is never returned)
859  */
860 TDSRET
862 {
863  TDS_INT res_type;
864  TDS_INT done_flags;
865  TDSRET rc;
866  TDSRET ret = TDS_SUCCESS;
867 
869 
870  while ((rc = tds_process_tokens(tds, &res_type, &done_flags, TDS_RETURN_DONE)) == TDS_SUCCESS) {
871  switch (res_type) {
872 
873  case TDS_DONE_RESULT:
874  case TDS_DONEPROC_RESULT:
876  if ((done_flags & TDS_DONE_ERROR) != 0)
877  ret = TDS_FAIL;
878  break;
879 
880  default:
881  break;
882  }
883  }
884  if (TDS_FAILED(rc))
885  ret = rc;
886 
887  return ret;
888 }
889 
890 /**
891  * Holds list of names
892  */
893 struct namelist
894 {
895  /** string name */
896  char *name;
897  /** next element in the list */
898  struct namelist *next;
899 };
900 
901 /**
902  * Frees list of names
903  * \param head list head to free
904  */
905 static void
907 {
908  struct namelist *cur = head, *prev;
909 
910  while (cur != NULL) {
911  prev = cur;
912  cur = cur->next;
913  free(prev->name);
914  free(prev);
915  }
916 }
917 
918 /**
919  * Reads list of names (usually table names)
920  * \tds
921  * \param remainder bytes left to read
922  * \param p_head list head to return
923  * \param large true if name length from network are 2 byte (usually 1)
924  */
925 static int
926 tds_read_namelist(TDSSOCKET * tds, int remainder, struct namelist **p_head, int large)
927 {
928  struct namelist *head = NULL, *cur = NULL, *prev;
929  int num_names = 0;
930 
931  /*
932  * this is a little messy...TDS 5.0 gives the number of columns
933  * upfront, while in TDS 4.2, you're expected to figure it out
934  * by the size of the message. So, I use a link list to get the
935  * colum names and then allocate the result structure, copy
936  * and delete the linked list
937  */
938  while (remainder > 0) {
939  TDS_USMALLINT namelen;
940 
941  prev = cur;
942  if (!(cur = tds_new(struct namelist, 1))) {
944  return -1;
945  }
946 
947  cur->next = NULL;
948  if (prev)
949  prev->next = cur;
950  else
951  head = cur;
952 
953  if (large) {
954  namelen = tds_get_usmallint(tds);
955  remainder -= 2;
956  } else {
957  namelen = tds_get_byte(tds);
958  --remainder;
959  }
960 
961  if (tds_alloc_get_string(tds, &cur->name, namelen) < 0) {
963  return -1;
964  }
965 
966  remainder -= namelen;
967  if (IS_TDS7_PLUS(tds->conn))
968  remainder -= namelen;
969  num_names++;
970  }
971 
972  *p_head = head;
973  return num_names;
974 }
975 
976 /**
977  * tds_process_col_name() is one half of the result set under TDS 4.2
978  * it contains all the column names, a TDS_COLFMT_TOKEN should
979  * immediately follow this token with the datatype/size information
980  * This is a 4.2 only function
981  * \tds
982  */
983 static TDSRET
985 {
986  int hdrsize;
987  int col, num_names = 0;
988  struct namelist *head = NULL, *cur = NULL;
989  TDSCOLUMN *curcol;
991 
993 
994  hdrsize = tds_get_usmallint(tds);
995 
996  if ((num_names = tds_read_namelist(tds, hdrsize, &head, 0)) < 0)
997  return TDS_FAIL;
998 
999  /* free results/computes/params etc... */
1002 
1003  if ((info = tds_alloc_results(num_names)) == NULL)
1004  goto memory_error;
1005 
1006  tds->res_info = info;
1008 
1009  cur = head;
1010  for (col = 0; col < num_names; ++col) {
1011  curcol = info->columns[col];
1012  if (!tds_dstr_copy(&curcol->column_name, cur->name))
1013  goto memory_error;
1014  cur = cur->next;
1015  }
1017  return TDS_SUCCESS;
1018 
1019 memory_error:
1021  return TDS_FAIL;
1022 }
1023 
1024 /**
1025  * tds_process_col_fmt() is the other half of result set processing
1026  * under TDS 4.2. It follows tds_process_col_name(). It contains all the
1027  * column type and size information.
1028  * This is a 4.2 only function
1029  * \tds
1030  */
1031 static TDSRET
1033 {
1034  unsigned int col;
1035  TDSCOLUMN *curcol;
1038 
1040 
1041  tds_get_usmallint(tds); /* hdrsize */
1042 
1043  /* TODO use current_results instead of res_info ?? */
1044  info = tds->res_info;
1045  if (!info || info->num_cols < 0)
1046  return TDS_FAIL;
1047  for (col = 0; col < info->num_cols; col++) {
1048  curcol = info->columns[col];
1049  /* In Sybase all 4 byte are used for usertype, while mssql place 2 byte as usertype and 2 byte as flags */
1050  if (TDS_IS_MSSQL(tds)) {
1053  curcol->column_nullable = flags & 0x01;
1054  curcol->column_writeable = (flags & 0x08) > 0;
1055  curcol->column_identity = (flags & 0x10) > 0;
1056  } else {
1057  curcol->column_usertype = tds_get_int(tds);
1058  }
1059  /* on with our regularly scheduled code (mlilback, 11/7/01) */
1060  TDS_GET_COLUMN_TYPE(curcol);
1061 
1062  tdsdump_log(TDS_DBG_INFO1, "processing result. type = %d(%s), varint_size %d\n",
1063  curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
1064 
1065  TDS_GET_COLUMN_INFO(tds, curcol);
1066 
1067  /* Adjust column size according to client's encoding */
1068  curcol->on_server.column_size = curcol->column_size;
1070  }
1071 
1072  return tds_alloc_row(info);
1073 }
1074 
1075 /**
1076  * Reads table names for TDS 7.1+.
1077  * TDS 7.1+ return table names as an array of names
1078  * (so database.schema.owner.name as separate names)
1079  * \tds
1080  * \param remainder bytes left to read
1081  * \param p_head pointer to list head to return
1082  * \return number of element returned or -1 on error
1083  */
1084 static int
1085 tds71_read_table_names(TDSSOCKET *tds, int remainder, struct namelist **p_head)
1086 {
1087  struct namelist *head = NULL, *cur = NULL, *prev;
1088  int num_names = 0;
1089 
1090  /*
1091  * this is a little messy...TDS 5.0 gives the number of columns
1092  * upfront, while in TDS 4.2, you're expected to figure it out
1093  * by the size of the message. So, I use a link list to get the
1094  * colum names and then allocate the result structure, copy
1095  * and delete the linked list
1096  */
1097  while (remainder > 0) {
1098  int elements, i;
1099  size_t len;
1100  char *partials[4], *p;
1101 
1102  prev = cur;
1103  if (!(cur = tds_new(struct namelist, 1))) {
1105  return -1;
1106  }
1107 
1108  cur->name = NULL;
1109  cur->next = NULL;
1110  if (prev)
1111  prev->next = cur;
1112  else
1113  head = cur;
1114 
1115  elements = tds_get_byte(tds);
1116  --remainder;
1117  if (elements <= 0 || elements > 4) {
1119  return -1;
1120  }
1121 
1122  /* read partials IDs and compute full length */
1123  len = 0;
1124  for (i = 0; i < elements; ++i) {
1125  TDS_USMALLINT namelen = tds_get_usmallint(tds);
1126  remainder -= 2 + 2 * namelen;
1127  if (tds_alloc_get_string(tds, &partials[i], namelen) < 0) {
1128  while (i > 0)
1129  free(partials[--i]);
1131  return -1;
1132  }
1133  len += tds_quote_id(tds, NULL, partials[i], -1) + 1;
1134  }
1135 
1136  /* allocate full name */
1137  p = tds_new(char, len);
1138  if (!p) {
1139  i = elements;
1140  while (i > 0)
1141  free(partials[--i]);
1143  return -1;
1144  }
1145 
1146  /* compose names */
1147  cur->name = p;
1148  for (i = 0; i < elements; ++i) {
1149  p += tds_quote_id(tds, p, partials[i], -1);
1150  *p++ = '.';
1151  free(partials[i]);
1152  }
1153  *--p = 0;
1154 
1155  num_names++;
1156  }
1157 
1158  *p_head = head;
1159  return num_names;
1160 }
1161 
1162 /**
1163  * Process list of table from network.
1164  * This token is only TDS 4.2
1165  * \tds
1166  */
1167 static TDSRET
1169 {
1170  struct namelist *head, *cur;
1171  int num_names, hdrsize, i;
1172  char **names;
1173  unsigned char marker;
1174  TDSRET rc;
1175 
1176  hdrsize = tds_get_usmallint(tds);
1177 
1178  /* different structure for tds7.1 */
1179  /* hdrsize check is required for tds7.1 revision 1 (mssql without SPs) */
1180  /* TODO change tds_version ?? */
1181  if (IS_TDS71_PLUS(tds->conn) && (!IS_TDS71(tds->conn) || !tds->conn->tds71rev1))
1182  num_names = tds71_read_table_names(tds, hdrsize, &head);
1183  else
1184  num_names = tds_read_namelist(tds, hdrsize, &head, 1);
1185  if (num_names <= 0)
1186  return TDS_FAIL;
1187 
1188  /* put in an array */
1189  names = tds_new(char*, num_names);
1190  if (!names) {
1192  return TDS_FAIL;
1193  }
1194  for (cur = head, i = 0; i < num_names; ++i, cur = cur->next)
1195  names[i] = cur->name;
1196 
1197  rc = TDS_SUCCESS;
1198  marker = tds_get_byte(tds);
1199  if (marker != TDS_COLINFO_TOKEN)
1201  else
1202  rc = tds_process_colinfo(tds, names, num_names);
1203 
1204  free(names);
1206  return rc;
1207 }
1208 
1209 /**
1210  * Reads column information.
1211  * This token is only TDS 4.2
1212  * \tds
1213  * \param[in] names table names
1214  * \param[in] num_names number of table names
1215  */
1216 static TDSRET
1217 tds_process_colinfo(TDSSOCKET * tds, char **names, int num_names)
1218 {
1219  unsigned int hdrsize, l;
1220  TDSCOLUMN *curcol;
1222  unsigned int bytes_read = 0;
1223  unsigned char col_info[3];
1224 
1226 
1227  hdrsize = tds_get_usmallint(tds);
1228 
1230 
1231  while (bytes_read < hdrsize) {
1232 
1233  tds_get_n(tds, col_info, 3);
1234  bytes_read += 3;
1235 
1236  curcol = NULL;
1237  if (info && col_info[0] > 0 && col_info[0] <= info->num_cols)
1238  curcol = info->columns[col_info[0] - 1];
1239 
1240  if (curcol) {
1241  curcol->column_writeable = (col_info[2] & 0x4) == 0;
1242  curcol->column_key = (col_info[2] & 0x8) > 0;
1243  curcol->column_hidden = (col_info[2] & 0x10) > 0;
1244 
1245  if (names && col_info[1] > 0 && col_info[1] <= num_names)
1246  if (!tds_dstr_copy(&curcol->table_name, names[col_info[1] - 1]))
1247  return TDS_FAIL;
1248  }
1249  /* read real column name */
1250  if (col_info[2] & 0x20) {
1251  l = tds_get_byte(tds);
1252  if (curcol) {
1253  tds_dstr_get(tds, &curcol->table_column_name, l);
1254  if (IS_TDS7_PLUS(tds->conn))
1255  l *= 2;
1256  } else {
1257  if (IS_TDS7_PLUS(tds->conn))
1258  l *= 2;
1259  /* discard silently */
1260  tds_get_n(tds, NULL, l);
1261  }
1262  bytes_read += l + 1;
1263  }
1264  }
1265 
1266  return TDS_SUCCESS;
1267 }
1268 
1269 /**
1270  * process output parameters of a stored
1271  * procedure. This differs from regular row/compute results in that there
1272  * is no total number of parameters given, they just show up singly.
1273  * \tds
1274  * \param[out] pinfo output parameter.
1275  * Should point to a not allocated structure
1276  */
1277 static TDSRET
1279 {
1280  TDSCOLUMN *curparam;
1281  TDSPARAMINFO *info;
1282  TDSRET token, rc;
1283 
1284  tdsdump_log(TDS_DBG_FUNC, "tds_process_param_result(%p, %p)\n", tds, pinfo);
1285 
1287  if (*pinfo)
1288  CHECK_PARAMINFO_EXTRA(*pinfo);
1289 
1290  /* TODO check if current_results is a param result */
1291 
1292  /* limited to 64K but possible types are always smaller (not TEXT/IMAGE) */
1293  tds_get_smallint(tds); /* header size */
1294  if ((info = tds_alloc_param_result(*pinfo)) == NULL)
1295  return TDS_FAIL;
1296 
1297  *pinfo = info;
1298  curparam = info->columns[info->num_cols - 1];
1299 
1300  /*
1301  * FIXME check support for tds7+ (seem to use same format of tds5 for data...)
1302  * perhaps varint_size can be 2 or collation can be specified ??
1303  */
1304  rc = tds_get_data_info(tds, curparam, 1);
1305  if (TDS_FAILED(rc))
1306  return rc;
1307 
1308  curparam->column_cur_size = curparam->column_size; /* needed ?? */
1309 
1310  if (tds_alloc_param_data(curparam) == NULL)
1311  return TDS_FAIL;
1312 
1313  token = curparam->funcs->get_data(tds, curparam);
1315  tdsdump_col(curparam);
1316 
1317  /*
1318  * Real output parameters will either be unnamed or will have a valid
1319  * parameter name beginning with '@'. Ignore any other Spurious parameters
1320  * such as those returned from calls to writetext in the proc.
1321  */
1322  if (!tds_dstr_isempty(&curparam->column_name) && tds_dstr_cstr(&curparam->column_name)[0] != '@')
1323  tds_free_param_result(*pinfo);
1324 
1325  return token;
1326 }
1327 
1328 /**
1329  * Process parameters from networks.
1330  * Read all consecutives paramaters, not a single one.
1331  * Parameters are then stored in tds->param_info or tds->cur_dyn->res_info
1332  * depending if we are reading cursor results or normal parameters.
1333  * \tds
1334  */
1335 static TDSRET
1337 {
1338  int marker;
1339  TDSPARAMINFO **pinfo;
1340  TDSRET rc;
1341 
1343 
1344  if (tds->cur_dyn)
1345  pinfo = &(tds->cur_dyn->res_info);
1346  else
1347  pinfo = &(tds->param_info);
1348 
1349  while ((marker = tds_get_byte(tds)) == TDS_PARAM_TOKEN) {
1350  rc = tds_process_param_result(tds, pinfo);
1351  if (TDS_FAILED(rc))
1352  return rc;
1353  }
1354  if (!marker) {
1355  tdsdump_log(TDS_DBG_FUNC, "error: tds_process_param_result() returned TDS_FAIL\n");
1356  return TDS_FAIL;
1357  }
1358 
1359  tds_set_current_results(tds, *pinfo);
1361  return TDS_SUCCESS;
1362 }
1363 
1364 /**
1365  * tds_process_params_result_token() processes params on TDS5.
1366  * \tds
1367  */
1368 static TDSRET
1370 {
1371  unsigned int i;
1372  TDSPARAMINFO *info;
1373 
1375 
1376  /* TODO check if current_results is a param result */
1378  if (!info)
1379  return TDS_FAIL;
1380 
1381  for (i = 0; i < info->num_cols; i++) {
1382  TDSCOLUMN *curcol = info->columns[i];
1383  TDSRET rc = curcol->funcs->get_data(tds, curcol);
1384  if (TDS_FAILED(rc))
1385  return rc;
1386  }
1387  return TDS_SUCCESS;
1388 }
1389 
1390 /**
1391  * tds_process_compute_result() processes compute result sets. These functions
1392  * need work but since they get little use, nobody has complained!
1393  * It is very similar to normal result sets.
1394  * \tds
1395  */
1396 static TDSRET
1398 {
1399  unsigned int col, num_cols;
1400  TDS_TINYINT by_cols = 0;
1401  TDS_SMALLINT *cur_by_col;
1402  TDS_SMALLINT compute_id = 0;
1403  TDSCOLUMN *curcol;
1405  unsigned int i;
1406 
1408 
1409  tds_get_smallint(tds); /* header size*/
1410 
1411  /*
1412  * Compute statement id which this relates to.
1413  * You can have more than one compute clause in a SQL statement
1414  */
1415 
1416  compute_id = tds_get_smallint(tds);
1417  num_cols = tds_get_byte(tds);
1418 
1419  tdsdump_log(TDS_DBG_INFO1, "tds_process_compute_result(): compute_id %d for %d columns\n", compute_id, num_cols);
1420 
1421  for (i=0; i < tds->num_comp_info; ++i) {
1422  if (tds->comp_info[i]->computeid == compute_id) {
1423  info = tds->comp_info[i];
1424  break;
1425  }
1426  }
1427  if (NULL == info) {
1428  tdsdump_log(TDS_DBG_FUNC, "logic error: compute_id (%d) from server not found in tds->comp_info\n", compute_id);
1429  return TDS_FAIL;
1430  }
1431 
1432  tdsdump_log(TDS_DBG_FUNC, "found computeid %d in tds->comp_info\n", info->computeid);
1434 
1435  tdsdump_log(TDS_DBG_INFO1, "processing compute result. num_cols = %d\n", num_cols);
1436 
1437  /*
1438  * Iterate over compute columns returned,
1439  * e.g. COMPUTE SUM(x), AVG(x) would return num_cols = 2.
1440  */
1441  for (col = 0; col < num_cols; col++) {
1442  tdsdump_log(TDS_DBG_INFO1, "processing compute column %d\n", col);
1443  curcol = info->columns[col];
1444 
1445  curcol->column_operator = tds_get_byte(tds);
1446  curcol->column_operand = tds_get_byte(tds);
1447 
1448  /* If no name has been defined for the compute column, use "max", "avg" etc. */
1449  if (tds_dstr_isempty(&curcol->column_name))
1450  if (!tds_dstr_copy(&curcol->column_name, tds_pr_op(curcol->column_operator)))
1451  return TDS_FAIL;
1452 
1453  /* User defined data type of the column */
1454  curcol->column_usertype = tds_get_int(tds);
1455 
1456  TDS_GET_COLUMN_TYPE(curcol);
1457 
1458  TDS_GET_COLUMN_INFO(tds, curcol);
1459 
1460  tdsdump_log(TDS_DBG_INFO1, "compute column_size is %d\n", curcol->column_size);
1461 
1462  /* Adjust column size according to client's encoding */
1463  curcol->on_server.column_size = curcol->column_size;
1464  /* TODO check if this column can have collation information associated */
1466 
1467  /* skip locale */
1468  if (!IS_TDS42(tds->conn))
1470  }
1471 
1472  by_cols = tds_get_byte(tds);
1473 
1474  tdsdump_log(TDS_DBG_INFO1, "processing tds compute result, by_cols = %d\n", by_cols);
1475 
1476  if (by_cols) {
1477  if ((info->bycolumns = tds_new0(TDS_SMALLINT, by_cols)) == NULL)
1478  return TDS_FAIL;
1479  }
1480  info->by_cols = by_cols;
1481 
1482  cur_by_col = info->bycolumns;
1483  for (col = 0; col < by_cols; col++) {
1484  *cur_by_col = tds_get_byte(tds);
1485  cur_by_col++;
1486  }
1487 
1488  return tds_alloc_compute_row(info);
1489 }
1490 
1491 /**
1492  * Reads data information from wire
1493  * \tds
1494  * \param curcol column where to store information
1495  */
1496 static TDSRET
1498 {
1500  CHECK_COLUMN_EXTRA(curcol);
1501 
1502  /* User defined data type of the column */
1504 
1505  curcol->column_flags = tds_get_smallint(tds); /* Flags */
1506 
1507  curcol->column_nullable = curcol->column_flags & 0x01;
1508  curcol->column_writeable = (curcol->column_flags & 0x08) > 0;
1509  curcol->column_identity = (curcol->column_flags & 0x10) > 0;
1510 
1511  TDS_GET_COLUMN_TYPE(curcol); /* sets "cardinal" type */
1512 
1513  curcol->column_timestamp = (curcol->column_type == SYBBINARY && curcol->column_usertype == TDS_UT_TIMESTAMP);
1514 
1515  TDS_GET_COLUMN_INFO(tds, curcol);
1516 
1517  /* Adjust column size according to client's encoding */
1518  curcol->on_server.column_size = curcol->column_size;
1519 
1520  /* NOTE adjustements must be done after curcol->char_conv initialization */
1522 
1523  /*
1524  * under 7.0 lengths are number of characters not
1525  * number of bytes...tds_get_string handles this
1526  */
1528 
1529  tdsdump_log(TDS_DBG_INFO1, "tds7_get_data_info: \n"
1530  "\tcolname = %s\n"
1531  "\ttype = %d (%s)\n"
1532  "\tserver's type = %d (%s)\n"
1533  "\tcolumn_varint_size = %d\n"
1534  "\tcolumn_size = %d (%d on server)\n",
1535  tds_dstr_cstr(&curcol->column_name),
1536  curcol->column_type, tds_prtype(curcol->column_type),
1538  curcol->column_varint_size,
1539  curcol->column_size, curcol->on_server.column_size);
1540 
1541  CHECK_COLUMN_EXTRA(curcol);
1542 
1543  return TDS_SUCCESS;
1544 }
1545 
1546 /**
1547  * tds7_process_result() is the TDS 7.0 result set processing routine. It
1548  * is responsible for populating the tds->res_info structure.
1549  * This is a TDS 7.0 only function
1550  * \tds
1551  */
1552 static TDSRET
1554 {
1555  int col, num_cols;
1556  TDSRET result;
1558 
1560  tdsdump_log(TDS_DBG_INFO1, "processing TDS7 result metadata.\n");
1561 
1562  /* read number of columns and allocate the columns structure */
1563 
1564  num_cols = tds_get_smallint(tds);
1565 
1566  /* This can be a DUMMY results token from a cursor fetch */
1567 
1568  if (num_cols < 0) {
1569  tdsdump_log(TDS_DBG_INFO1, "no meta data\n");
1570  return TDS_SUCCESS;
1571  }
1572 
1575 
1576  if ((info = tds_alloc_results(num_cols)) == NULL)
1577  return TDS_FAIL;
1579  if (tds->cur_cursor) {
1582  tdsdump_log(TDS_DBG_INFO1, "set current_results to cursor->res_info\n");
1583  } else {
1584  tds->res_info = info;
1585  tdsdump_log(TDS_DBG_INFO1, "set current_results (%d column%s) to tds->res_info\n", num_cols, (num_cols==1? "":"s"));
1586  }
1587 
1588  /*
1589  * loop through the columns populating COLINFO struct from
1590  * server response
1591  */
1592  tdsdump_log(TDS_DBG_INFO1, "setting up %d columns\n", num_cols);
1593  for (col = 0; col < num_cols; col++) {
1594  TDSCOLUMN *curcol = info->columns[col];
1595 
1596  result = tds7_get_data_info(tds, curcol);
1597  if (TDS_FAILED(result))
1598  return result;
1599  }
1600 
1601  if (num_cols > 0) {
1602  static const char dashes[31] = "------------------------------";
1603  tdsdump_log(TDS_DBG_INFO1, " %-20s %-15s %-15s %-7s\n", "name", "size/wsize", "type/wtype", "utype");
1604  tdsdump_log(TDS_DBG_INFO1, " %-20s %15s %15s %7s\n", dashes+10, dashes+30-15, dashes+30-15, dashes+30-7);
1605  }
1606  for (col = 0; col < num_cols; col++) {
1607  TDSCOLUMN *curcol = info->columns[col];
1608 
1609  tdsdump_log(TDS_DBG_INFO1, " %-20s %7d/%-7d %7d/%-7d %7d\n",
1610  tds_dstr_cstr(&curcol->column_name),
1611  curcol->column_size, curcol->on_server.column_size,
1612  curcol->column_type, curcol->on_server.column_type,
1613  curcol->column_usertype);
1614  }
1615 
1616  /* all done now allocate a row for tds_process_row to use */
1619  return result;
1620 }
1621 
1622 /**
1623  * Reads data metadata from wire
1624  * \param tds state information for the socket and the TDS protocol
1625  * \param curcol column where to store information
1626  * \param is_param true if metadata are for a parameter (false for normal
1627  * column)
1628  */
1629 static TDSRET
1630 tds_get_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int is_param)
1631 {
1633  CHECK_COLUMN_EXTRA(curcol);
1634 
1635  tdsdump_log(TDS_DBG_INFO1, "tds_get_data_info(%p, %p, %d) %s\n", tds, curcol, is_param, is_param? "[for parameter]" : "");
1636 
1638 
1639  curcol->column_flags = tds_get_byte(tds); /* Flags */
1640  if (!is_param) {
1641  /* TODO check if all flags are the same for all TDS versions */
1642  if (IS_TDS50(tds->conn))
1643  curcol->column_hidden = curcol->column_flags & 0x1;
1644  curcol->column_key = (curcol->column_flags & 0x2) > 1;
1645  curcol->column_writeable = (curcol->column_flags & 0x10) > 1;
1646  curcol->column_nullable = (curcol->column_flags & 0x20) > 1;
1647  curcol->column_identity = (curcol->column_flags & 0x40) > 1;
1648 #if 0
1649  /****************************************
1650  * NumParts=BYTE; (introduced in TDS 7.2)
1651  * PartName=US_VARCHAR;(introduced in TDS 7.2)
1652  * TableName=NumParts, {PartName}-;
1653  * ColName= HYPERLINK \l "B_VARCHAR_Def" B_VARCHAR;
1654  * ColumnData=UserType, Flags, [TableName], // <Only specified if text, //ntext or image columns are included //in the rowset being described> ColName;
1655  * NoMetaData='0xFF', '0xFF';
1656  */
1657  enum column_flag_bits_according_to_microsoft {
1658  case_sensitive = 0x0001
1659  , nullable = 0x0002
1660  , updateable = 0x0004
1661  , might_be_updateable = 0x0008
1662  , identity = 0x0010
1663  , computed = 0x0020
1664  , us_reserved_odbc = 0x0040 | 0x0080
1665  , is_fixed_len_clr_type = 0x0100
1666  , is_hidden_browse_pk = 0x0200
1667  , is_browse_pk = 0x0400
1668  , might_be_nullable = 0x0800
1669  };
1670  /* TODO: implement members in TDSCOLUMN */
1671  if (IS_TDS72_PLUS(tds->conn)) {
1672  curcol->is_computed = (curcol->column_flags & (1 << 4)) > 1;
1673  curcol->us_reserved_odbc1 = (curcol->column_flags & (1 << 5)) > 1;
1674  curcol->us_reserved_odbc2 = (curcol->column_flags & (1 << 6)) > 1;
1675  curcol->is_fixed_len_clr_type = (curcol->column_flags & (1 << 7)) > 1;
1676  }
1677 #endif
1678  }
1679 
1680  if (IS_TDS72_PLUS(tds->conn)) {
1681  tds_get_n(tds, NULL, 2);
1682 #if 0
1683  /* TODO: implement members in TDSCOLUMN, values untested */
1684  curcol->us_reserved1 = (curcol->column_flags & 0x01);
1685  curcol->us_reserved2 = (curcol->column_flags & 0x02);
1686  curcol->us_reserved3 = (curcol->column_flags & 0x04);
1687  curcol->us_reserved4 = (curcol->column_flags & 0x08);
1688  curcol->is_hidden = (curcol->column_flags & 0x10);
1689  curcol->is_key = (curcol->column_flags & 0x20);
1690  curcol->is_nullable_unknown = (curcol->column_flags & 0x40);
1691 #endif
1692  }
1693 
1694  curcol->column_usertype = tds_get_int(tds);
1695  TDS_GET_COLUMN_TYPE(curcol);
1696 
1697  tdsdump_log(TDS_DBG_INFO1, "processing result. type = %d(%s), varint_size %d\n",
1698  curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
1699 
1700  TDS_GET_COLUMN_INFO(tds, curcol);
1701 
1702  tdsdump_log(TDS_DBG_INFO1, "processing result. column_size %d\n", curcol->column_size);
1703 
1704  /* Adjust column size according to client's encoding */
1705  curcol->on_server.column_size = curcol->column_size;
1707 
1708  return TDS_SUCCESS;
1709 }
1710 
1711 /**
1712  * tds5_process_result() is the TDS 5.0 result set processing routine.
1713  * It is responsible for populating the tds->res_info structure.
1714  * This is a TDS 5.0 only function
1715  * \tds
1716  */
1717 static TDSRET
1719 {
1720  unsigned int col, num_cols;
1721  TDSCOLUMN *curcol;
1723  TDSRET rc;
1724 
1726 
1729 
1730  tds_get_usmallint(tds); /* header size */
1731 
1732  /* read number of columns and allocate the columns structure */
1733  num_cols = tds_get_usmallint(tds);
1734 
1735  if ((info = tds_alloc_results(num_cols)) == NULL)
1736  return TDS_FAIL;
1738  if (tds->cur_cursor)
1740  else
1741  tds->res_info = info;
1742 
1743  /*
1744  * loop through the columns populating COLINFO struct from
1745  * server response
1746  */
1747  for (col = 0; col < info->num_cols; col++) {
1748  curcol = info->columns[col];
1749 
1750  rc = tds_get_data_info(tds, curcol, 0);
1751  if (TDS_FAILED(rc))
1752  return rc;
1753 
1754  /* skip locale information */
1755  /* NOTE do not put into tds_get_data_info, param do not have locale information */
1757  }
1758  return tds_alloc_row(info);
1759 }
1760 
1761 /**
1762  * tds5_process_result2() is the new TDS 5.0 result set processing routine.
1763  * It is responsible for populating the tds->res_info structure.
1764  * This is a TDS 5.0 only function
1765  * \tds
1766  */
1767 static TDSRET
1769 {
1770  unsigned int colnamelen;
1771  TDS_USMALLINT col, num_cols;
1772  TDSCOLUMN *curcol;
1774 
1776 
1777  tdsdump_log(TDS_DBG_INFO1, "tds5_process_result2\n");
1778 
1779  /*
1780  * free previous resultset
1781  */
1784 
1785  /*
1786  * read length of packet (4 bytes)
1787  */
1788  tds_get_uint(tds);
1789 
1790  /* read number of columns and allocate the columns structure */
1791  num_cols = tds_get_usmallint(tds);
1792 
1793  if ((info = tds_alloc_results(num_cols)) == NULL)
1794  return TDS_FAIL;
1796  if (tds->cur_cursor)
1798  else
1799  tds->res_info = info;
1800 
1801  tdsdump_log(TDS_DBG_INFO1, "num_cols=%d\n", num_cols);
1802 
1803  /* TODO reuse some code... */
1804  /*
1805  * loop through the columns populating COLINFO struct from
1806  * server response
1807  */
1808  for (col = 0; col < info->num_cols; col++) {
1809  curcol = info->columns[col];
1810 
1811  /* label */
1813 
1814  /* TODO save informations somewhere */
1815  /* database */
1816  colnamelen = tds_get_byte(tds);
1817  tds_get_n(tds, NULL, colnamelen);
1818  /*
1819  * tds_get_n(tds, curcol->catalog_name, colnamelen);
1820  * curcol->catalog_name[colnamelen] = '\0';
1821  */
1822 
1823  /* owner */
1824  colnamelen = tds_get_byte(tds);
1825  tds_get_n(tds, NULL, colnamelen);
1826  /*
1827  * tds_get_n(tds, curcol->schema_name, colnamelen);
1828  * curcol->schema_name[colnamelen] = '\0';
1829  */
1830 
1831  /* table */
1832  /* TODO use with owner and database */
1834 
1835  /* table column name */
1837 
1838  /* if label is empty, use the table column name */
1839  if (tds_dstr_isempty(&curcol->column_name))
1840  if (!tds_dstr_dup(&curcol->column_name, &curcol->table_column_name))
1841  return TDS_FAIL;
1842 
1843  /* flags (4 bytes) */
1844  curcol->column_flags = tds_get_int(tds);
1845  curcol->column_hidden = curcol->column_flags & 0x1;
1846  curcol->column_key = (curcol->column_flags & 0x2) > 1;
1847  curcol->column_writeable = (curcol->column_flags & 0x10) > 1;
1848  curcol->column_nullable = (curcol->column_flags & 0x20) > 1;
1849  curcol->column_identity = (curcol->column_flags & 0x40) > 1;
1850 
1851  curcol->column_usertype = tds_get_int(tds);
1852 
1853  TDS_GET_COLUMN_TYPE(curcol);
1854 
1855  TDS_GET_COLUMN_INFO(tds, curcol);
1856 
1857  /* Adjust column size according to client's encoding */
1858  curcol->on_server.column_size = curcol->column_size;
1860 
1861  /* discard Locale */
1863 
1864  /*
1865  * Dump all information on this column
1866  */
1867  tdsdump_log(TDS_DBG_INFO1, "col %d:\n", col);
1868  tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", tds_dstr_cstr(&curcol->column_name));
1869 /*
1870  tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", curcol->column_colname);
1871  tdsdump_log(TDS_DBG_INFO1, "\tcatalog=[%s] schema=[%s] table=[%s]\n",
1872  curcol->catalog_name, curcol->schema_name, curcol->table_name, curcol->column_colname);
1873 */
1874  tdsdump_log(TDS_DBG_INFO1, "\tflags=%x utype=%d type=%d varint=%d\n",
1875  curcol->column_flags, curcol->column_usertype, curcol->column_type, curcol->column_varint_size);
1876 
1877  tdsdump_log(TDS_DBG_INFO1, "\tcolsize=%d prec=%d scale=%d\n",
1878  curcol->column_size, curcol->column_prec, curcol->column_scale);
1879  }
1880  return tds_alloc_row(info);
1881 }
1882 
1883 /**
1884  * tds_process_compute() processes compute rows and places them in the row
1885  * buffer.
1886  * \tds
1887  */
1888 static TDSRET
1890 {
1891  unsigned int i;
1892  TDSCOLUMN *curcol;
1894  TDS_INT id;
1895 
1897 
1898  id = tds_get_smallint(tds);
1899 
1900  tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() found compute id %d\n", id);
1901 
1902  for (i = 0;; ++i) {
1903  if (i >= tds->num_comp_info) {
1904  tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() FAIL: id exceeds bound (%d)\n", tds->num_comp_info);
1905  return TDS_FAIL;
1906  }
1907  info = tds->comp_info[i];
1908  if (info->computeid == id)
1909  break;
1910  }
1912 
1913  for (i = 0; i < info->num_cols; i++) {
1914  curcol = info->columns[i];
1915  if (TDS_FAILED(curcol->funcs->get_data(tds, curcol))) {
1916  tdsdump_log(TDS_DBG_INFO1, "tds_process_compute() FAIL: get_data() failed\n");
1917  return TDS_FAIL;
1918  }
1919  }
1920  return TDS_SUCCESS;
1921 }
1922 
1923 /**
1924  * tds_process_row() processes rows and places them in the row buffer.
1925  * \tds
1926  */
1927 static TDSRET
1929 {
1930  unsigned int i;
1931  TDSCOLUMN *curcol;
1933 
1935 
1937  if (!info || info->num_cols <= 0)
1938  return TDS_FAIL;
1939 
1940  for (i = 0; i < info->num_cols; i++) {
1941  tdsdump_log(TDS_DBG_INFO1, "tds_process_row(): reading column %d \n", i);
1942  curcol = info->columns[i];
1943  if (TDS_FAILED(curcol->funcs->get_data(tds, curcol)))
1944  return TDS_FAIL;
1945  }
1946  return TDS_SUCCESS;
1947 }
1948 
1949 /**
1950  * tds_process_nbcrow() processes rows and places them in the row buffer.
1951  */
1952 static TDSRET
1954 {
1955  unsigned int i;
1956  TDSCOLUMN *curcol;
1958  char *nbcbuf;
1959 
1961 
1963  if (!info || info->num_cols <= 0)
1964  return TDS_FAIL;
1965 
1966  nbcbuf = (char *) alloca((info->num_cols + 7) / 8);
1967  tds_get_n(tds, nbcbuf, (info->num_cols + 7) / 8);
1968  for (i = 0; i < info->num_cols; i++) {
1969  curcol = info->columns[i];
1970  tdsdump_log(TDS_DBG_INFO1, "tds_process_nbcrow(): reading column %d \n", i);
1971  if (nbcbuf[i / 8] & (1 << (i % 8))) {
1972  curcol->column_cur_size = -1;
1973  } else {
1974  if (TDS_FAILED(curcol->funcs->get_data(tds, curcol)))
1975  return TDS_FAIL;
1976  }
1977  }
1978  return TDS_SUCCESS;
1979 }
1980 
1981 static TDSRET
1983 {
1985 
1986  /* TODO do something with it */
1987  for (;;) {
1988  TDS_UINT data_len;
1989  TDS_TINYINT feature_id;
1990 
1991  feature_id = tds_get_byte(tds);
1992  if (feature_id == 0xff)
1993  break;
1994 
1995  data_len = tds_get_uint(tds);
1996  tds_get_n(tds, NULL, data_len);
1997  }
1998  return TDS_SUCCESS;
1999 }
2000 
2001 /**
2002  * Attempt to close all deferred closes (dynamics and cursors).
2003  * \tds
2004  */
2005 static void
2007 {
2008  TDSDYNAMIC *dyn, *next_dyn;
2009  TDSCURSOR *cursor, *next_cursor;
2010  int all_closed = 1;
2011 
2012  /* avoid recursions */
2013  tds->conn->pending_close = 0;
2014 
2015  /* scan all cursors to close */
2016  cursor = tds->conn->cursors;
2017  if (cursor)
2018  ++cursor->ref_count;
2019  for (; cursor; cursor = next_cursor) {
2020  next_cursor = cursor->next;
2021  if (next_cursor)
2022  ++next_cursor->ref_count;
2023 
2024  if (cursor->defer_close) {
2026  if (TDS_FAILED(tds_cursor_close(tds, cursor))
2028  all_closed = 0;
2029  } else {
2030  cursor->defer_close = 0;
2031  tds_cursor_dealloc(tds, cursor);
2032  }
2033  }
2034  tds_release_cursor(&cursor);
2035  }
2036 
2037  /* scan all dynamic to close */
2038  dyn = tds->conn->dyns;
2039  if (dyn)
2040  ++dyn->ref_count;
2041  for (; dyn; dyn = next_dyn) {
2042  next_dyn = dyn->next;
2043  if (next_dyn)
2044  ++next_dyn->ref_count;
2045 
2046  if (dyn->defer_close) {
2049  all_closed = 0;
2050  } else {
2051  dyn->defer_close = 0;
2052  }
2053  }
2054  tds_release_dynamic(&dyn);
2055  }
2056 
2057  if (!all_closed)
2058  tds->conn->pending_close = 1;
2059 }
2060 
2061 /**
2062  * tds_process_end() processes any of the DONE, DONEPROC, or DONEINPROC
2063  * tokens.
2064  * \param tds state information for the socket and the TDS protocol
2065  * \param marker TDS token number
2066  * \param flags_parm filled with bit flags (see TDS_DONE_ constants).
2067  * Is NULL nothing is returned
2068  */
2069 static TDSRET
2070 tds_process_end(TDSSOCKET * tds, int marker, int *flags_parm)
2071 {
2072  int more_results, was_cancelled, error, done_count_valid;
2073  int tmp;
2074  TDS_INT8 rows_affected;
2075 
2077 
2079 
2080  tds_get_smallint(tds); /* state */
2081 
2082  more_results = (tmp & TDS_DONE_MORE_RESULTS) != 0;
2083  was_cancelled = (tmp & TDS_DONE_CANCELLED) != 0;
2084  error = (tmp & TDS_DONE_ERROR) != 0;
2085  done_count_valid = (tmp & TDS_DONE_COUNT) != 0;
2086 
2087 
2088  tdsdump_log(TDS_DBG_FUNC, "tds_process_end: more_results = %d\n"
2089  "\t\twas_cancelled = %d\n"
2090  "\t\terror = %d\n"
2091  "\t\tdone_count_valid = %d\n", more_results, was_cancelled, error, done_count_valid);
2092 
2093  tds->in_row = false;
2094 
2095  if (tds->res_info) {
2096  tds->res_info->more_results = more_results;
2097  /* FIXME this should not happen !!! */
2098  if (tds->current_results == NULL)
2100 
2101  }
2102 
2103  if (flags_parm)
2104  *flags_parm = tmp;
2105 
2106  rows_affected = IS_TDS72_PLUS(tds->conn) ? tds_get_int8(tds) : tds_get_int(tds);
2107  tdsdump_log(TDS_DBG_FUNC, " rows_affected = %" PRId64 "\n", rows_affected);
2108 
2109  if (was_cancelled || (!more_results && !tds->in_cancel)) {
2110  tdsdump_log(TDS_DBG_FUNC, "tds_process_end() state set to TDS_IDLE\n");
2111  /* reset of in_cancel should must done before setting IDLE */
2112  tds->in_cancel = 0;
2113  if (tds->bulk_query) {
2114  tds->out_flag = TDS_BULK;
2116  tds->bulk_query = 0;
2117  } else {
2119  if (tds->conn->pending_close)
2121  }
2122  }
2123 
2124  if (IS_TDSDEAD(tds))
2125  return TDS_FAIL;
2126 
2127  /*
2128  * rows affected is in the tds struct because a query may affect rows but
2129  * have no result set.
2130  */
2131 
2132  if (done_count_valid)
2133  tds->rows_affected = rows_affected;
2134  else
2136 
2137  if (IS_TDSDEAD(tds))
2138  return TDS_FAIL;
2139 
2140  return was_cancelled ? TDS_CANCELLED : TDS_SUCCESS;
2141 }
2142 
2143 static TDSRET
2145 {
2146  unsigned len = tds_get_usmallint(tds);
2147  if (len) {
2148  /* protocol (byte, 0 for ip)
2149  * port (short, not 0)
2150  * us_varchar
2151  */
2152  TDS_TINYINT protocol;
2153  TDS_USMALLINT port, address_len;
2154  if (len < 5)
2155  return TDS_FAIL;
2156  protocol = tds_get_byte(tds);
2157  port = tds_get_usmallint(tds);
2158  address_len = tds_get_usmallint(tds);
2159  len -= 5;
2160  if (address_len * 2 < len)
2161  return TDS_FAIL;
2162  if (protocol == 0 && port != 0 && tds->login) {
2163  tds->login->routing_port = port;
2164  tds_dstr_get(tds, &tds->login->routing_address, address_len);
2165  tds_get_n(tds, NULL, len - 2 * address_len);
2166  } else {
2167  tds_get_n(tds, NULL, len);
2168  }
2169  }
2171  return TDS_SUCCESS;
2172 }
2173 
2174 /**
2175  * tds_process_env_chg()
2176  * when ever certain things change on the server, such as database, character
2177  * set, language, or block size. A environment change message is generated
2178  * There is no action taken currently, but certain functions at the CLI level
2179  * that return the name of the current database will need to use this.
2180  * \tds
2181  */
2182 static TDSRET
2184 {
2185  unsigned int size;
2186  TDS_TINYINT type;
2187  char *oldval = NULL;
2188  char *newval = NULL;
2189  char **dest;
2190  int new_block_size;
2191  int lcid;
2192  int memrc = 0;
2193 
2195 
2197  if (TDS_UNLIKELY(size < 1)) {
2198  tdsdump_log(TDS_DBG_ERROR, "Got invalid size %u\n", size);
2200  return TDS_FAIL;
2201  }
2202 
2203  /*
2204  * this came in a patch, apparently someone saw an env message
2205  * that was different from what we are handling? -- brian
2206  * changed back because it won't handle multibyte chars -- 7.0
2207  */
2208  /* tds_get_n(tds,NULL,size); */
2209 
2210  type = tds_get_byte(tds);
2211 
2212  /*
2213  * handle collate default change (if you change db or during login)
2214  * this environment is not a string so need different handles
2215  */
2216  if (type == TDS_ENV_SQLCOLLATION) {
2217  /* save new collation */
2218  size = tds_get_byte(tds);
2219  tdsdump_log(TDS_DBG_ERROR, "tds_process_env_chg(): %d bytes of collation data received\n", size);
2220  tdsdump_dump_buf(TDS_DBG_NETWORK, "tds->conn->collation was", tds->conn->collation, 5);
2221  memset(tds->conn->collation, 0, 5);
2222  if (size < 5) {
2224  } else {
2225  tds_get_n(tds, tds->conn->collation, 5);
2226  tds_get_n(tds, NULL, size - 5);
2227  lcid = TDS_GET_UA4LE(tds->conn->collation) & 0xffffflu;
2229  }
2230  tdsdump_dump_buf(TDS_DBG_NETWORK, "tds->conn->collation now", tds->conn->collation, 5);
2231  /* discard old one */
2233  return TDS_SUCCESS;
2234  }
2235 
2236  if (type == TDS_ENV_BEGINTRANS) {
2237  /* TODO check size */
2238  size = tds_get_byte(tds);
2241  return TDS_SUCCESS;
2242  }
2243 
2245  memset(tds->conn->tds72_transaction, 0, 8);
2248  return TDS_SUCCESS;
2249  }
2250 
2252  return tds_process_env_routing(tds);
2253 
2254  /* discard byte values, not still supported */
2255  /* TODO support them */
2257  /* discard rest of the packet */
2258  tds_get_n(tds, NULL, size - 1);
2259  return TDS_SUCCESS;
2260  }
2261 
2262  /* fetch the new value */
2263  memrc += tds_alloc_get_string(tds, &newval, tds_get_byte(tds));
2264 
2265  /* fetch the old value */
2266  memrc += tds_alloc_get_string(tds, &oldval, tds_get_byte(tds));
2267 
2268  if (memrc != 0) {
2269  free(newval);
2270  free(oldval);
2271  return TDS_FAIL;
2272  }
2273 
2274  dest = NULL;
2275  switch (type) {
2276  case TDS_ENV_PACKSIZE:
2277  new_block_size = atoi(newval);
2278  if (new_block_size >= 512) {
2279  tdsdump_log(TDS_DBG_INFO1, "changing block size from %s to %d\n", oldval, new_block_size);
2280  /*
2281  * Is possible to have a shrink if server limits packet
2282  * size more than what we specified
2283  */
2284  /* Reallocate buffer if possible (strange values from server or out of memory) use older buffer */
2285  tds_realloc_socket(tds, new_block_size);
2286  }
2287  break;
2288  case TDS_ENV_DATABASE:
2289  dest = &tds->conn->env.database;
2290  break;
2291  case TDS_ENV_LANG:
2292  dest = &tds->conn->env.language;
2293  break;
2294  case TDS_ENV_CHARSET:
2295  tdsdump_log(TDS_DBG_FUNC, "server indicated charset change to \"%s\"\n", newval);
2296  dest = &tds->conn->env.charset;
2297  tds_srv_charset_changed(tds->conn, newval);
2298  break;
2299  }
2300  if (tds->env_chg_func) {
2301  (*(tds->env_chg_func)) (tds, type, oldval, newval);
2302  }
2303 
2304  free(oldval);
2305  if (newval) {
2306  if (dest) {
2307  free(*dest);
2308  *dest = newval;
2309  } else
2310  free(newval);
2311  }
2312 
2313  return TDS_SUCCESS;
2314 }
2315 
2316 /**
2317  * tds_process_info() is called for INFO, ERR, or EED tokens and is responsible
2318  * for calling the CLI's message handling routine
2319  * \returns TDS_SUCCESS if informational, TDS_FAIL if error.
2320  */
2321 static TDSRET
2323 {
2324  int rc;
2325  unsigned int len_sqlstate;
2326  int has_eed = 0;
2327  TDSMESSAGE msg;
2328 
2330 
2331  if (!tds->in_row)
2333 
2334  /* make sure message has been freed */
2335  memset(&msg, 0, sizeof(TDSMESSAGE));
2336 
2337  /* packet length */
2339 
2340  /* message number */
2341  msg.msgno = tds_get_int(tds);
2342 
2343  /* msg state */
2344  msg.state = tds_get_byte(tds);
2345 
2346  /* msg level */
2347  msg.severity = tds_get_byte(tds);
2348 
2349  /* determine if msg or error */
2350  switch (marker) {
2351  case TDS_EED_TOKEN:
2352  if (msg.severity <= 10)
2353  msg.priv_msg_type = 0;
2354  else
2355  msg.priv_msg_type = 1;
2356 
2357  /* read SQL state */
2358  len_sqlstate = tds_get_byte(tds);
2359  msg.sql_state = tds_new(char, len_sqlstate + 1);
2360  if (!msg.sql_state) {
2361  tds_free_msg(&msg);
2362  return TDS_FAIL;
2363  }
2364 
2365  tds_get_n(tds, msg.sql_state, len_sqlstate);
2366  msg.sql_state[len_sqlstate] = '\0';
2367 
2368  /* do a better mapping using native errors */
2369  if (strcmp(msg.sql_state, "ZZZZZ") == 0)
2370  TDS_ZERO_FREE(msg.sql_state);
2371 
2372  /* if has_eed = 1, extended error data follows */
2373  has_eed = tds_get_byte(tds);
2374 
2375  /* junk status and transaction state */
2377  break;
2378  case TDS_INFO_TOKEN:
2379  msg.priv_msg_type = 0;
2380  break;
2381  case TDS_ERROR_TOKEN:
2382  msg.priv_msg_type = 1;
2383  break;
2384  default:
2385  tdsdump_log(TDS_DBG_ERROR, "tds_process_info() called with unknown marker '%d'!\n", (int) marker);
2386  tds_free_msg(&msg);
2387  return TDS_FAIL;
2388  }
2389 
2390  tdsdump_log(TDS_DBG_ERROR, "tds_process_info() reading message %d from server\n", msg.msgno);
2391 
2392  rc = 0;
2393  /* the message */
2395 
2396  /* server name */
2398 
2399  if ((!msg.server || !msg.server[0]) && tds->login) {
2400  TDS_ZERO_FREE(msg.server);
2401  if (-1 == asprintf(&msg.server, "[%s]", tds_dstr_cstr(&tds->login->server_name))) {
2402  tdsdump_log(TDS_DBG_ERROR, "out of memory (%d), %s\n", errno, strerror(errno));
2403  return TDS_FAIL;
2404  }
2405  }
2406 
2407  /* stored proc name if available */
2409 
2410  /* line number in the sql statement where the problem occured */
2412 
2413  /*
2414  * If the server doesen't provide an sqlstate, map one via server native errors
2415  * I'm assuming there is not a protocol I'm missing to fetch these from the server?
2416  * I know sybase has an sqlstate column in it's sysmessages table, mssql doesn't and
2417  * TDS_EED_TOKEN is not being called for me.
2418  */
2419  if (msg.sql_state == NULL)
2421 
2422 
2423  /* In case extended error data is sent, we just try to discard it */
2424  if (has_eed == 1) {
2425  int next_marker;
2426  for (;;) {
2427  switch (next_marker = tds_get_byte(tds)) {
2428  case TDS5_PARAMFMT_TOKEN:
2429  case TDS5_PARAMFMT2_TOKEN:
2430  case TDS5_PARAMS_TOKEN:
2431  if (TDS_FAILED(tds_process_default_tokens(tds, next_marker)))
2432  --rc;
2433  continue;
2434  }
2435  break;
2436  }
2438  }
2439 
2440  /*
2441  * call the msg_handler that was set by an upper layer
2442  * (dblib, ctlib or some other one). Call it with the pointer to
2443  * the "parent" structure.
2444  */
2445 
2446  if (rc != 0) {
2447  tds_free_msg(&msg);
2448  return TDS_FAIL;
2449  }
2450 
2451  /* special case, */
2452  if (marker == TDS_EED_TOKEN && tds->cur_dyn && !TDS_IS_MSSQL(tds) && msg.msgno == 2782) {
2453  /* we must emulate prepare */
2454  tds->cur_dyn->emulated = 1;
2456  } else if (marker == TDS_INFO_TOKEN && msg.msgno == 16954 && TDS_IS_MSSQL(tds)
2458  /* here mssql say "Executing SQL directly; no cursor." opening cursor */
2459  } else {
2460 
2461  if (tds_get_ctx(tds)->msg_handler) {
2462  tdsdump_log(TDS_DBG_ERROR, "tds_process_info() calling client msg handler\n");
2463  tds_get_ctx(tds)->msg_handler(tds_get_ctx(tds), tds, &msg);
2464  } else if (msg.msgno) {
2466  "Msg %d, Severity %d, State %d, Server %s, Line %d\n%s\n",
2467  msg.msgno,
2468  msg.severity ,
2469  msg.state, msg.server, msg.line_number, msg.message);
2470  }
2471  }
2472 
2473  if (!tds->conn->server) {
2474  tds->conn->server = msg.server;
2475  msg.server = NULL;
2476  }
2477  tds_free_msg(&msg);
2478 
2479  tdsdump_log(TDS_DBG_ERROR, "tds_process_info() returning TDS_SUCCESS\n");
2480 
2481  return TDS_SUCCESS;
2482 }
2483 
2484 /**
2485  * Reads a string from wire in a new allocated buffer
2486  * \tds
2487  * \param string output string
2488  * \param len length of string to read
2489  * \returns 0 for success, -1 on error.
2490  */
2491 static int
2492 tds_alloc_get_string(TDSSOCKET * tds, char **string, size_t len)
2493 {
2494  char *s;
2495  size_t out_len;
2496 
2498 
2499  /* assure sufficient space for every conversion */
2500  s = tds_new(char, len * 4 + 1);
2501  out_len = tds_get_string(tds, len, s, len * 4);
2502  if (!s) {
2503  *string = NULL;
2504  return -1;
2505  }
2506  s = (char*) realloc(s, out_len + 1);
2507  s[out_len] = '\0';
2508  *string = s;
2509  return 0;
2510 }
2511 
2512 /**
2513  * \remarks Process the incoming token stream until it finds
2514  * an end token (DONE, DONEPROC, DONEINPROC) with the cancel flag set.
2515  * At that point the connection should be ready to handle a new query.
2516  * \tds
2517  */
2518 TDSRET
2520 {
2522 
2523  /* silly cases, nothing to do */
2524  if (!tds->in_cancel)
2525  return TDS_SUCCESS;
2526  /* TODO handle cancellation sending data */
2527  if (tds->state != TDS_PENDING)
2528  return TDS_SUCCESS;
2529 
2530  /* TODO support TDS5 cancel, wait for cancel packet first, then wait for done */
2531  for (;;) {
2532  TDS_INT result_type;
2533 
2534  switch (tds_process_tokens(tds, &result_type, NULL, 0)) {
2535  case TDS_FAIL:
2536  return TDS_FAIL;
2537  case TDS_CANCELLED:
2538  case TDS_SUCCESS:
2539  case TDS_NO_MORE_RESULTS:
2540  return TDS_SUCCESS;
2541  }
2542  }
2543 }
2544 
2545 /**
2546  * Finds a dynamic given string id
2547  * \return dynamic or NULL is not found
2548  * \param conn state information for the socket and the TDS protocol
2549  * \param id dynamic id to search
2550  */
2551 TDSDYNAMIC *
2553 {
2554  TDSDYNAMIC *curr;
2555 
2557 
2558  for (curr = conn->dyns; curr != NULL; curr = curr->next) {
2559  if (!strcmp(curr->id, id))
2560  return curr;
2561  }
2562  return NULL;
2563 }
2564 
2565 /**
2566  * tds_process_dynamic()
2567  * finds the element of the dyns array for the id
2568  * \tds
2569  * \return allocated dynamic or NULL on failure.
2570  */
2571 static TDSDYNAMIC *
2573 {
2574  unsigned int token_sz;
2575  unsigned char type;
2576  TDS_TINYINT id_len, drain = 0;
2577  char id[TDS_MAX_DYNID_LEN + 1];
2578 
2580 
2581  token_sz = tds_get_usmallint(tds);
2582  type = tds_get_byte(tds);
2583  tds_get_byte(tds); /* status */
2584  /* handle only acknowledge */
2585  if (type != TDS_DYN_ACK) {
2586  tdsdump_log(TDS_DBG_ERROR, "Unrecognized TDS5_DYN type %x\n", type);
2587  tds_get_n(tds, NULL, token_sz - 2);
2588  return NULL;
2589  }
2590  id_len = tds_get_byte(tds);
2591  if (id_len > TDS_MAX_DYNID_LEN) {
2592  drain = id_len - TDS_MAX_DYNID_LEN;
2593  id_len = TDS_MAX_DYNID_LEN;
2594  }
2595  id_len = (TDS_TINYINT) tds_get_string(tds, id_len, id,
2597  id[id_len] = '\0';
2598  if (drain) {
2599  tds_get_n(tds, NULL, drain);
2600  }
2601  return tds_lookup_dynamic(tds->conn, id);
2602 }
2603 
2604 /**
2605  * Process results from dynamic.
2606  * \tds
2607  */
2608 static TDSRET
2610 {
2611  unsigned int col, num_cols;
2612  TDSCOLUMN *curcol;
2613  TDSPARAMINFO *info;
2614  TDSDYNAMIC *dyn;
2615  TDSRET rc;
2616 
2618 
2619  tds_get_usmallint(tds); /* header size */
2620  num_cols = tds_get_usmallint(tds);
2621 
2622  /* read number of columns and allocate the columns structure */
2623  if ((info = tds_alloc_results(num_cols)) == NULL)
2624  return TDS_FAIL;
2625  if (tds->cur_dyn) {
2626  dyn = tds->cur_dyn;
2628  dyn->res_info = info;
2629  } else {
2631  tds->param_info = info;
2632  }
2634 
2635  for (col = 0; col < info->num_cols; col++) {
2636  curcol = info->columns[col];
2637 
2638  rc = tds_get_data_info(tds, curcol, 1);
2639  if (TDS_FAILED(rc))
2640  return rc;
2641 
2642  /* skip locale information */
2644  }
2645 
2646  return tds_alloc_row(info);
2647 }
2648 
2649 /**
2650  * Process new TDS 5.0 token for describing output parameters
2651  * \tds
2652  */
2653 static TDSRET
2655 {
2656  unsigned int col, num_cols;
2657  TDSCOLUMN *curcol;
2658  TDSPARAMINFO *info;
2659  TDSDYNAMIC *dyn = NULL;
2660 
2662 
2663  tds_get_uint(tds); /* header size */
2664  num_cols = tds_get_usmallint(tds);
2665 
2666  /* read number of columns and allocate the columns structure */
2667  if ((info = tds_alloc_results(num_cols)) == NULL)
2668  return TDS_FAIL;
2669  if (tds->cur_dyn) {
2670  dyn = tds->cur_dyn;
2672  dyn->res_info = info;
2673  } else {
2675  tds->param_info = info;
2676  }
2678 
2679  for (col = 0; col < info->num_cols; col++) {
2680  curcol = info->columns[col];
2681 
2682  /* TODO reuse tds_get_data_info code, sligthly different */
2683 
2684  /* column name */
2686 
2687  /* column status */
2688  curcol->column_flags = tds_get_int(tds);
2689  curcol->column_nullable = (curcol->column_flags & 0x20) > 0;
2690 
2691  /* user type */
2692  curcol->column_usertype = tds_get_int(tds);
2693 
2694  /* column type */
2695  TDS_GET_COLUMN_TYPE(curcol);
2696 
2697  TDS_GET_COLUMN_INFO(tds, curcol);
2698 
2699  /* Adjust column size according to client's encoding */
2700  curcol->on_server.column_size = curcol->column_size;
2702 
2703  /* discard Locale */
2705 
2706  tdsdump_log(TDS_DBG_INFO1, "elem %d:\n", col);
2707  tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", tds_dstr_cstr(&curcol->column_name));
2708  tdsdump_log(TDS_DBG_INFO1, "\tflags=%x utype=%d type=%d varint=%d\n",
2709  curcol->column_flags, curcol->column_usertype, curcol->column_type, curcol->column_varint_size);
2710  tdsdump_log(TDS_DBG_INFO1, "\tcolsize=%d prec=%d scale=%d\n",
2711  curcol->column_size, curcol->column_prec, curcol->column_scale);
2712 
2713  /*
2714  * As of ASE 16.0, Sybase servers have started allowing
2715  * dynamic query (prepared statement) declarations with
2716  * IMAGE or (N)TEXT parameters. However, subsequent
2717  * attempts to instantiate these queries have been failing
2718  * with message 3805, "The token datastream length was not
2719  * correct." In such cases, switch on dynamic query
2720  * emulation (as already needed for older Sybase versions
2721  * that immediately reject these declarations) and
2722  * explicitly discard column information to avoid
2723  * misconstruing the status of subsequent queries that
2724  * yield no row results.
2725  */
2726  if (dyn != NULL && !TDS_IS_MSSQL(tds)
2727  && is_blob_col(curcol)) {
2728  dyn->emulated = 1;
2730  dyn = NULL;
2731  }
2732  }
2733 
2734  if (tds->cur_dyn != NULL && tds->cur_dyn->emulated) {
2736  }
2737 
2738  return tds_alloc_row(info);
2739 }
2740 
2741 /**
2742  * tds_get_token_size() returns the size of a fixed length token
2743  * used by tds_process_cancel() to determine how to read past a token
2744  * \param marker token type.
2745  */
2746 int
2748 {
2749  /* TODO finish */
2750  switch (marker) {
2751  case TDS_DONE_TOKEN:
2752  case TDS_DONEPROC_TOKEN:
2753  case TDS_DONEINPROC_TOKEN:
2754  return 8;
2756  return 4;
2757  case TDS_PROCID_TOKEN:
2758  return 8;
2759  default:
2760  return 0;
2761  }
2762 }
2763 
2764 
2765 /**
2766  * tds_process_compute_names() processes compute result sets.
2767  * \tds
2768  */
2769 static TDSRET
2771 {
2772  int hdrsize;
2773  int num_cols = 0;
2774  TDS_USMALLINT compute_id = 0;
2776  int col;
2777 
2778  struct namelist *head = NULL, *cur;
2779 
2781 
2782  hdrsize = tds_get_usmallint(tds);
2783  tdsdump_log(TDS_DBG_INFO1, "processing tds5 compute names. hdrsize = %d\n", hdrsize);
2784 
2785  /*
2786  * compute statement id which this relates
2787  * to. You can have more than one compute
2788  * statement in a SQL statement
2789  */
2790  compute_id = tds_get_usmallint(tds);
2791 
2792  if ((num_cols = tds_read_namelist(tds, hdrsize - 2, &head, 0)) <= 0)
2793  return TDS_FAIL;
2794 
2795  tdsdump_log(TDS_DBG_INFO1, "processing tds5 compute names. num_cols = %d\n", num_cols);
2796 
2797  if ((tds->comp_info = tds_alloc_compute_results(tds, num_cols, 0)) == NULL)
2798  goto memory_error;
2799 
2800  tdsdump_log(TDS_DBG_INFO1, "processing tds5 compute names. num_comp_info = %d\n", tds->num_comp_info);
2801 
2802  info = tds->comp_info[tds->num_comp_info - 1];
2804 
2805  info->computeid = compute_id;
2806 
2807  cur = head;
2808  for (col = 0; col < num_cols; col++) {
2809  TDSCOLUMN *curcol = info->columns[col];
2810 
2811  if (!tds_dstr_copy(&curcol->column_name, cur->name))
2812  goto memory_error;
2813 
2814  cur = cur->next;
2815  }
2817  return TDS_SUCCESS;
2818 
2819 memory_error:
2821  return TDS_FAIL;
2822 }
2823 
2824 /**
2825  * tds7_process_compute_result() processes compute result sets for TDS 7/8.
2826  * They is are very similar to normal result sets.
2827  * \tds
2828  */
2829 static TDSRET
2831 {
2832  unsigned int col, num_cols;
2833  TDS_TINYINT by_cols;
2834  TDS_SMALLINT *cur_by_col;
2835  TDS_USMALLINT compute_id;
2836  TDSCOLUMN *curcol;
2838  TDSRET rc;
2839 
2841 
2842  /* compute without result should never happens */
2843  if (!tds->res_info)
2844  return TDS_FAIL;
2845 
2846  /*
2847  * number of compute columns returned - so
2848  * COMPUTE SUM(x), AVG(x)... would return
2849  * num_cols = 2
2850  */
2851 
2852  num_cols = tds_get_usmallint(tds);
2853 
2854  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. num_cols = %u\n", num_cols);
2855 
2856  /*
2857  * compute statement id which this relates
2858  * to. You can have more than one compute
2859  * statement in a SQL statement
2860  */
2861 
2862  compute_id = tds_get_usmallint(tds);
2863 
2864  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. compute_id = %u\n", compute_id);
2865  /*
2866  * number of "by" columns in compute - so
2867  * COMPUTE SUM(x) BY a, b, c would return
2868  * by_cols = 3
2869  */
2870 
2871  by_cols = tds_get_byte(tds);
2872  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. by_cols = %d\n", by_cols);
2873 
2874  if ((tds->comp_info = tds_alloc_compute_results(tds, num_cols, by_cols)) == NULL)
2875  return TDS_FAIL;
2876 
2877  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. num_comp_info = %d\n", tds->num_comp_info);
2878 
2879  info = tds->comp_info[tds->num_comp_info - 1];
2881 
2882  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. point 0\n");
2883 
2884  info->computeid = compute_id;
2885 
2886  /*
2887  * the by columns are a list of the column
2888  * numbers in the select statement
2889  */
2890 
2891  cur_by_col = info->bycolumns;
2892  for (col = 0; col < by_cols; col++) {
2893  *cur_by_col = tds_get_smallint(tds);
2894  cur_by_col++;
2895  }
2896  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. point 1\n");
2897 
2898  for (col = 0; col < num_cols; col++) {
2899  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. point 2\n");
2900  curcol = info->columns[col];
2901 
2902  curcol->column_operator = tds_get_byte(tds);
2903  curcol->column_operand = tds_get_smallint(tds);
2904 
2905  rc = tds7_get_data_info(tds, curcol);
2906  if (TDS_FAILED(rc))
2907  return rc;
2908 
2909  if (tds_dstr_isempty(&curcol->column_name))
2910  if (!tds_dstr_copy(&curcol->column_name, tds_pr_op(curcol->column_operator)))
2911  return TDS_FAIL;
2912  }
2913 
2914  /* all done now allocate a row for tds_process_row to use */
2915  tdsdump_log(TDS_DBG_INFO1, "processing tds7 compute result. point 5 \n");
2916  return tds_alloc_compute_row(info);
2917 }
2918 
2919 /**
2920  * Reads cursor command results.
2921  * This contains status of cursors.
2922  * \tds
2923  */
2924 static TDSRET
2926 {
2927  TDS_USMALLINT hdrsize;
2928  TDS_INT cursor_id;
2929  TDS_TINYINT namelen;
2930  TDS_USMALLINT cursor_status;
2931  TDSCURSOR *cursor;
2932 
2934 
2935  hdrsize = tds_get_usmallint(tds);
2936  cursor_id = tds_get_int(tds);
2937  hdrsize -= sizeof(TDS_INT);
2938  if (cursor_id == 0){
2939  namelen = tds_get_byte(tds);
2940  hdrsize -= 1;
2941  /* discard name */
2942  tds_get_n(tds, NULL, namelen);
2943  hdrsize -= namelen;
2944  }
2945  tds_get_byte(tds); /* cursor command */
2946  cursor_status = tds_get_usmallint(tds);
2947  hdrsize -= 3;
2948 
2949  if (hdrsize == sizeof(TDS_INT))
2950  tds_get_int(tds); /* row count TODO useless ?? */
2951 
2952  if (tds->cur_cursor) {
2953  cursor = tds->cur_cursor;
2954  cursor->cursor_id = cursor_id;
2955  cursor->srv_status = cursor_status;
2956  if ((cursor_status & TDS_CUR_ISTAT_DEALLOC) != 0)
2957  tds_cursor_deallocated(tds->conn, cursor);
2958  }
2959  return TDS_SUCCESS;
2960 }
2961 
2962 /**
2963  * Process option cmd results.
2964  * This token is available only on TDS 5.0 (Sybase).
2965  * \tds
2966  */
2967 static TDSRET
2969 {
2970  TDS_INT command;
2972  TDS_TINYINT argsize;
2973  TDS_INT arg;
2974 
2976 
2977  tdsdump_log(TDS_DBG_INFO1, "tds5_process_optioncmd()\n");
2978 
2979  if (!IS_TDS50(tds->conn))
2980  return TDS_FAIL;
2981 
2982  tds_get_usmallint(tds); /* length */
2984  option = tds_get_byte(tds);
2985  argsize = tds_get_byte(tds);
2986 
2987  switch (argsize) {
2988  case 0:
2989  arg = 0;
2990  break;
2991  case 1:
2992  arg = tds_get_byte(tds);
2993  break;
2994  case 4:
2995  arg = tds_get_int(tds);
2996  break;
2997  default:
2998  tdsdump_log(TDS_DBG_INFO1, "oops: cannot process option %d of size %d\n", option, argsize);
2999  /* ignore argument */
3000  tds_get_n(tds, NULL, argsize);
3001  return TDS_FAIL;
3002  }
3003  tdsdump_log(TDS_DBG_INFO1, "received option %d value %d\n", option, arg);
3004 
3005  if (command != TDS_OPT_INFO)
3006  return TDS_FAIL;
3007 
3008  tds->option_value = arg;
3009 
3010  return TDS_SUCCESS;
3011 }
3012 
3013 /**
3014  * Returns string representation for a given operation
3015  * \param op operation code
3016  * \return string representation. Empty if not found.
3017  */
3018 static const char *
3019 tds_pr_op(int op)
3020 {
3021 /** \cond HIDDEN_SYMBOLS */
3022 #define TYPE(con, s) case con: return s; break
3023 /** \endcond */
3024  switch (op) {
3025  TYPE(SYBAOPAVG, "avg");
3026  TYPE(SYBAOPAVGU, "avg");
3027  TYPE(SYBAOPCNT, "count");
3028  TYPE(SYBAOPCNTU, "count");
3029  TYPE(SYBAOPMAX, "max");
3030  TYPE(SYBAOPMIN, "min");
3031  TYPE(SYBAOPSUM, "sum");
3032  TYPE(SYBAOPSUMU, "sum");
3033  TYPE(SYBAOPCHECKSUM_AGG, "checksum_agg");
3034  TYPE(SYBAOPCNT_BIG, "count");
3035  TYPE(SYBAOPSTDEV, "stdevp");
3036  TYPE(SYBAOPSTDEVP, "stdevp");
3037  TYPE(SYBAOPVAR, "var");
3038  TYPE(SYBAOPVARP, "varp");
3039  default:
3040  break;
3041  }
3042  return "";
3043 #undef TYPE
3044 }
3045 
3046 /**
3047  * Returns string representation of the given type.
3048  * \param type data type
3049  * \return type as string. Empty if not found.
3050  */
3051 const char *
3053 {
3054 /** \cond HIDDEN_SYMBOLS */
3055 #define TYPE(con, s) case con: return s; break
3056 /** \endcond */
3057  switch (type) {
3058  TYPE(SYBAOPAVG, "avg");
3059  TYPE(SYBAOPCNT, "count");
3060  TYPE(SYBAOPMAX, "max");
3061  TYPE(SYBAOPMIN, "min");
3062  TYPE(SYBAOPSUM, "sum");
3063 
3064  TYPE(SYBBINARY, "binary");
3065  TYPE(SYBLONGBINARY, "longbinary");
3066  TYPE(SYBBIT, "bit");
3067  TYPE(SYBBITN, "bit-null");
3068  TYPE(SYBCHAR, "char");
3069  TYPE(SYBDATETIME4, "smalldatetime");
3070  TYPE(SYBDATETIME, "datetime");
3071  TYPE(SYBDATETIMN, "datetime-null");
3072  TYPE(SYBDECIMAL, "decimal");
3073  TYPE(SYBFLT8, "float");
3074  TYPE(SYBFLTN, "float-null");
3075  TYPE(SYBIMAGE, "image");
3076  TYPE(SYBINT1, "tinyint");
3077  TYPE(SYBINT2, "smallint");
3078  TYPE(SYBINT4, "int");
3079  TYPE(SYBINT8, "bigint");
3080  TYPE(SYBUINT1, "unsigned tinyint");
3081  TYPE(SYBUINT2, "unsigned smallint");
3082  TYPE(SYBUINT4, "unsigned int");
3083  TYPE(SYBUINT8, "unsigned bigint");
3084  TYPE(SYBINTN, "integer-null");
3085  TYPE(SYBMONEY4, "smallmoney");
3086  TYPE(SYBMONEY, "money");
3087  TYPE(SYBMONEYN, "money-null");
3088  TYPE(SYBNTEXT, "UCS-2 text");
3089  TYPE(SYBNVARCHAR, "UCS-2 varchar");
3090  TYPE(SYBNUMERIC, "numeric");
3091  TYPE(SYBREAL, "real");
3092  TYPE(SYBTEXT, "text");
3093  TYPE(SYBUNIQUE, "uniqueidentifier");
3094  TYPE(SYBVARBINARY, "varbinary");
3095  TYPE(SYBVARCHAR, "varchar");
3096  TYPE(SYBVARIANT, "variant");
3097  TYPE(SYBVOID, "void");
3098  TYPE(XSYBBINARY, "xbinary");
3099  TYPE(XSYBCHAR, "xchar");
3100  TYPE(XSYBNCHAR, "x UCS-2 char");
3101  TYPE(XSYBNVARCHAR, "x UCS-2 varchar");
3102  TYPE(XSYBVARBINARY, "xvarbinary");
3103  TYPE(XSYBVARCHAR, "xvarchar");
3104  TYPE(SYBMSXML, "xml");
3105  TYPE(SYBMSDATE, "date");
3106  TYPE(SYBMSTIME, "time");
3107  TYPE(SYBMSDATETIME2, "datetime2");
3108  TYPE(SYBMSDATETIMEOFFSET, "datetimeoffset");
3109  TYPE(SYBDATE, "date");
3110  TYPE(SYBTIME, "time");
3111  TYPE(SYB5BIGTIME, "bigtime");
3112  TYPE(SYB5BIGDATETIME, "bigdatetime");
3113  default:
3114  break;
3115  }
3116  return "";
3117 #undef TYPE
3118 }
3119 
3120 /**
3121  * Returns string representation for a given token type
3122  * \param marker token type
3123  * \return string representation. Empty if not token not valid.
3124  */
3125 static const char *
3126 tds_token_name(unsigned char marker)
3127 {
3128  switch (marker) {
3129 
3130  case TDS5_PARAMFMT2_TOKEN:
3131  return "TDS5_PARAMFMT2";
3132  case TDS_ORDERBY2_TOKEN:
3133  return "ORDERBY2";
3134  case TDS_ROWFMT2_TOKEN:
3135  return "ROWFMT2";
3136  case TDS_LOGOUT_TOKEN:
3137  return "LOGOUT";
3139  return "RETURNSTATUS";
3140  case TDS_PROCID_TOKEN:
3141  return "PROCID";
3142  case TDS7_RESULT_TOKEN:
3143  return "TDS7_RESULT";
3144  case TDS_CURINFO_TOKEN:
3145  return "TDS_CURINFO";
3147  return "TDS7_COMPUTE_RESULT";
3148  case TDS_COLNAME_TOKEN:
3149  return "COLNAME";
3150  case TDS_COLFMT_TOKEN:
3151  return "COLFMT";
3152  case TDS_DYNAMIC2_TOKEN:
3153  return "DYNAMIC2";
3154  case TDS_TABNAME_TOKEN:
3155  return "TABNAME";
3156  case TDS_COLINFO_TOKEN:
3157  return "COLINFO";
3159  return "COMPUTE_NAMES";
3161  return "COMPUTE_RESULT";
3162  case TDS_ORDERBY_TOKEN:
3163  return "ORDERBY";
3164  case TDS_ERROR_TOKEN:
3165  return "ERROR";
3166  case TDS_INFO_TOKEN:
3167  return "INFO";
3168  case TDS_PARAM_TOKEN:
3169  return "PARAM";
3170  case TDS_LOGINACK_TOKEN:
3171  return "LOGINACK";
3173  return "CONTROL/FEATUREEXTACK";
3174  case TDS_ROW_TOKEN:
3175  return "ROW";
3176  case TDS_NBC_ROW_TOKEN:
3177  return "NBC_ROW";
3178  case TDS_CMP_ROW_TOKEN:
3179  return "CMP_ROW";
3180  case TDS5_PARAMS_TOKEN:
3181  return "TDS5_PARAMS";
3182  case TDS_CAPABILITY_TOKEN:
3183  return "CAPABILITY";
3184  case TDS_ENVCHANGE_TOKEN:
3185  return "ENVCHANGE";
3187  return "SESSIONSTATE";
3188  case TDS_EED_TOKEN:
3189  return "EED";
3190  case TDS_DBRPC_TOKEN:
3191  return "DBRPC";
3192  case TDS5_DYNAMIC_TOKEN:
3193  return "TDS5_DYNAMIC";
3194  case TDS5_PARAMFMT_TOKEN:
3195  return "TDS5_PARAMFMT";
3196  case TDS_AUTH_TOKEN:
3197  return "AUTH";
3198  case TDS_RESULT_TOKEN:
3199  return "RESULT";
3200  case TDS_DONE_TOKEN:
3201  return "DONE";
3202  case TDS_DONEPROC_TOKEN:
3203  return "DONEPROC";
3204  case TDS_DONEINPROC_TOKEN:
3205  return "DONEINPROC";
3206  case TDS_MSG_TOKEN:
3207  return "MSG";
3208 
3209  default:
3210  break;
3211  }
3212 
3213  return "";
3214 }
3215 
3216 /**
3217  * Adjust column size according to client's encoding
3218  * \tds
3219  * \param curcol column to adjust
3220  */
3221 static void
3223 {
3225  CHECK_COLUMN_EXTRA(curcol);
3226 
3227  if (is_unicode_type(curcol->on_server.column_type))
3228  curcol->char_conv = tds->conn->char_convs[client2ucs2];
3229 
3230  /* Sybase UNI(VAR)CHAR fields are transmitted via SYBLONGBINARY and in UTF-16 */
3231  if (curcol->on_server.column_type == SYBLONGBINARY && (
3232  curcol->column_usertype == USER_UNICHAR_TYPE ||
3233  curcol->column_usertype == USER_UNIVARCHAR_TYPE)) {
3234 #ifdef WORDS_BIGENDIAN
3235  static const char sybase_utf[] = "UTF-16BE";
3236 #else
3237  static const char sybase_utf[] = "UTF-16LE";
3238 #endif
3239 
3240  curcol->char_conv = tds_iconv_get(tds->conn, tds->conn->char_convs[client2ucs2]->from.charset.name, sybase_utf);
3241 
3242  /* fallback to UCS-2LE */
3243  /* FIXME should be useless. Does not works always */
3244  if (!curcol->char_conv)
3245  curcol->char_conv = tds->conn->char_convs[client2ucs2];
3246  }
3247 
3248  /* FIXME: and sybase ?? */
3249  if (!curcol->char_conv && IS_TDS7_PLUS(tds->conn) && is_ascii_type(curcol->on_server.column_type))
3251 
3252  if (!USE_ICONV || !curcol->char_conv)
3253  return;
3254 
3255  curcol->on_server.column_size = curcol->column_size;
3256  curcol->column_size = determine_adjusted_size(curcol->char_conv, curcol->column_size);
3257 
3258  tdsdump_log(TDS_DBG_INFO1, "adjust_character_column_size:\n"
3259  "\tServer charset: %s\n"
3260  "\tServer column_size: %d\n"
3261  "\tClient charset: %s\n"
3262  "\tClient column_size: %d\n",
3263  curcol->char_conv->to.charset.name,
3264  curcol->on_server.column_size,
3265  curcol->char_conv->from.charset.name,
3266  curcol->column_size);
3267 }
3268 
3269 /**
3270  * Allow for maximum possible size of converted data,
3271  * while being careful about integer division truncation.
3272  * All character data pass through iconv. It doesn't matter if the server side
3273  * is Unicode or not; even Latin1 text need conversion if,
3274  * for example, the client is UTF-8.
3275  * \param char_conv conversion structure
3276  * \param size unconverted byte size
3277  * \return maximum size for converted string
3278  */
3279 int
3280 determine_adjusted_size(const TDSICONV * char_conv, int size)
3281 {
3282  if (!char_conv)
3283  return size;
3284 
3285  /* avoid possible overflow */
3286  if (size >= 0x10000000)
3287  return 0x7fffffff;
3288 
3289  size *= char_conv->from.charset.max_bytes_per_char;
3290  if (size % char_conv->to.charset.min_bytes_per_char)
3291  size += char_conv->to.charset.min_bytes_per_char;
3292  size /= char_conv->to.charset.min_bytes_per_char;
3293 
3294  return size;
3295 }
3296 
3297 /** @} */
void * alloca(size_t)
#define TYPE(s)
#define TDS_GET_A2BE(ptr)
Definition: bytes.h:59
#define TDS_GET_UA4LE(ptr)
Definition: bytes.h:69
#define CHECK_COLUMN_EXTRA(column)
Definition: checks.h:34
#define CHECK_TDS_EXTRA(tds)
Definition: checks.h:31
#define CHECK_CONN_EXTRA(conn)
Definition: checks.h:39
#define CHECK_PARAMINFO_EXTRA(res_info)
Definition: checks.h:36
static TDSSOCKET * tds
Definition: collations.c:37
#define option
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
#define head
Definition: ct_nlmzip_i.h:138
static uch flags
static const struct name_t names[]
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
static int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
static int type
Definition: getdata.c:31
#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_dup(DSTR *s, const DSTR *src) TDS_WUR
Duplicate a string from another dynamic string.
Definition: tdsstring.c:135
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 TDSRET tds7_get_data_info(TDSSOCKET *tds, TDSCOLUMN *curcol)
Reads data information from wire \tds.
Definition: token.c:1497
const char * tds_prtype(int type)
Returns string representation of the given type.
Definition: token.c:3052
static void tds_free_namelist(struct namelist *head)
Frees list of names.
Definition: token.c:906
static TDSRET tds_process_colinfo(TDSSOCKET *tds, char **names, int num_names)
Reads column information.
Definition: token.c:1217
static TDSRET tds_process_cursor_tokens(TDSSOCKET *tds)
Reads cursor command results.
Definition: token.c:2925
static TDSRET tds_process_default_tokens(TDSSOCKET *tds, int marker)
tds_process_default_tokens() is a catch all function that is called to process tokens not known to ot...
Definition: token.c:123
static TDSRET tds_process_env_chg(TDSSOCKET *tds)
tds_process_env_chg() when ever certain things change on the server, such as database,...
Definition: token.c:2183
static TDSRET tds_process_featureextack(TDSSOCKET *tds)
Definition: token.c:1982
static TDSRET tds_process_dyn_result(TDSSOCKET *tds)
Process results from dynamic.
Definition: token.c:2609
static TDSRET tds_process_auth(TDSSOCKET *tds)
Process authentication token.
Definition: token.c:436
static TDSRET tds_process_col_fmt(TDSSOCKET *tds)
tds_process_col_fmt() is the other half of result set processing under TDS 4.2.
Definition: token.c:1032
static TDSRET tds5_process_result(TDSSOCKET *tds)
tds5_process_result() is the TDS 5.0 result set processing routine.
Definition: token.c:1718
TDSDYNAMIC * tds_lookup_dynamic(TDSCONNECTION *conn, const char *id)
Finds a dynamic given string id.
Definition: token.c:2552
static TDSDYNAMIC * tds_process_dynamic(TDSSOCKET *tds)
tds_process_dynamic() finds the element of the dyns array for the id \tds
Definition: token.c:2572
static const char * tds_pr_op(int op)
Returns string representation for a given operation.
Definition: token.c:3019
static TDSRET tds_process_info(TDSSOCKET *tds, int marker)
tds_process_info() is called for INFO, ERR, or EED tokens and is responsible for calling the CLI's me...
Definition: token.c:2322
static TDSRET tds7_process_compute_result(TDSSOCKET *tds)
tds7_process_compute_result() processes compute result sets for TDS 7/8.
Definition: token.c:2830
static void tds_process_pending_closes(TDSSOCKET *tds)
Attempt to close all deferred closes (dynamics and cursors).
Definition: token.c:2006
static TDSRET tds_process_compute(TDSSOCKET *tds)
tds_process_compute() processes compute rows and places them in the row buffer.
Definition: token.c:1889
static int tds71_read_table_names(TDSSOCKET *tds, int remainder, struct namelist **p_head)
Reads table names for TDS 7.1+.
Definition: token.c:1085
static TDSRET tds_process_end(TDSSOCKET *tds, int marker, int *flags_parm)
tds_process_end() processes any of the DONE, DONEPROC, or DONEINPROC tokens.
Definition: token.c:2070
static TDSRET tds_process_params_result_token(TDSSOCKET *tds)
tds_process_params_result_token() processes params on TDS5.
Definition: token.c:1369
static const char * tds_token_name(unsigned char marker)
Returns string representation for a given token type.
Definition: token.c:3126
int determine_adjusted_size(const TDSICONV *char_conv, int size)
Allow for maximum possible size of converted data, while being careful about integer division truncat...
Definition: token.c:3280
static TDSRET tds_process_col_name(TDSSOCKET *tds)
tds_process_col_name() is one half of the result set under TDS 4.2 it contains all the column names,...
Definition: token.c:984
static void adjust_character_column_size(TDSSOCKET *tds, TDSCOLUMN *curcol)
Adjust column size according to client's encoding \tds.
Definition: token.c:3222
static TDSRET tds_process_env_routing(TDSSOCKET *tds)
Definition: token.c:2144
TDSRET tds_process_login_tokens(TDSSOCKET *tds)
tds_process_login_tokens() is called after sending the login packet to the server.
Definition: token.c:296
int tds_get_token_size(int marker)
tds_get_token_size() returns the size of a fixed length token used by tds_process_cancel() to determi...
Definition: token.c:2747
static TDSRET tds_process_param_result_tokens(TDSSOCKET *tds)
Process parameters from networks.
Definition: token.c:1336
static TDSRET tds5_process_optioncmd(TDSSOCKET *tds)
Process option cmd results.
Definition: token.c:2968
static TDSRET tds_process_row(TDSSOCKET *tds)
tds_process_row() processes rows and places them in the row buffer.
Definition: token.c:1928
static TDSRET tds5_process_result2(TDSSOCKET *tds)
tds5_process_result2() is the new TDS 5.0 result set processing routine.
Definition: token.c:1768
TDSRET tds_process_tokens(TDSSOCKET *tds, TDS_INT *result_type, int *done_flags, unsigned flag)
process all streams.
Definition: token.c:510
static TDSRET tds7_process_result(TDSSOCKET *tds)
tds7_process_result() is the TDS 7.0 result set processing routine.
Definition: token.c:1553
static TDSRET tds_process_param_result(TDSSOCKET *tds, TDSPARAMINFO **info)
process output parameters of a stored procedure.
Definition: token.c:1278
static TDSRET tds_get_data_info(TDSSOCKET *tds, TDSCOLUMN *curcol, int is_param)
Reads data metadata from wire.
Definition: token.c:1630
static TDSRET tds_process_compute_result(TDSSOCKET *tds)
tds_process_compute_result() processes compute result sets.
Definition: token.c:1397
static TDSRET tds_process_compute_names(TDSSOCKET *tds)
tds_process_compute_names() processes compute result sets.
Definition: token.c:2770
static TDSRET tds5_process_dyn_result2(TDSSOCKET *tds)
Process new TDS 5.0 token for describing output parameters \tds.
Definition: token.c:2654
static int tds_read_namelist(TDSSOCKET *tds, int remainder, struct namelist **p_head, int large)
Reads list of names (usually table names) \tds.
Definition: token.c:926
TDSRET tds_process_simple_query(TDSSOCKET *tds)
Process results for simple query as "SET TEXTSIZE" or "USE dbname" If the statement returns results,...
Definition: token.c:861
static TDSRET tds_process_tabname(TDSSOCKET *tds)
Process list of table from network.
Definition: token.c:1168
TDSRET tds_process_cancel(TDSSOCKET *tds)
Definition: token.c:2519
static TDSRET tds_process_nbcrow(TDSSOCKET *tds)
tds_process_nbcrow() processes rows and places them in the row buffer.
Definition: token.c:1953
static int tds_alloc_get_string(TDSSOCKET *tds, char **string, size_t len)
Reads a string from wire in a new allocated buffer \tds.
Definition: token.c:2492
int i
if(yy_accept[yy_current_state])
int len
static MDB_envinfo info
Definition: mdb_load.c:37
const struct ncbi::grid::netcache::search::fields::SIZE size
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
const char * command
static char tmp[2048]
Definition: utf8.c:42
char * strerror(int n)
Definition: pcregrep.c:835
#define TDS_ENV_ROLLBACKTRANS
Definition: proto.h:135
#define TDS_UT_TIMESTAMP
Definition: proto.h:385
#define SYBAOPCNT
Definition: proto.h:242
#define SYBAOPSUM
Definition: proto.h:244
@ TDS_OPT_INFO
Report current setting of a specific option.
Definition: proto.h:267
#define TDS_DONEINPROC_TOKEN
Definition: proto.h:115
#define TDS_ENV_DATABASE
Definition: proto.h:127
#define TDS_COMPUTE_RESULT_TOKEN
Definition: proto.h:92
#define TDS7_COMPUTE_RESULT_TOKEN
Definition: proto.h:84
#define SYBAOPAVG
Definition: proto.h:246
#define TDS_DONE_TOKEN
Definition: proto.h:113
@ TDS_BULK
Definition: proto.h:338
#define TDS_TABNAME_TOKEN
Definition: proto.h:88
#define TDS_ENV_COMMITTRANS
Definition: proto.h:134
#define TDS_CURINFO_TOKEN
Definition: proto.h:121
#define TDS_LOGOUT_TOKEN
Definition: proto.h:80
#define TDS_NBC_ROW_TOKEN
Definition: proto.h:101
@ 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
@ XSYBVARBINARY
Definition: proto.h:197
@ XSYBNCHAR
Definition: proto.h:196
@ SYB5BIGTIME
Definition: proto.h:231
@ XSYBBINARY
Definition: proto.h:198
@ SYBMSXML
Definition: proto.h:202
@ SYB5BIGDATETIME
Definition: proto.h:230
@ SYBUINT1
Definition: proto.h:212
#define TDS_COLNAME_TOKEN
Definition: proto.h:85
#define TDS5_PARAMFMT_TOKEN
Definition: proto.h:110
#define TDS_ENVCHANGE_TOKEN
Definition: proto.h:105
#define TDS_CAPABILITY_TOKEN
Definition: proto.h:104
#define SYBAOPVARP
Definition: proto.h:256
#define TDS_ENV_PACKSIZE
Definition: proto.h:130
#define SYBAOPVAR
Definition: proto.h:255
@ TDS_DYN_ACK
Definition: proto.h:443
#define TDS_LOGINACK_TOKEN
Definition: proto.h:97
#define TDS_ENV_SQLCOLLATION
Definition: proto.h:132
#define TDS_ENV_ROUTING
Definition: proto.h:136
#define TDS_OPTIONCMD_TOKEN
Definition: proto.h:90
#define TDS_ORDERBY_TOKEN
Definition: proto.h:93
#define TDS_PROCID_TOKEN
Definition: proto.h:82
#define TDS5_PARAMS_TOKEN
Definition: proto.h:103
#define TDS_ORDERBY2_TOKEN
Definition: proto.h:77
#define TDS_DONEPROC_TOKEN
Definition: proto.h:114
#define TDS_PARAM_TOKEN
Definition: proto.h:96
#define TDS_ERROR_TOKEN
Definition: proto.h:94
#define TDS7_RESULT_TOKEN
Definition: proto.h:83
#define TDS_MSG_TOKEN
Definition: proto.h:79
#define TDS_ENV_CHARSET
Definition: proto.h:129
#define TDS_COMPUTE_NAMES_TOKEN
Definition: proto.h:91
#define TDS_RETURNSTATUS_TOKEN
Definition: proto.h:81
#define TDS_RESULT_TOKEN
Definition: proto.h:112
#define SYBAOPSTDEV
Definition: proto.h:253
#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_DYNAMIC2_TOKEN
Definition: proto.h:87
#define TDS_ROWFMT2_TOKEN
Definition: proto.h:78
#define TDS_EED_TOKEN
Definition: proto.h:107
#define TDS_CMP_ROW_TOKEN
Definition: proto.h:102
#define TDS_COLINFO_TOKEN
Definition: proto.h:89
#define SYBAOPCHECKSUM_AGG
Definition: proto.h:257
#define TDS_SESSIONSTATE_TOKEN
Definition: proto.h:106
#define TDS_COLFMT_TOKEN
Definition: proto.h:86
#define SYBAOPSTDEVP
Definition: proto.h:254
@ USER_UNICHAR_TYPE
Definition: proto.h:237
@ USER_UNIVARCHAR_TYPE
Definition: proto.h:238
#define TDS_CONTROL_FEATUREEXTACK_TOKEN
Definition: proto.h:98
#define SYBAOPMAX
Definition: proto.h:249
#define TDS_AUTH_TOKEN
Definition: proto.h:111
#define SYBAOPCNTU
Definition: proto.h:243
#define TDS_ENV_BEGINTRANS
Definition: proto.h:133
#define SYBAOPMIN
Definition: proto.h:248
#define TDS_ENV_LANG
Definition: proto.h:128
#define SYBAOPSUMU
Definition: proto.h:245
#define SYBAOPCNT_BIG
Definition: proto.h:252
#define TDS_INFO_TOKEN
Definition: proto.h:95
#define TDS_ROW_TOKEN
Definition: proto.h:100
#define SYBAOPAVGU
Definition: proto.h:247
#define tds_cursor_close
#define tds_alloc_results
#define tds_get_n
#define tds_submit_unprepare
#define tds_free_param_results
#define tds_free_all_results
#define tds_close_socket
#define tds_write_dump
#define tds_get_string
#define tds_release_dynamic
#define tds_free_msg
#define tds_alloc_lookup_sqlstate
#define tds_quote_id
#define tds_dynamic_deallocated
#define tds_alloc_param_result
#define tds_release_cursor
#define tds_unget_byte
#define tds_set_current_results
#define tds_alloc_compute_results
#define tdsdump_col
#define tds_cursor_dealloc
#define tds_get_byte
#define tds_get_usmallint
#define tds_dstr_get
#define tds_set_cur_dyn
#define tds_get_uint
#define tds_alloc_compute_row
#define tds_cursor_deallocated
#define tds_set_state
#define tds7_srv_charset_changed
#define tds_peek
#define tds_iconv_get
#define tds_alloc_param_data
#define tds_alloc_row
#define tdserror
#define tds_srv_charset_changed
#define tds_free_param_result
#define tds_realloc_socket
#define tds5_negotiate_set_msg_type
#define tds_free_results
#define asprintf
Definition: replacements.h:54
Holds list of names.
Definition: token.c:894
struct namelist * next
next element in the list
Definition: token.c:898
char * name
string name
Definition: token.c:896
TDSRET(* handle_next)(TDSSOCKET *tds, struct tds_authentication *auth, size_t len)
Definition: tds.h:1119
TDSRET(* free)(TDSCONNECTION *conn, struct tds_authentication *auth)
Definition: tds.h:1118
TDS_CAPABILITY_TYPE types[2]
Definition: tds.h:579
unsigned char type
Definition: tds.h:572
unsigned char values[32/2-2]
Definition: tds.h:574
unsigned char len
Definition: tds.h:573
tds_func_get_data * get_data
Definition: tds.h:711
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_TINYINT column_varint_size
size of length when reading from wire (0, 1, 2 or 4)
Definition: tds.h:773
TDS_TINYINT column_operator
Definition: tds.h:806
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
TDS_SMALLINT column_operand
Definition: tds.h:807
DSTR column_name
Definition: tds.h:787
unsigned int column_timestamp
Definition: tds.h:801
const TDSCOLUMNFUNCS * funcs
Definition: tds.h:762
unsigned int column_writeable
Definition: tds.h:796
unsigned char * column_data
Definition: tds.h:793
DSTR table_column_name
Definition: tds.h:788
TDS_TINYINT column_prec
precision for decimal/numeric
Definition: tds.h:775
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
unsigned int column_identity
Definition: tds.h:797
unsigned int column_key
Definition: tds.h:798
DSTR table_name
Definition: tds.h:786
unsigned int column_nullable
Definition: tds.h:795
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:784
TDS_TINYINT column_scale
scale for decimal/numeric
Definition: tds.h:776
struct tds_column::@124 on_server
TDS_INT column_flags
Definition: tds.h:764
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDS_INT column_usertype
Definition: tds.h:763
unsigned int column_hidden
Definition: tds.h:799
char * product_name
Definition: tds.h:1140
TDSENV env
environment is shared between all sessions
Definition: tds.h:1147
TDSAUTHENTICATION * authentication
Definition: tds.h:1203
unsigned int tds71rev1
Definition: tds.h:1169
TDSCURSOR * cursors
linked list of cursors allocated for this connection contains only cursors allocated on the server
Definition: tds.h:1153
TDS_UINT product_version
version of product (Sybase/MS and full version)
Definition: tds.h:1139
TDSICONV ** char_convs
Definition: tds.h:1161
TDSDYNAMIC * dyns
list of dynamic allocated for this connection contains only dynamic allocated on the server
Definition: tds.h:1158
unsigned int pending_close
true is connection has pending closing (cursors or dynamic)
Definition: tds.h:1170
TDS_UCHAR collation[5]
Definition: tds.h:1163
int spid
Definition: tds.h:1192
TDS_CAPABILITIES capabilities
Definition: tds.h:1166
char * server
Definition: tds.h:1204
TDS_UCHAR tds72_transaction[8]
Definition: tds.h:1164
TDS_CURSOR_STATE dealloc
Definition: tds.h:982
Holds informations about a cursor.
Definition: tds.h:1007
TDS_INT ref_count
reference counter so client can retain safely a pointer
Definition: tds.h:1009
TDSRESULTINFO * res_info
Definition: tds.h:1025
TDS_TINYINT defer_close
true if cursor was marker to be closed when connection is idle
Definition: tds.h:1016
TDS_INT cursor_id
cursor id returned by the server after cursor declare
Definition: tds.h:1011
struct tds_cursor * next
next in linked list, keep first
Definition: tds.h:1008
TDS_CURSOR_STATUS status
cursor parameter
Definition: tds.h:1023
TDS_USMALLINT srv_status
Definition: tds.h:1024
Holds information for a dynamic (also called prepared) query.
Definition: tds.h:1047
TDS_TINYINT defer_close
true if dynamic was marker to be closed when connection is idle
Definition: tds.h:1067
TDS_INT ref_count
reference counter so client can retain safely a pointer
Definition: tds.h:1049
char id[30]
id of dynamic.
Definition: tds.h:1057
TDSPARAMINFO * res_info
query results
Definition: tds.h:1069
TDS_TINYINT emulated
this dynamic query cannot be prepared so libTDS have to construct a simple query.
Definition: tds.h:1063
struct tds_dynamic * next
next in linked list, keep first
Definition: tds.h:1048
TDS_INT num_id
numeric id for mssql7+
Definition: tds.h:1051
unsigned char max_bytes_per_char
Definition: tds.h:687
const char * name
name of the encoding (ie UTF-8)
Definition: tds.h:685
char * charset
character set encoding
Definition: tds.h:1038
char * language
Definition: tds.h:1036
char * database
database name
Definition: tds.h:1040
DSTR routing_address
Definition: tds.h:619
DSTR server_name
server name (in freetds.conf)
Definition: tds.h:585
TDS_USMALLINT routing_port
Definition: tds.h:620
TDS_CHAR * message
Definition: tds.h:947
TDS_INT msgno
Definition: tds.h:950
TDS_CHAR * proc_name
Definition: tds.h:948
TDS_INT line_number
Definition: tds.h:951
TDS_CHAR * server
Definition: tds.h:946
TDS_CHAR * sql_state
Definition: tds.h:949
TDS_TINYINT priv_msg_type
Definition: tds.h:954
TDS_TINYINT severity
Definition: tds.h:955
TDS_SMALLINT state
Definition: tds.h:953
Hold information for any results.
Definition: tds.h:842
TDS_TINYINT rows_exist
Definition: tds.h:855
TDS_USMALLINT computeid
Definition: tds.h:846
TDS_USMALLINT num_cols
Definition: tds.h:845
TDS_TINYINT more_results
Definition: tds.h:857
TDSCOLUMN ** columns
Definition: tds.h:844
Information for a server connection.
Definition: tds.h:1211
TDSLOGIN * login
config for login stuff.
Definition: tds.h:1283
unsigned char * in_buf
Input buffer.
Definition: tds.h:1223
TDSCOMPUTEINFO ** comp_info
Definition: tds.h:1266
TDS_INT ret_status
return status from store procedure
Definition: tds.h:1272
void(* env_chg_func)(TDSSOCKET *tds, int type, char *oldval, char *newval)
Definition: tds.h:1285
TDSRESULTINFO * current_results
Current query information.
Definition: tds.h:1263
TDS_TINYINT has_status
true is ret_status is valid
Definition: tds.h:1270
TDSRESULTINFO * res_info
Definition: tds.h:1264
TDS_INT8 rows_affected
rows updated/deleted/inserted/selected, TDS_NO_COUNT if not valid
Definition: tds.h:1278
TDS_TINYINT bulk_query
true is query sent was a bulk query so we need to switch state to QUERYING
Definition: tds.h:1269
unsigned char out_flag
output buffer type
Definition: tds.h:1241
TDSCURSOR * cur_cursor
cursor in use
Definition: tds.h:1268
TDS_STATE state
Definition: tds.h:1273
bool in_row
true if we are getting rows
Definition: tds.h:1271
TDSPARAMINFO * param_info
Definition: tds.h:1267
int option_value
Definition: tds.h:1288
TDS_UINT num_comp_info
Definition: tds.h:1265
volatile unsigned char in_cancel
indicate we are waiting a cancel reply; discard tokens till acknowledge; 1 mean we have to send cance...
Definition: tds.h:1275
TDS_OPERATION current_op
Definition: tds.h:1286
TDSDYNAMIC * cur_dyn
dynamic structure in use
Definition: tds.h:1281
TDSCONNECTION conn[1]
Definition: tds.h:1215
TDS_ENCODING charset
Definition: iconv.h:86
struct tdsiconvdir to from
Definition: iconv.h:93
Definition: type.c:6
#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 PRId64
#define USE_ICONV
Definition: data.c:206
Main include file for libtds.
#define TDS_FAIL
Definition: tds.h:204
#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_NO_COUNT
Definition: tds.h:214
#define TDS_DONEPROC_RESULT
Definition: tds.h:228
#define TDS_FAILED(rc)
Definition: tds.h:206
@ TDS_OP_CURSORPREPARE
Definition: tds.h:878
@ TDS_OP_CURSORFETCH
Definition: tds.h:882
@ TDS_OP_DYN_DEALLOC
Definition: tds.h:893
@ TDS_OP_CURSOROPEN
Definition: tds.h:877
@ TDS_OP_PREPEXECRPC
Definition: tds.h:889
@ TDS_OP_PREPEXEC
Definition: tds.h:888
@ TDS_OP_UNPREPARE
Definition: tds.h:890
@ TDS_OP_CURSORCLOSE
Definition: tds.h:884
@ TDS_OP_CURSOREXECUTE
Definition: tds.h:879
@ TDS_OP_CURSOROPTION
Definition: tds.h:883
@ TDS_OP_CURSOR
Definition: tds.h:876
@ TDS_OP_CURSORPREPEXEC
Definition: tds.h:880
@ TDS_OP_CURSORUNPREPARE
Definition: tds.h:881
@ TDS_OP_PREPARE
Definition: tds.h:886
#define IS_TDS71_PLUS(x)
Definition: tds.h:1709
#define TDS_ROWFMT_RESULT
Definition: tds.h:224
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define IS_TDS42(x)
Definition: tds.h:1699
@ TDS_HANDLE_ALL
Definition: tds.h:250
@ TDS_STOPAT_PROC
Definition: tds.h:258
@ TDS_RETURN_DONE
Definition: tds.h:255
#define TDS_MSG_RESULT
Definition: tds.h:219
#define TDS_DONE_RESULT
Definition: tds.h:227
#define is_ascii_type(x)
Definition: tds.h:459
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
#define TDS_DBG_WARN
Definition: tds.h:902
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 TDS_COMPUTEFMT_RESULT
Definition: tds.h:225
#define tds_get_int(tds)
Definition: tds.h:1517
#define TDS_OTHERS_RESULT
Definition: tds.h:230
#define tds_get_smallint(tds)
Definition: tds.h:1515
tds_sysdep_int64_type TDS_INT8
Definition: tds.h:153
#define TDS_MAX_DYNID_LEN
Definition: tds.h:472
#define is_unicode_type(x)
Definition: tds.h:457
#define TDS_DESCRIBE_RESULT
Definition: tds.h:226
#define is_blob_col(x)
Definition: tds.h:445
#define IS_TDS72_PLUS(x)
Definition: tds.h:1710
#define TDS_COMPUTE_RESULT
Definition: tds.h:220
@ 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_SENDING
client would send data
Definition: tds.h:865
@ TDS_READING
client is reading data
Definition: tds.h:867
@ TDS_IDLE
no data expected
Definition: tds.h:863
@ TDS_DEAD
no connection
Definition: tds.h:868
#define tdsdump_dump_buf
Definition: tds.h:1564
tds_sysdep_int16_type TDS_SMALLINT
Definition: tds.h:147
@ TDSEBTOK
Definition: tds.h:316
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
#define TDS_CANCELLED
Definition: tds.h:205
#define IS_TDSDEAD(x)
Definition: tds.h:1717
#define tds_new0(type, n)
Definition: tds.h:1393
#define TDS_ROW_RESULT
Definition: tds.h:216
@ TDS_DONE_CANCELLED
acknowledging an attention command (usually a cancel)
Definition: tds.h:276
@ TDS_DONE_MORE_RESULTS
more results follow
Definition: tds.h:271
@ TDS_DONE_ERROR
error occurred
Definition: tds.h:272
@ TDS_DONE_COUNT
count field in packet is valid
Definition: tds.h:275
#define IS_TDS71(x)
Definition: tds.h:1703
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_DBG_ERROR
Definition: tds.h:903
#define TDS_UNLIKELY(x)
Definition: tds.h:372
#define TDS_SUCCESS
Definition: tds.h:203
#define TDS_STATUS_RESULT
Definition: tds.h:218
#define TDS_SYB_VER(maj, min, x)
Calc a version number for Sybase.
Definition: tds.h:1731
#define TDS_SUCCEED(rc)
Definition: tds.h:207
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define tds_get_ctx(tds)
Definition: tds.h:1294
#define tds_get_int8(tds)
Definition: tds.h:1519
#define TDS_DONEINPROC_RESULT
Definition: tds.h:229
#define IS_TDS74_PLUS(x)
Definition: tds.h:1712
#define TDS_DBG_FUNC
Definition: tds.h:898
#define TDS_DBG_NETWORK
Definition: tds.h:901
@ TDS_CUR_ISTAT_CLOSED
Definition: tds.h:336
@ TDS_CUR_ISTAT_DEALLOC
Definition: tds.h:340
@ TDS_CUR_ISTAT_OPEN
Definition: tds.h:335
@ TDS_CUR_ISTAT_DECLARED
Definition: tds.h:334
else result
Definition: token2.c:20
@ DONE
Definition: inflate.h:49
void free(voidpf ptr)
Modified on Wed Dec 06 07:15:36 2023 by modify_doxy.py rev. 669887