LCOV - code coverage report
Current view: top level - src/tds - token.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1103 1465 75.3 %
Date: 2025-01-18 11:50:39 Functions: 41 45 91.1 %

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

Generated by: LCOV version 1.13