LCOV - code coverage report
Current view: top level - src/tds - token.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1108 1447 76.6 %
Date: 2026-06-16 18:55:27 Functions: 42 45 93.3 %

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

Generated by: LCOV version 1.13