LCOV - code coverage report
Current view: top level - src/tds - token.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1116 1465 76.2 %
Date: 2025-04-13 14:39:30 Functions: 42 45 93.3 %

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

Generated by: LCOV version 1.13