LCOV - code coverage report
Current view: top level - src/tds - token.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1116 1466 76.1 %
Date: 2026-02-12 05:14:38 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             : #include <assert.h>
      36             : 
      37             : #if HAVE_MALLOC_H
      38             : #include <malloc.h>
      39             : #endif /* HAVE_MALLOC_H */
      40             : 
      41             : #include <freetds/tds.h>
      42             : #include <freetds/utils/string.h>
      43             : #include <freetds/convert.h>
      44             : #include <freetds/iconv.h>
      45             : #include <freetds/checks.h>
      46             : #include <freetds/bytes.h>
      47             : #include <freetds/alloca.h>
      48             : #include <freetds/encodings.h>
      49             : #include <freetds/enum_cap.h>
      50             : #include <freetds/replacements.h>
      51             : 
      52             : /** \cond HIDDEN_SYMBOLS */
      53             : #define USE_ICONV (tds->conn->use_iconv)
      54             : 
      55             : #define TDS_GET_COLUMN_TYPE(col) do { \
      56             :         TDS_TINYINT _tds_type = tds_get_byte(tds); \
      57             :         if (!is_tds_type_valid(_tds_type)) \
      58             :                 return TDS_FAIL; \
      59             :         tds_set_column_type(tds->conn, col, (TDS_SERVER_TYPE) _tds_type); \
      60             : } while(0)
      61             : 
      62             : #define TDS_GET_COLUMN_INFO(tds, col) \
      63             :         TDS_PROPAGATE(col->funcs->get_info(tds, col))
      64             : 
      65             : /** \endcond */
      66             : 
      67             : static TDSRET tds_process_info(TDSSOCKET * tds, int marker);
      68             : static TDSRET tds_process_compute_result(TDSSOCKET * tds);
      69             : static TDSRET tds_process_compute_names(TDSSOCKET * tds);
      70             : static TDSRET tds7_process_compute_result(TDSSOCKET * tds);
      71             : static TDSRET tds5_process_result(TDSSOCKET * tds);
      72             : static TDSRET tds_process_col_name(TDSSOCKET * tds);
      73             : static TDSRET tds_process_col_fmt(TDSSOCKET * tds);
      74             : static TDSRET tds_process_tabname(TDSSOCKET *tds);
      75             : static TDSRET tds_process_colinfo(TDSSOCKET * tds, char **names, int num_names);
      76             : static TDSRET tds_process_compute(TDSSOCKET * tds);
      77             : static TDSRET tds_process_cursor_tokens(TDSSOCKET * tds);
      78             : static TDSRET tds_process_row(TDSSOCKET * tds);
      79             : static TDSRET tds_process_nbcrow(TDSSOCKET * tds);
      80             : static TDSRET tds_process_featureextack(TDSSOCKET * tds);
      81             : static TDSRET tds_process_param_result(TDSSOCKET * tds, TDSPARAMINFO ** info);
      82             : static TDSRET tds7_process_result(TDSSOCKET * tds);
      83             : static TDSDYNAMIC *tds_process_dynamic(TDSSOCKET * tds);
      84             : static TDSRET tds_process_auth(TDSSOCKET * tds);
      85             : static TDSRET tds_process_env_chg(TDSSOCKET * tds);
      86             : static TDSRET tds_process_param_result_tokens(TDSSOCKET * tds);
      87             : static TDSRET tds_process_params_result_token(TDSSOCKET * tds);
      88             : static TDSRET tds_process_dyn_result(TDSSOCKET * tds);
      89             : static TDSRET tds5_process_result2(TDSSOCKET * tds);
      90             : static TDSRET tds5_process_dyn_result2(TDSSOCKET * tds);
      91             : static TDSRET tds_process_default_tokens(TDSSOCKET * tds, int marker);
      92             : static TDSRET tds5_process_optioncmd(TDSSOCKET * tds);
      93             : static TDSRET tds_process_end(TDSSOCKET * tds, int marker, /*@out@*/ int *flags_parm);
      94             : 
      95             : static TDSRET tds_get_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int is_param);
      96             : static /*@observer@*/ const char *tds_token_name(unsigned char marker);
      97             : static void adjust_character_column_size(TDSSOCKET * tds, TDSCOLUMN * curcol);
      98             : static int determine_adjusted_size(const TDSICONV * char_conv, int size);
      99             : static /*@observer@*/ const char *tds_pr_op(int op);
     100             : static int tds_alloc_get_string(TDSSOCKET * tds, /*@special@*/ char **string, size_t len) /*allocates *string*/;
     101             : 
     102             : /**
     103             :  * \ingroup libtds
     104             :  * \defgroup token Results processing
     105             :  * Handle tokens in packets. Many PDU (packets data unit) contain tokens.
     106             :  * (like result description, rows, data, errors and many other).
     107             :  */
     108             : 
     109             : 
     110             : /**
     111             :  * \addtogroup token
     112             :  * @{ 
     113             :  */
     114             : 
     115             : /**
     116             :  * tds_process_default_tokens() is a catch all function that is called to
     117             :  * process tokens not known to other tds_process_* routines
     118             :  * @tds
     119             :  * @param marker Token type
     120             :  */
     121             : static TDSRET
     122       59516 : tds_process_default_tokens(TDSSOCKET * tds, int marker)
     123             : {
     124             :         int tok_size;
     125             :         int done_flags;
     126             :         TDS_INT ret_status;
     127             :         TDS_CAPABILITY_TYPE *cap;
     128             : 
     129       59516 :         CHECK_TDS_EXTRA(tds);
     130             : 
     131       59516 :         tdsdump_log(TDS_DBG_FUNC, "tds_process_default_tokens() marker is %x(%s)\n", marker, tds_token_name(marker));
     132             : 
     133       59516 :         if (IS_TDSDEAD(tds)) {
     134          56 :                 tdsdump_log(TDS_DBG_FUNC, "leaving tds_process_default_tokens() connection dead\n");
     135          56 :                 tds_close_socket(tds);
     136          56 :                 return TDS_FAIL;
     137             :         }
     138             : 
     139       59460 :         switch (marker) {
     140         716 :         case TDS_AUTH_TOKEN:
     141         716 :                 return tds_process_auth(tds);
     142             :                 break;
     143       20409 :         case TDS_ENVCHANGE_TOKEN:
     144       20409 :                 return tds_process_env_chg(tds);
     145             :                 break;
     146        3648 :         case TDS_DONE_TOKEN:
     147             :         case TDS_DONEPROC_TOKEN:
     148             :         case TDS_DONEINPROC_TOKEN:
     149        3648 :                 return tds_process_end(tds, marker, &done_flags);
     150             :                 break;
     151           0 :         case TDS_PROCID_TOKEN:
     152           0 :                 tds_get_n(tds, NULL, 8);
     153           0 :                 break;
     154           0 :         case TDS_RETURNSTATUS_TOKEN:
     155           0 :                 ret_status = tds_get_int(tds);
     156           0 :                 marker = tds_peek(tds);
     157           0 :                 if (marker != TDS_PARAM_TOKEN && marker != TDS_DONEPROC_TOKEN && marker != TDS_DONE_TOKEN
     158           0 :                     && marker != TDS5_PARAMFMT_TOKEN)
     159             :                         break;
     160           0 :                 tds->has_status = true;
     161           0 :                 tds->ret_status = ret_status;
     162           0 :                 tdsdump_log(TDS_DBG_INFO1, "tds_process_default_tokens: return status is %d\n", tds->ret_status);
     163             :                 break;
     164       15637 :         case TDS_ERROR_TOKEN:
     165             :         case TDS_INFO_TOKEN:
     166             :         case TDS_EED_TOKEN:
     167       15637 :                 return tds_process_info(tds, marker);
     168             :                 break;
     169         716 :         case TDS_CAPABILITY_TOKEN:
     170         716 :                 tok_size = tds_get_usmallint(tds);
     171         716 :                 cap = tds->conn->capabilities.types;
     172         716 :                 memset(cap, 0, 2*sizeof(*cap));
     173         716 :                 cap[0].type = 1;
     174         716 :                 cap[0].len = sizeof(cap[0].values);
     175         716 :                 cap[1].type = 2;
     176         716 :                 cap[1].len = sizeof(cap[1].values);
     177        2864 :                 while (tok_size > 1) {
     178             :                         unsigned char type, size, *p;
     179             : 
     180        1432 :                         type = tds_get_byte(tds);
     181        1432 :                         size = tds_get_byte(tds);
     182        1432 :                         tok_size -= 2 + size;
     183        1432 :                         if (type != 1 && type != 2) {
     184           0 :                                 tds_get_n(tds, NULL, size);
     185           0 :                                 continue;
     186             :                         }
     187        1432 :                         if (size > sizeof(cap->values)) {
     188           0 :                                 tds_get_n(tds, NULL, size - sizeof(cap->values));
     189           0 :                                 size = sizeof(cap->values);
     190             :                         }
     191        1432 :                         p = (unsigned char *) &cap[type];
     192        1432 :                         if (!tds_get_n(tds, p-size, size))
     193             :                                 return TDS_FAIL;
     194             :                         /*
     195             :                          * Sybase 11.0 servers return the wrong length in the capability packet,
     196             :                          * causing us to read past the done packet.
     197             :                          */
     198        1432 :                         if (tds->conn->product_version < TDS_SYB_VER(12, 0, 0) && type == 2)
     199             :                                 break;
     200             :                 }
     201             :                 break;
     202             :                 /* PARAM_TOKEN can be returned inserting text in db, to return new timestamp */
     203           0 :         case TDS_PARAM_TOKEN:
     204           0 :                 tds_unget_byte(tds);
     205           0 :                 return tds_process_param_result_tokens(tds);
     206             :                 break;
     207           0 :         case TDS7_RESULT_TOKEN:
     208           0 :                 return tds7_process_result(tds);
     209             :                 break;
     210           8 :         case TDS_OPTIONCMD_TOKEN:
     211           8 :                 return tds5_process_optioncmd(tds);
     212             :                 break;
     213           0 :         case TDS_RESULT_TOKEN:
     214           0 :                 return tds5_process_result(tds);
     215             :                 break;
     216           0 :         case TDS_ROWFMT2_TOKEN:
     217           0 :                 return tds5_process_result2(tds);
     218             :                 break;
     219           0 :         case TDS_COLNAME_TOKEN:
     220           0 :                 return tds_process_col_name(tds);
     221             :                 break;
     222           0 :         case TDS_COLFMT_TOKEN:
     223           0 :                 return tds_process_col_fmt(tds);
     224             :                 break;
     225           0 :         case TDS_ROW_TOKEN:
     226           0 :                 return tds_process_row(tds);
     227             :                 break;
     228           2 :         case TDS5_PARAMFMT_TOKEN:
     229             :                 /* store discarded parameters in param_info, not in old dynamic */
     230           2 :                 tds_release_cur_dyn(tds);
     231           2 :                 return tds_process_dyn_result(tds);
     232             :                 break;
     233           0 :         case TDS5_PARAMFMT2_TOKEN:
     234           0 :                 tds_release_cur_dyn(tds);
     235           0 :                 return tds5_process_dyn_result2(tds);
     236             :                 break;
     237           2 :         case TDS5_PARAMS_TOKEN:
     238             :                 /* save params */
     239           2 :                 return tds_process_params_result_token(tds);
     240             :                 break;
     241           0 :         case TDS_CURINFO_TOKEN:
     242           0 :                 return tds_process_cursor_tokens(tds);
     243             :                 break;
     244        7468 :         case TDS_CONTROL_FEATUREEXTACK_TOKEN:
     245        7468 :                 if (IS_TDS74_PLUS(tds->conn))
     246         714 :                         return tds_process_featureextack(tds);
     247             :                 /* fall through */
     248             :         case TDS5_DYNAMIC_TOKEN:
     249             :         case TDS_LOGINACK_TOKEN:
     250             :         case TDS_ORDERBY_TOKEN:
     251       17600 :                 tdsdump_log(TDS_DBG_WARN, "Eating %s token\n", tds_token_name(marker));
     252       17600 :                 tds_get_n(tds, NULL, tds_get_usmallint(tds));
     253       17600 :                 break;
     254           0 :         case TDS_MSG_TOKEN:
     255           0 :                 tok_size = tds_get_byte(tds);
     256           0 :                 if (tok_size >= 3) {
     257           0 :                         tds_get_byte(tds);
     258           0 :                         tds5_negotiate_set_msg_type(tds->conn->authentication, tds_get_usmallint(tds));
     259           0 :                         tok_size -= 3;
     260             :                 }
     261           0 :                 tds_get_n(tds, NULL, tok_size);
     262           0 :                 break;
     263           2 :         case TDS_TABNAME_TOKEN: /* used for FOR BROWSE query */
     264           2 :                 return tds_process_tabname(tds);
     265             :                 break;
     266           6 :         case TDS_COLINFO_TOKEN:
     267           6 :                 return tds_process_colinfo(tds, NULL, 0);
     268             :                 break;
     269           0 :         case TDS_SESSIONSTATE_TOKEN:
     270             :         case TDS_ORDERBY2_TOKEN:
     271           0 :                 tdsdump_log(TDS_DBG_WARN, "Eating %s token\n", tds_token_name(marker));
     272           0 :                 tds_get_n(tds, NULL, tds_get_uint(tds));
     273           0 :                 break;
     274           0 :         case TDS_NBC_ROW_TOKEN:
     275           0 :                 return tds_process_nbcrow(tds);
     276             :                 break;
     277           0 :         default: 
     278           0 :                 tds_close_socket(tds);
     279           0 :                 tdserror(tds_get_ctx(tds), tds, TDSEBTOK, 0);
     280           0 :                 tdsdump_log(TDS_DBG_ERROR, "Unknown marker: %d(%x)!!\n", marker, (unsigned char) marker);
     281             :                 return TDS_FAIL;
     282             :         }
     283           0 :         return TDS_SUCCESS;
     284             : }
     285             : 
     286             : static TDSRET
     287        3640 : tds_process_loginack(TDSSOCKET *tds, TDSRET *login_succeeded)
     288             : {
     289             :         unsigned int len;
     290             :         unsigned char ack;
     291             :         TDS_UINT product_version;
     292        3640 :         int memrc = 0;
     293        3640 :         TDS_USMALLINT orig_tds_version = tds->conn->tds_version;
     294             : 
     295             :         struct  { unsigned char major, minor, tiny[2];
     296             :                   unsigned int reported;
     297             :                   const char *name;
     298             :                 } ver;
     299             : 
     300        3640 :         tds->conn->tds71rev1 = 0;
     301        3640 :         len = tds_get_usmallint(tds);
     302        3640 :         if (len < 10)
     303             :                 return TDS_FAIL;
     304        3640 :         ack = tds_get_byte(tds);
     305             : 
     306        3640 :         ver.major = tds_get_byte(tds);
     307        3640 :         ver.minor = tds_get_byte(tds);
     308        3640 :         ver.tiny[0] = tds_get_byte(tds);
     309        3640 :         ver.tiny[1] = tds_get_byte(tds);
     310        3640 :         ver.reported = (ver.major << 24) | (ver.minor << 16) | (ver.tiny[0] << 8) | ver.tiny[1];
     311             : 
     312        3640 :         if (ver.reported == 0x07010000)
     313           0 :                 tds->conn->tds71rev1 = 1;
     314             : 
     315             :         /* Log reported server product name, cf. MS-TDS LOGINACK documentation. */
     316        3640 :         switch (ver.reported) {
     317           0 :         case 0x07000000:
     318           0 :                 ver.name = "7.0";
     319           0 :                 tds->conn->tds_version = 0x700;
     320           0 :                 break;
     321           0 :         case 0x07010000:
     322           0 :                 ver.name = "2000";
     323           0 :                 tds->conn->tds_version = 0x701;
     324           0 :                 break;
     325        1472 :         case 0x71000001:
     326        1472 :                 ver.name = "2000 SP1";
     327        1472 :                 tds->conn->tds_version = 0x701;
     328        1472 :                 break;
     329           0 :         case 0x72090002:
     330           0 :                 ver.name = "2005";
     331           0 :                 tds->conn->tds_version = 0x702;
     332           0 :                 break;
     333           0 :         case 0x730A0003:
     334           0 :                 ver.name = "2008 (no NBCROW or fSparseColumnSet)";
     335           0 :                 tds->conn->tds_version = 0x703;
     336           0 :                 break;
     337         736 :         case 0x730B0003:
     338         736 :                 ver.name = "2008";
     339         736 :                 tds->conn->tds_version = 0x703;
     340         736 :                 break;
     341         714 :         case 0x74000004:
     342         714 :                 ver.name = "2012-2019";
     343         714 :                 tds->conn->tds_version = 0x704;
     344         714 :                 break;
     345             :         default:
     346             :                 ver.name = "unknown";
     347             :                 break;
     348             :         }
     349             : 
     350        3640 :         tdsdump_log(TDS_DBG_FUNC, "server reports TDS version %x.%x.%x.%x\n",
     351             :                                         ver.major, ver.minor, ver.tiny[0], ver.tiny[1]);
     352        3640 :         tdsdump_log(TDS_DBG_FUNC, "Product name for 0x%x is %s\n", ver.reported, ver.name);
     353             : 
     354             :         /* Get server product name. */
     355             :         /* Ignore product name length; some servers seem to set it incorrectly.  */
     356        3640 :         tds_get_byte(tds);
     357        3640 :         product_version = 0;
     358             :         /* Compute product name length from packet length. */
     359        3640 :         len -= 10;
     360        3640 :         free(tds->conn->product_name);
     361        3640 :         if (ver.major >= 7u) {
     362        2922 :                 product_version = 0x80u;
     363        2922 :                 memrc += tds_alloc_get_string(tds, &tds->conn->product_name, len / 2);
     364         718 :         } else if (ver.major >= 5) {
     365         718 :                 memrc += tds_alloc_get_string(tds, &tds->conn->product_name, len);
     366             :         } else {
     367           0 :                 memrc += tds_alloc_get_string(tds, &tds->conn->product_name, len);
     368           0 :                 if (tds->conn->product_name != NULL && strstr(tds->conn->product_name, "Microsoft") != NULL)
     369           0 :                         product_version = 0x80u;
     370             :         }
     371        3640 :         if (memrc != 0)
     372             :                 return TDS_FAIL;
     373             : 
     374        3640 :         product_version |= tds_get_byte(tds); product_version <<= 8;
     375        3640 :         product_version |= tds_get_byte(tds); product_version <<= 8;
     376        3640 :         product_version |= tds_get_byte(tds); product_version <<= 8;
     377        3640 :         product_version |= tds_get_byte(tds);
     378             : 
     379             :         /*
     380             :          * MSSQL 6.5 and 7.0 seem to return strange values for this
     381             :          * using TDS 4.2, something like 5F 06 32 FF for 6.50
     382             :          */
     383        3640 :         if (ver.major == 4 && ver.minor == 2 && (product_version & 0xff0000ffu) == 0x5f0000ffu)
     384           0 :                 product_version = ((product_version & 0xffff00u) | 0x800000u) << 8;
     385        3640 :         tds->conn->product_version = product_version;
     386        3640 :         tdsdump_log(TDS_DBG_FUNC, "Product version %lX\n", (unsigned long) product_version);
     387             : 
     388             :         /* internal version is ignored for TDS 8.0+ */
     389        3640 :         if (orig_tds_version >= 0x800)
     390           0 :                 tds->conn->tds_version = orig_tds_version;
     391             : 
     392             :         /*
     393             :          * TDS 5.0 reports 5 on success 6 on failure
     394             :          * TDS 4.2 reports 1 on success and is not
     395             :          * present on failure
     396             :          */
     397        3640 :         if (ack == 5 || ack == 1 || (IS_TDS50(tds->conn) && ack == 0x85)) {
     398        3638 :                 *login_succeeded = TDS_SUCCESS;
     399             :                 /* authentication is now useless */
     400        3638 :                 if (tds->conn->authentication) {
     401         716 :                         tds->conn->authentication->free(tds->conn, tds->conn->authentication);
     402         716 :                         tds->conn->authentication = NULL;
     403             :                 }
     404             :         }
     405             : 
     406             :         return TDS_SUCCESS;
     407             : }
     408             : 
     409             : /**
     410             :  * tds_process_login_tokens() is called after sending the login packet 
     411             :  * to the server.  It returns the success or failure of the login 
     412             :  * dependent on the protocol version. 4.2 sends an ACK token only when
     413             :  * successful, TDS 5.0 sends it always with a success byte within
     414             :  * @tds
     415             :  */
     416             : TDSRET
     417        3660 : tds_process_login_tokens(TDSSOCKET * tds)
     418             : {
     419        3660 :         TDSRET succeed = TDS_FAIL;
     420             :         int marker;
     421             : 
     422        3660 :         CHECK_TDS_EXTRA(tds);
     423             : 
     424        3660 :         tdsdump_log(TDS_DBG_FUNC, "tds_process_login_tokens()\n");
     425             :         do {
     426       30220 :                 marker = tds_get_byte(tds);
     427             : 
     428       30220 :                 tdsdump_log(TDS_DBG_FUNC, "looking for login token, got  %x(%s)\n", marker, tds_token_name(marker));
     429             : 
     430       30220 :                 switch (marker) {
     431        3640 :                 case TDS_LOGINACK_TOKEN:
     432        3640 :                         TDS_PROPAGATE(tds_process_loginack(tds, &succeed));
     433             :                         break;
     434       26580 :                 default:
     435       26580 :                         TDS_PROPAGATE(tds_process_default_tokens(tds, marker));
     436             :                         break;
     437             :                 }
     438       30208 :                 if (marker == TDS_DONE_TOKEN && IS_TDS50(tds->conn) && tds->conn->authentication) {
     439           0 :                         TDSAUTHENTICATION *auth = tds->conn->authentication;
     440           0 :                         if (TDS_SUCCEED(auth->handle_next(tds, auth, 0))) {
     441           0 :                                 marker = 0;
     442           0 :                                 continue;
     443             :                         }
     444             :                 }
     445       30208 :         } while (marker != TDS_DONE_TOKEN);
     446             : 
     447             :         /* set the spid */
     448        3648 :         if (TDS_IS_MSSQL(tds))
     449        2922 :                 tds->conn->spid = TDS_GET_A2BE(tds->in_buf+4);
     450             : 
     451        3652 :         tdsdump_log(TDS_DBG_FUNC, "tds_process_login_tokens() returning %s\n", 
     452           4 :                                         (succeed == TDS_SUCCESS)? "TDS_SUCCESS" : "TDS_FAIL");
     453             : 
     454        3648 :         return succeed;
     455             : }
     456             : 
     457             : /**
     458             :  * Process authentication token.
     459             :  * This token is only TDS 7.0+.
     460             :  * \tds
     461             :  */
     462             : static TDSRET
     463         716 : tds_process_auth(TDSSOCKET * tds)
     464             : {
     465             :         unsigned int pdu_size;
     466             : 
     467         716 :         CHECK_TDS_EXTRA(tds);
     468             : 
     469             : #if ENABLE_EXTRA_CHECKS
     470         716 :         if (!IS_TDS7_PLUS(tds->conn))
     471           0 :                 tdsdump_log(TDS_DBG_ERROR, "Called auth on TDS version < 7\n");
     472             : #endif
     473             : 
     474         716 :         pdu_size = tds_get_usmallint(tds);
     475         716 :         tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN PDU size %u\n", pdu_size);
     476             : 
     477         716 :         if (!tds->conn->authentication)
     478             :                 return TDS_FAIL;
     479             : 
     480         716 :         return tds->conn->authentication->handle_next(tds, tds->conn->authentication, pdu_size);
     481             : }
     482             : 
     483             : /**
     484             :  * process all streams.
     485             :  * tds_process_tokens() is called after submitting a query with
     486             :  * tds_submit_query() and is responsible for calling the routines to
     487             :  * populate tds->res_info if appropriate (some query have no result sets)
     488             :  * @tds
     489             :  * @param result_type A pointer to an integer variable which 
     490             :  *        tds_process_tokens sets to indicate the current type of result.
     491             :  *  @par
     492             :  *  <b>Values that indicate command status</b>
     493             :  *  <table>
     494             :  *   <tr><td>TDS_DONE_RESULT</td><td>The results of a command have been completely processed. 
     495             :  *                                      This command returned no rows.</td></tr>
     496             :  *   <tr><td>TDS_DONEPROC_RESULT</td><td>The results of a  command have been completely processed.  
     497             :  *                                      This command returned rows.</td></tr>
     498             :  *   <tr><td>TDS_DONEINPROC_RESULT</td><td>The results of a  command have been completely processed.  
     499             :  *                                      This command returned rows.</td></tr>
     500             :  *  </table>
     501             :  *  <b>Values that indicate results information is available</b>
     502             :  *  <table><tr>
     503             :  *    <td>TDS_ROWFMT_RESULT</td><td>Regular Data format information</td>
     504             :  *    <td>tds->res_info now contains the result details ; tds->current_results now points to that data</td>
     505             :  *   </tr><tr>
     506             :  *    <td>TDS_COMPUTEFMT_ RESULT</td><td>Compute data format information</td>
     507             :  *    <td>tds->comp_info now contains the result data; tds->current_results now points to that data</td>
     508             :  *   </tr><tr>
     509             :  *    <td>TDS_DESCRIBE_RESULT</td><td></td>
     510             :  *    <td></td>
     511             :  *  </tr></table>
     512             :  *  <b>Values that indicate data is available</b>
     513             :  *  <table><tr>
     514             :  *   <td><b>Value</b></td><td><b>Meaning</b></td><td><b>Information returned</b></td>
     515             :  *   </tr><tr>
     516             :  *    <td>TDS_ROW_RESULT</td><td>Regular row results</td>
     517             :  *    <td>1 or more rows of regular data can now be retrieved</td>
     518             :  *   </tr><tr>
     519             :  *    <td>TDS_COMPUTE_RESULT</td><td>Compute row results</td>
     520             :  *    <td>A single row of compute data can now be retrieved</td>
     521             :  *   </tr><tr>
     522             :  *    <td>TDS_PARAM_RESULT</td><td>Return parameter results</td>
     523             :  *    <td>param_info or cur_dyn->params contain returned parameters</td>
     524             :  *   </tr><tr>
     525             :  *    <td>TDS_STATUS_RESULT</td><td>Stored procedure status results</td>
     526             :  *    <td>tds->ret_status contain the returned code</td>
     527             :  *  </tr></table>
     528             :  * @param done_flags Flags contained in the TDS_DONE*_TOKEN readed
     529             :  * @param flag Flags to select token type to stop/return
     530             :  * @todo Complete TDS_DESCRIBE_RESULT description
     531             :  * @retval TDS_SUCCESS if a result set is available for processing.
     532             :  * @retval TDS_FAIL on error.
     533             :  * @retval TDS_NO_MORE_RESULTS if all results have been completely processed.
     534             :  * @retval anything returned by one of the many functions it calls.  :-(
     535             :  */
     536             : TDSRET
     537      543406 : tds_process_tokens(TDSSOCKET *tds, TDS_INT *result_type, int *done_flags, unsigned flag)
     538             : {
     539             :         int marker;
     540      543406 :         TDSPARAMINFO *pinfo = NULL;
     541             :         TDSCOLUMN   *curcol;
     542             :         TDSRET rc;
     543      543406 :         TDS_INT8 saved_rows_affected = tds->rows_affected;
     544             :         TDS_INT ret_status;
     545      543406 :         int cancel_seen = 0;
     546      543406 :         unsigned return_flag = 0;
     547             : 
     548             : /** \cond HIDDEN_SYMBOLS */
     549             : #define SET_RETURN(ret, f) do { \
     550             :         *result_type = ret; \
     551             :         return_flag = TDS_RETURN_##f | TDS_STOPAT_##f; \
     552             :         if (flag & TDS_STOPAT_##f) {\
     553             :                 tds_unget_byte(tds); \
     554             :                 tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens::SET_RETURN stopping on current token\n"); \
     555             :                 goto set_return_exit; \
     556             :         } } while(0)
     557             : /** \endcond */
     558             : 
     559      543406 :         CHECK_TDS_EXTRA(tds);
     560             : 
     561      543406 :         tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens(%p, %p, %p, 0x%x)\n", tds, result_type, done_flags, flag);
     562             :         
     563      543406 :         if (tds->state == TDS_IDLE || tds->state == TDS_SENDING) {
     564       57881 :                 tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens() state is COMPLETED\n");
     565       57881 :                 *result_type = TDS_DONE_RESULT;
     566       57881 :                 return TDS_NO_MORE_RESULTS;
     567             :         }
     568             : 
     569      485525 :         if (tds_set_state(tds, TDS_READING) != TDS_READING)
     570             :                 return TDS_FAIL;
     571             : 
     572             :         rc = TDS_SUCCESS;
     573             :         for (;;) {
     574             : 
     575      654895 :                 marker = tds_get_byte(tds);
     576      654895 :                 tdsdump_log(TDS_DBG_INFO1, "processing result tokens.  marker is  %x(%s)\n", marker, tds_token_name(marker));
     577             : 
     578      654895 :                 switch (marker) {
     579       25561 :                 case TDS7_RESULT_TOKEN:
     580             : 
     581             :                         /*
     582             :                          * If we're processing the results of a cursor fetch
     583             :                          * from sql server we don't want to pass back the
     584             :                          * TDS_ROWFMT_RESULT to the calling API
     585             :                          */
     586       25561 :                         if (tds->current_op != TDS_OP_CURSORFETCH)
     587       24737 :                                 SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
     588             : 
     589       25321 :                         rc = tds7_process_result(tds);
     590       25321 :                         if (TDS_FAILED(rc))
     591             :                                 break;
     592             :                         /* handle browse information (if present) */
     593       25321 :                         marker = tds_get_byte(tds);
     594       25321 :                         if (marker != TDS_TABNAME_TOKEN)
     595       25031 :                                 tds_unget_byte(tds);
     596             :                         else
     597         290 :                                 rc = tds_process_tabname(tds);
     598             :                         break;
     599          58 :                 case TDS_RESULT_TOKEN:
     600          58 :                         SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
     601          58 :                         rc = tds5_process_result(tds);
     602          58 :                         break;
     603        6822 :                 case TDS_ROWFMT2_TOKEN:
     604        6822 :                         SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
     605        6798 :                         rc = tds5_process_result2(tds);
     606        6798 :                         break;
     607           0 :                 case TDS_COLNAME_TOKEN:
     608           0 :                         rc = tds_process_col_name(tds);
     609           0 :                         break;
     610           0 :                 case TDS_COLFMT_TOKEN:
     611           0 :                         SET_RETURN(TDS_ROWFMT_RESULT, ROWFMT);
     612           0 :                         rc = tds_process_col_fmt(tds);
     613           0 :                         if (TDS_FAILED(rc))
     614             :                                 break;
     615             :                         /* handle browse information (if present) */
     616           0 :                         marker = tds_get_byte(tds);
     617           0 :                         if (marker != TDS_TABNAME_TOKEN)
     618           0 :                                 tds_unget_byte(tds);
     619             :                         else
     620           0 :                                 rc = tds_process_tabname(tds);
     621             :                         break;
     622        5250 :                 case TDS_PARAM_TOKEN:
     623        5250 :                         tds_unget_byte(tds);
     624        5250 :                         if (tds->current_op) {
     625        4416 :                                 tdsdump_log(TDS_DBG_FUNC, "processing parameters for op %d\n", tds->current_op);
     626       15870 :                                 while ((marker = tds_get_byte(tds)) == TDS_PARAM_TOKEN) {
     627       11454 :                                         tdsdump_log(TDS_DBG_INFO1, "calling tds_process_param_result\n");
     628       11454 :                                         rc = tds_process_param_result(tds, &pinfo);
     629       11454 :                                         if (TDS_FAILED(rc))
     630             :                                                 goto set_return_exit;
     631             :                                 }
     632        4416 :                                 tds_unget_byte(tds);
     633        4416 :                                 tdsdump_log(TDS_DBG_FUNC, "%d hidden return parameters\n", pinfo ? pinfo->num_cols : -1);
     634        4416 :                                 if (pinfo && pinfo->num_cols > 0) {
     635        4416 :                                         curcol = pinfo->columns[0];
     636        4416 :                                         if (tds->current_op == TDS_OP_CURSOROPEN && tds->cur_cursor) {
     637        2346 :                                                 TDSCURSOR  *cursor = tds->cur_cursor; 
     638             : 
     639        2346 :                                                 cursor->cursor_id = *(TDS_INT *) curcol->column_data;
     640        2346 :                                                 tdsdump_log(TDS_DBG_FUNC, "stored internal cursor id %d\n", cursor->cursor_id);
     641        2346 :                                                 cursor->srv_status &= ~(TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_OPEN|TDS_CUR_ISTAT_DEALLOC);
     642        2346 :                                                 cursor->srv_status |= cursor->cursor_id ? TDS_CUR_ISTAT_OPEN : TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_DEALLOC;
     643             :                                         }
     644        4416 :                                         if ((tds->current_op == TDS_OP_PREPARE || tds->current_op == TDS_OP_PREPEXEC)
     645        2070 :                                             && tds->cur_dyn && tds->cur_dyn->num_id == 0 && curcol->column_cur_size > 0) {
     646        2060 :                                                 tds->cur_dyn->num_id = *(TDS_INT *) curcol->column_data;
     647             :                                         }
     648        4416 :                                         if (tds->current_op == TDS_OP_UNPREPARE)
     649           0 :                                                 tds_dynamic_deallocated(tds->conn, tds->cur_dyn);
     650             :                                 }
     651        4416 :                                 tds_free_param_results(pinfo);
     652             :                         } else {
     653         834 :                                 SET_RETURN(TDS_PARAM_RESULT, PROC);
     654         834 :                                 rc = tds_process_param_result_tokens(tds);
     655             :                         }
     656             :                         break;
     657          18 :                 case TDS_COMPUTE_NAMES_TOKEN:
     658          18 :                         rc = tds_process_compute_names(tds);
     659          18 :                         break;
     660          18 :                 case TDS_COMPUTE_RESULT_TOKEN:
     661          18 :                         SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT);
     662          18 :                         rc = tds_process_compute_result(tds);
     663          18 :                         break;
     664          54 :                 case TDS7_COMPUTE_RESULT_TOKEN:
     665          54 :                         SET_RETURN(TDS_COMPUTEFMT_RESULT, COMPUTEFMT);
     666          54 :                         rc = tds7_process_compute_result(tds);
     667          54 :                         break;
     668      392227 :                 case TDS_ROW_TOKEN:
     669             :                 case TDS_NBC_ROW_TOKEN:
     670             :                         /* overstepped the mark... */
     671      392227 :                         if (tds->cur_cursor) {
     672        2288 :                                 tds_set_current_results(tds, tds->cur_cursor->res_info);
     673        2288 :                                 tdsdump_log(TDS_DBG_INFO1, "tds_process_tokens(). set current_results to cursor->res_info\n");
     674             :                         } else {
     675             :                                 /* assure that we point to row, not to compute */
     676      389939 :                                 if (tds->res_info)
     677      389939 :                                         tds_set_current_results(tds, tds->res_info);
     678             :                         }
     679             :                         /* I don't know when this it's false but it happened, also server can send garbage... */
     680      392227 :                         if (tds->current_results)
     681      392227 :                                 tds->current_results->rows_exist = true;
     682      392227 :                         SET_RETURN(TDS_ROW_RESULT, ROW);
     683             : 
     684      363825 :                         switch (marker) {
     685      358885 :                         case TDS_ROW_TOKEN:
     686      358885 :                                 rc = tds_process_row(tds);
     687      358885 :                                 break;
     688        4940 :                         case TDS_NBC_ROW_TOKEN:
     689        4940 :                                 rc = tds_process_nbcrow(tds);
     690        4940 :                                 break;
     691             :                         }
     692             :                         break;
     693         184 :                 case TDS_CMP_ROW_TOKEN:
     694             :                         /* I don't know when this it's false but it happened, also server can send garbage... */
     695         184 :                         if (tds->res_info)
     696         184 :                                 tds->res_info->rows_exist = true;
     697         184 :                         SET_RETURN(TDS_COMPUTE_RESULT, COMPUTE);
     698         104 :                         rc = tds_process_compute(tds);
     699         104 :                         break;
     700       11852 :                 case TDS_RETURNSTATUS_TOKEN:
     701       11852 :                         ret_status = tds_get_int(tds);
     702       11852 :                         marker = tds_peek(tds);
     703       11852 :                         if (marker != TDS_PARAM_TOKEN && marker != TDS_DONEPROC_TOKEN && marker != TDS_DONE_TOKEN && marker != TDS5_PARAMFMT_TOKEN && marker != TDS5_PARAMFMT2_TOKEN)
     704             :                                 break;
     705       11696 :                         if (tds->current_op) {
     706             :                                 /* TODO perhaps we should use ret_status ?? */
     707             :                         } else {
     708             :                                 /* TODO optimize */
     709        1798 :                                 flag &= ~TDS_STOPAT_PROC;
     710        1798 :                                 SET_RETURN(TDS_STATUS_RESULT, PROC);
     711        1798 :                                 tds->has_status = true;
     712        1798 :                                 tds->ret_status = ret_status;
     713        1798 :                                 tdsdump_log(TDS_DBG_FUNC, "tds_process_tokens: return status is %d\n", tds->ret_status);
     714             :                                 rc = TDS_SUCCESS;
     715             :                         }
     716             :                         break;
     717         962 :                 case TDS5_DYNAMIC_TOKEN:
     718             :                         /* process acknowledge dynamic */
     719         962 :                         tds_set_cur_dyn(tds, tds_process_dynamic(tds));
     720             :                         /* special case, prepared statement cannot be prepared */
     721        1924 :                         if (!tds->cur_dyn || tds->cur_dyn->emulated)
     722             :                                 break;
     723         962 :                         marker = tds_get_byte(tds);
     724         962 :                         if (marker != TDS_EED_TOKEN) {
     725         896 :                                 tds_unget_byte(tds);
     726         896 :                                 break;
     727             :                         }
     728          66 :                         tds_process_info(tds, marker);
     729         130 :                         if (!tds->cur_dyn || !tds->cur_dyn->emulated)
     730             :                                 break;
     731          60 :                         marker = tds_get_byte(tds);
     732          60 :                         if (marker != TDS_DONE_TOKEN) {
     733           0 :                                 tds_unget_byte(tds);
     734           0 :                                 break;
     735             :                         }
     736          60 :                         rc = tds_process_end(tds, marker, done_flags);
     737          60 :                         if (done_flags)
     738          60 :                                 *done_flags &= ~TDS_DONE_ERROR;
     739             :                         /* FIXME warning to macro expansion */
     740          60 :                         SET_RETURN(TDS_DONE_RESULT, DONE);
     741             :                         break;
     742          18 :                 case TDS5_PARAMFMT_TOKEN:
     743          18 :                         SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT);
     744          18 :                         rc = tds_process_dyn_result(tds);
     745          18 :                         break;
     746         334 :                 case TDS5_PARAMFMT2_TOKEN:
     747         334 :                         SET_RETURN(TDS_DESCRIBE_RESULT, PARAMFMT);
     748         334 :                         rc = tds5_process_dyn_result2(tds);
     749         334 :                         break;
     750          98 :                 case TDS5_PARAMS_TOKEN:
     751          98 :                         SET_RETURN(TDS_PARAM_RESULT, PROC);
     752          98 :                         rc = tds_process_params_result_token(tds);
     753          98 :                         break;
     754          40 :                 case TDS_CURINFO_TOKEN:
     755          40 :                         rc = tds_process_cursor_tokens(tds);
     756          40 :                         break;
     757      139863 :                 case TDS_DONE_TOKEN:
     758      139863 :                         SET_RETURN(TDS_DONE_RESULT, DONE);
     759      139467 :                         rc = tds_process_end(tds, marker, done_flags);
     760      139467 :                         switch (tds->current_op) {
     761         272 :                         case TDS_OP_DYN_DEALLOC:
     762         272 :                                 if (done_flags && (*done_flags & TDS_DONE_ERROR) == 0)
     763         270 :                                         tds_dynamic_deallocated(tds->conn, tds->cur_dyn);
     764             :                                 break;
     765             :                         default:
     766             :                                 break;
     767             :                         }
     768             :                         break;
     769       12008 :                 case TDS_DONEPROC_TOKEN:
     770       12008 :                         SET_RETURN(TDS_DONEPROC_RESULT, DONE);
     771       12000 :                         rc = tds_process_end(tds, marker, done_flags);
     772       12000 :                         tds->rows_affected = saved_rows_affected;
     773       12000 :                         switch (tds->current_op) {
     774             :                         default:
     775             :                                 break;
     776        2346 :                         case TDS_OP_CURSOROPEN: 
     777        2346 :                                 *result_type       = TDS_DONE_RESULT;
     778        2346 :                                 break;
     779         280 :                         case TDS_OP_CURSORCLOSE:
     780         280 :                                 tdsdump_log(TDS_DBG_FUNC, "TDS_OP_CURSORCLOSE\n");
     781         280 :                                 if (tds->cur_cursor) {
     782             :  
     783         280 :                                         TDSCURSOR  *cursor = tds->cur_cursor;
     784             :  
     785         280 :                                         cursor->srv_status &= ~TDS_CUR_ISTAT_OPEN;
     786         280 :                                         cursor->srv_status |= TDS_CUR_ISTAT_CLOSED|TDS_CUR_ISTAT_DECLARED;
     787         280 :                                         if (cursor->status.dealloc == TDS_CURSOR_STATE_SENT) {
     788           0 :                                                 tds_cursor_deallocated(tds->conn, cursor);
     789             :                                         }
     790             :                                 }
     791         280 :                                 *result_type = TDS_NO_MORE_RESULTS;
     792         280 :                                 rc = TDS_NO_MORE_RESULTS;
     793         280 :                                 break;
     794        2036 :                         case TDS_OP_UNPREPARE:
     795        2036 :                                 if (done_flags && (*done_flags & TDS_DONE_ERROR) == 0)
     796        2036 :                                         tds_dynamic_deallocated(tds->conn, tds->cur_dyn);
     797        2036 :                                 *result_type = TDS_NO_MORE_RESULTS;
     798        2036 :                                 rc = TDS_NO_MORE_RESULTS;
     799        2036 :                                 break;
     800        1392 :                         case TDS_OP_CURSOR:
     801             :                         case TDS_OP_CURSORPREPARE:
     802             :                         case TDS_OP_CURSOREXECUTE:
     803             :                         case TDS_OP_CURSORPREPEXEC:
     804             :                         case TDS_OP_CURSORUNPREPARE:
     805             :                         case TDS_OP_CURSORFETCH:
     806             :                         case TDS_OP_CURSOROPTION:
     807             :                         case TDS_OP_PREPEXECRPC:
     808        1392 :                                 *result_type = TDS_NO_MORE_RESULTS;
     809        1392 :                                 rc = TDS_NO_MORE_RESULTS;
     810        1392 :                                 break;
     811             :                         }
     812             :                         break;
     813       26492 :                 case TDS_DONEINPROC_TOKEN:
     814       26492 :                         switch(tds->current_op) {
     815        3494 :                         case TDS_OP_CURSOROPEN:
     816             :                         case TDS_OP_CURSORFETCH:
     817             :                         case TDS_OP_PREPARE:
     818             :                         case TDS_OP_CURSORCLOSE:
     819        3494 :                                 rc = tds_process_end(tds, marker, done_flags);
     820        3494 :                                 if (tds->rows_affected != TDS_NO_COUNT) {
     821        3082 :                                         saved_rows_affected = tds->rows_affected;
     822             :                                 }
     823             :                                 break;
     824       22998 :                         default:
     825       22998 :                                 SET_RETURN(TDS_DONEINPROC_RESULT, DONE);
     826       22958 :                                 rc = tds_process_end(tds, marker, done_flags);
     827       22958 :                                 break;
     828             :                         }
     829             :                         break;
     830        8593 :                 case TDS_ERROR_TOKEN:
     831             :                 case TDS_INFO_TOKEN:
     832             :                 case TDS_EED_TOKEN:
     833        8593 :                         SET_RETURN(TDS_MSG_RESULT, MSG);
     834        8525 :                         rc = tds_process_default_tokens(tds, marker);
     835        8525 :                         break;
     836        6747 :                 case TDS_ENVCHANGE_TOKEN:
     837        6747 :                         SET_RETURN(TDS_MSG_RESULT, ENV);
     838        6747 :                         rc = tds_process_default_tokens(tds, marker);
     839        6747 :                         break;
     840       17696 :                 default:
     841       17696 :                         SET_RETURN(TDS_OTHERS_RESULT, OTHERS);
     842       17660 :                         rc = tds_process_default_tokens(tds, marker);
     843       17660 :                         break;
     844             :                 }
     845             : 
     846      655057 :         set_return_exit:
     847      654895 :                 if (TDS_FAILED(rc)) {
     848        1822 :                         if (rc == TDS_CANCELLED)
     849        1778 :                                 tds_set_state(tds, TDS_PENDING);
     850             :                         else
     851          44 :                                 tds_close_socket(tds);
     852             :                         return rc;
     853             :                 }
     854             : 
     855      653073 :                 cancel_seen |= tds->in_cancel;
     856      653073 :                 if (cancel_seen) {
     857             :                         /* during cancel handle all tokens */
     858       73407 :                         flag = TDS_HANDLE_ALL;
     859             :                 }
     860             : 
     861      653073 :                 if ((return_flag & flag) != 0) {
     862      483001 :                         tds_set_state(tds, TDS_PENDING);
     863      483001 :                         return rc;
     864             :                 }
     865             : 
     866      170072 :                 if (tds->state == TDS_IDLE || tds->state == TDS_SENDING)
     867         692 :                         return cancel_seen ? TDS_CANCELLED : TDS_NO_MORE_RESULTS;
     868             : 
     869      169380 :                 if (tds->state == TDS_DEAD) {
     870             :                         /* TODO free all results ?? */
     871             :                         return TDS_FAIL;
     872             :                 }
     873             :         }
     874             : }
     875             : 
     876             : /**
     877             :  * Process results for simple query as "SET TEXTSIZE" or "USE dbname"
     878             :  * If the statement returns results, beware they are discarded.
     879             :  *
     880             :  * This function was written to avoid direct calls to tds_process_default_tokens
     881             :  * (which caused problems such as ignoring query errors).
     882             :  * Results are read until idle state or severe failure (do not stop for 
     883             :  * statement failure).
     884             :  * @return see tds_process_tokens for results (TDS_NO_MORE_RESULTS is never returned)
     885             :  */
     886             : TDSRET
     887        7476 : tds_process_simple_query(TDSSOCKET * tds)
     888             : {
     889             :         TDS_INT res_type;
     890             :         TDS_INT done_flags;
     891             :         TDSRET  rc;
     892        7476 :         TDSRET  ret = TDS_SUCCESS;
     893             : 
     894        7476 :         CHECK_TDS_EXTRA(tds);
     895             : 
     896       21930 :         while ((rc = tds_process_tokens(tds, &res_type, &done_flags, TDS_RETURN_DONE)) == TDS_SUCCESS) {
     897        6978 :                 switch (res_type) {
     898             : 
     899        6978 :                         case TDS_DONE_RESULT:
     900             :                         case TDS_DONEPROC_RESULT:
     901             :                         case TDS_DONEINPROC_RESULT:
     902        6978 :                                 if ((done_flags & TDS_DONE_ERROR) != 0) 
     903          18 :                                         ret = TDS_FAIL;
     904             :                                 break;
     905             : 
     906             :                         default:
     907             :                                 break;
     908             :                 }
     909             :         }
     910        7476 :         if (TDS_FAILED(rc))
     911          14 :                 ret = rc;
     912             : 
     913        7476 :         return ret;
     914             : }
     915             : 
     916             : /**
     917             :  * Holds list of names
     918             :  */
     919             : struct namelist
     920             : {
     921             :         /** string name */
     922             :         char *name;
     923             :         /** next element in the list */
     924             :         struct namelist *next;
     925             : };
     926             : 
     927             : /**
     928             :  * Frees list of names
     929             :  * \param head list head to free
     930             :  */
     931             : static void
     932         310 : tds_free_namelist(struct namelist *head)
     933             : {
     934         310 :         struct namelist *cur = head, *prev;
     935             : 
     936         958 :         while (cur != NULL) {
     937         338 :                 prev = cur;
     938         338 :                 cur = cur->next;
     939         338 :                 free(prev->name);
     940         338 :                 free(prev);
     941             :         }
     942         310 : }
     943             : 
     944             : /**
     945             :  * Reads list of names (usually table names)
     946             :  * \tds
     947             :  * \param remainder bytes left to read
     948             :  * \param p_head list head to return
     949             :  * \param large true if name length from network are 2 byte (usually 1)
     950             :  */
     951             : static int
     952          20 : tds_read_namelist(TDSSOCKET * tds, int remainder, struct namelist **p_head, int large)
     953             : {
     954          20 :         struct namelist *head = NULL, *cur = NULL, *prev;
     955          20 :         int num_names = 0;
     956             : 
     957             :         /*
     958             :          * this is a little messy...TDS 5.0 gives the number of columns
     959             :          * upfront, while in TDS 4.2, you're expected to figure it out
     960             :          * by the size of the message. So, I use a link list to get the
     961             :          * colum names and then allocate the result structure, copy
     962             :          * and delete the linked list
     963             :          */
     964          64 :         while (remainder > 0) {
     965             :                 TDS_USMALLINT namelen;
     966             : 
     967          24 :                 prev = cur;
     968          24 :                 if (!(cur = tds_new(struct namelist, 1))) {
     969           0 :                         tds_free_namelist(head);
     970           0 :                         return -1;
     971             :                 }
     972             : 
     973          24 :                 cur->next = NULL;
     974          24 :                 if (prev)
     975           4 :                         prev->next = cur;
     976             :                 else
     977             :                         head = cur;
     978             : 
     979          24 :                 if (large) {
     980           0 :                         namelen = tds_get_usmallint(tds);
     981           0 :                         remainder -= 2;
     982             :                 } else {
     983          24 :                         namelen = tds_get_byte(tds);
     984          24 :                         --remainder;
     985             :                 }
     986             : 
     987          24 :                 if (tds_alloc_get_string(tds, &cur->name, namelen) < 0) {
     988           0 :                         tds_free_namelist(head);
     989           0 :                         return -1;
     990             :                 }
     991             : 
     992          24 :                 remainder -= namelen;
     993          24 :                 if (IS_TDS7_PLUS(tds->conn))
     994           0 :                         remainder -= namelen;
     995          24 :                 num_names++;
     996             :         }
     997             : 
     998          20 :         *p_head = head;
     999          20 :         return num_names;
    1000             : }
    1001             : 
    1002             : /**
    1003             :  * tds_process_col_name() is one half of the result set under TDS 4.2
    1004             :  * it contains all the column names, a TDS_COLFMT_TOKEN should 
    1005             :  * immediately follow this token with the datatype/size information
    1006             :  * This is a 4.2 only function
    1007             :  * \tds
    1008             :  */
    1009             : static TDSRET
    1010           0 : tds_process_col_name(TDSSOCKET * tds)
    1011             : {
    1012             :         int hdrsize;
    1013           0 :         int col, num_names = 0;
    1014           0 :         struct namelist *head = NULL, *cur = NULL;
    1015             :         TDSCOLUMN *curcol;
    1016             :         TDSRESULTINFO *info;
    1017             : 
    1018           0 :         CHECK_TDS_EXTRA(tds);
    1019             : 
    1020           0 :         hdrsize = tds_get_usmallint(tds);
    1021             : 
    1022           0 :         if ((num_names = tds_read_namelist(tds, hdrsize, &head, 0)) < 0)
    1023             :                 return TDS_FAIL;
    1024             : 
    1025             :         /* free results/computes/params etc... */
    1026           0 :         tds_free_all_results(tds);
    1027           0 :         tds->rows_affected = TDS_NO_COUNT;
    1028             : 
    1029           0 :         if ((info = tds_alloc_results(num_names)) == NULL)
    1030             :                 goto memory_error;
    1031             : 
    1032           0 :         tds->res_info = info;
    1033           0 :         tds_set_current_results(tds, info);
    1034             : 
    1035           0 :         cur = head;
    1036           0 :         for (col = 0; col < num_names; ++col) {
    1037           0 :                 curcol = info->columns[col];
    1038           0 :                 if (!tds_dstr_copy(&curcol->column_name, cur->name))
    1039             :                         goto memory_error;
    1040           0 :                 cur = cur->next;
    1041             :         }
    1042           0 :         tds_free_namelist(head);
    1043           0 :         return TDS_SUCCESS;
    1044             : 
    1045           0 : memory_error:
    1046           0 :         tds_free_namelist(head);
    1047           0 :         return TDS_FAIL;
    1048             : }
    1049             : 
    1050             : /**
    1051             :  * tds_process_col_fmt() is the other half of result set processing
    1052             :  * under TDS 4.2. It follows tds_process_col_name(). It contains all the 
    1053             :  * column type and size information.
    1054             :  * This is a 4.2 only function
    1055             :  * \tds
    1056             :  */
    1057             : static TDSRET
    1058           0 : tds_process_col_fmt(TDSSOCKET * tds)
    1059             : {
    1060             :         unsigned int col;
    1061             :         TDSCOLUMN *curcol;
    1062             :         TDSRESULTINFO *info;
    1063             :         TDS_USMALLINT flags;
    1064             : 
    1065           0 :         CHECK_TDS_EXTRA(tds);
    1066             : 
    1067           0 :         tds_get_usmallint(tds); /* hdrsize */
    1068             : 
    1069             :         /* TODO use current_results instead of res_info ?? */
    1070           0 :         info = tds->res_info;
    1071           0 :         if (!info || info->num_cols < 0)
    1072             :                 return TDS_FAIL;
    1073           0 :         for (col = 0; col < info->num_cols; col++) {
    1074           0 :                 curcol = info->columns[col];
    1075             :                 /* In Sybase all 4 byte are used for usertype, while mssql place 2 byte as usertype and 2 byte as flags */
    1076           0 :                 if (TDS_IS_MSSQL(tds)) {
    1077           0 :                         curcol->column_usertype = tds_get_smallint(tds);
    1078           0 :                         flags = tds_get_usmallint(tds);
    1079           0 :                         curcol->column_nullable = flags & 0x01;
    1080           0 :                         curcol->column_writeable = (flags & 0x08) > 0;
    1081           0 :                         curcol->column_identity = (flags & 0x10) > 0;
    1082             :                 } else {
    1083           0 :                         curcol->column_usertype = tds_get_int(tds);
    1084             :                 }
    1085             :                 /* on with our regularly scheduled code (mlilback, 11/7/01) */
    1086           0 :                 TDS_GET_COLUMN_TYPE(curcol);
    1087             : 
    1088           0 :                 tdsdump_log(TDS_DBG_INFO1, "processing result. type = %d(%s), varint_size %d\n",
    1089           0 :                             curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
    1090             : 
    1091           0 :                 TDS_GET_COLUMN_INFO(tds, curcol);
    1092             : 
    1093             :                 /* Adjust column size according to client's encoding */
    1094           0 :                 curcol->on_server.column_size = curcol->column_size;
    1095           0 :                 adjust_character_column_size(tds, curcol);
    1096             :         }
    1097             : 
    1098           0 :         return tds_alloc_row(info);
    1099             : }
    1100             : 
    1101             : /**
    1102             :  * Reads table names for TDS 7.1+.
    1103             :  * TDS 7.1+ return table names as an array of names
    1104             :  * (so database.schema.owner.name as separate names)
    1105             :  * \tds
    1106             :  * \param remainder bytes left to read
    1107             :  * \param p_head pointer to list head to return
    1108             :  * \return number of element returned or -1 on error
    1109             :  */
    1110             : static int
    1111         290 : tds71_read_table_names(TDSSOCKET *tds, int remainder, struct namelist **p_head)
    1112             : {
    1113         290 :         struct namelist *head = NULL, *cur = NULL, *prev;
    1114         290 :         int num_names = 0;
    1115             : 
    1116             :         /*
    1117             :          * this is a little messy...TDS 5.0 gives the number of columns
    1118             :          * upfront, while in TDS 4.2, you're expected to figure it out
    1119             :          * by the size of the message. So, I use a link list to get the
    1120             :          * colum names and then allocate the result structure, copy
    1121             :          * and delete the linked list
    1122             :          */
    1123         894 :         while (remainder > 0) {
    1124             :                 int elements, i;
    1125             :                 size_t len;
    1126             :                 char *partials[4], *p;
    1127             : 
    1128         314 :                 prev = cur;
    1129         314 :                 if (!(cur = tds_new(struct namelist, 1))) {
    1130           0 :                         tds_free_namelist(head);
    1131           0 :                         return -1;
    1132             :                 }
    1133             : 
    1134         314 :                 cur->name = NULL;
    1135         314 :                 cur->next = NULL;
    1136         314 :                 if (prev)
    1137          24 :                         prev->next = cur;
    1138             :                 else
    1139             :                         head = cur;
    1140             : 
    1141         314 :                 elements = tds_get_byte(tds);
    1142         314 :                 --remainder;
    1143         314 :                 if (elements <= 0 || elements > 4) {
    1144           0 :                         tds_free_namelist(head);
    1145           0 :                         return -1;
    1146             :                 }
    1147             : 
    1148             :                 /* read partials IDs and compute full length */
    1149             :                 len = 0;
    1150         314 :                 for (i = 0; i < elements; ++i) {
    1151         314 :                         TDS_USMALLINT namelen = tds_get_usmallint(tds);
    1152         314 :                         remainder -= 2 + 2 * namelen;
    1153         314 :                         if (tds_alloc_get_string(tds, &partials[i], namelen) < 0) {
    1154           0 :                                 while (i > 0)
    1155           0 :                                         free(partials[--i]);
    1156           0 :                                 tds_free_namelist(head);
    1157           0 :                                 return -1;
    1158             :                         }
    1159         314 :                         len += tds_quote_id(tds, NULL, partials[i], -1) + 1;
    1160             :                 }
    1161             : 
    1162             :                 /* allocate full name */
    1163         314 :                 p = tds_new(char, len);
    1164         314 :                 if (!p) {
    1165             :                         i = elements;
    1166           0 :                         while (i > 0)
    1167           0 :                                 free(partials[--i]);
    1168           0 :                         tds_free_namelist(head);
    1169           0 :                         return -1;
    1170             :                 }
    1171             : 
    1172             :                 /* compose names */
    1173         314 :                 cur->name = p;
    1174         628 :                 for (i = 0; i < elements; ++i) {
    1175         314 :                         p += tds_quote_id(tds, p, partials[i], -1);
    1176         314 :                         *p++ = '.';
    1177         314 :                         free(partials[i]);
    1178             :                 }
    1179         314 :                 *--p = 0;
    1180             : 
    1181         314 :                 num_names++;
    1182             :         }
    1183             : 
    1184         290 :         *p_head = head;
    1185         290 :         return num_names;
    1186             : }
    1187             : 
    1188             : /**
    1189             :  * Process list of table from network.
    1190             :  * This token is only TDS 4.2
    1191             :  * \tds
    1192             :  */
    1193             : static TDSRET
    1194         292 : tds_process_tabname(TDSSOCKET *tds)
    1195             : {
    1196             :         struct namelist *head, *cur;
    1197             :         int num_names, hdrsize, i;
    1198             :         char **names;
    1199             :         unsigned char marker;
    1200             :         TDSRET rc;
    1201             : 
    1202         292 :         hdrsize = tds_get_usmallint(tds);
    1203             : 
    1204             :         /* different structure for tds7.1 */
    1205             :         /* hdrsize check is required for tds7.1 revision 1 (mssql without SPs) */
    1206             :         /* TODO change tds_version ?? */
    1207         292 :         if (IS_TDS71_PLUS(tds->conn) && (!IS_TDS71(tds->conn) || !tds->conn->tds71rev1))
    1208         290 :                 num_names = tds71_read_table_names(tds, hdrsize, &head);
    1209             :         else
    1210           2 :                 num_names = tds_read_namelist(tds, hdrsize, &head, IS_TDS7_PLUS(tds->conn));
    1211         292 :         if (num_names <= 0)
    1212             :                 return TDS_FAIL;
    1213             : 
    1214             :         /* put in an array */
    1215         292 :         names = tds_new(char*, num_names);
    1216         292 :         if (!names) {
    1217           0 :                 tds_free_namelist(head);
    1218           0 :                 return TDS_FAIL;
    1219             :         }
    1220         612 :         for (cur = head, i = 0; i < num_names; ++i, cur = cur->next)
    1221         320 :                 names[i] = cur->name;
    1222             : 
    1223         292 :         rc = TDS_SUCCESS;
    1224         292 :         marker = tds_get_byte(tds);
    1225         292 :         if (marker != TDS_COLINFO_TOKEN)
    1226           0 :                 tds_unget_byte(tds);
    1227             :         else
    1228         292 :                 rc = tds_process_colinfo(tds, names, num_names);
    1229             : 
    1230         292 :         free(names);
    1231         292 :         tds_free_namelist(head);
    1232         292 :         return rc;
    1233             : }
    1234             : 
    1235             : /**
    1236             :  * Reads column information.
    1237             :  * This token is only TDS 4.2
    1238             :  * \tds
    1239             :  * \param[in] names table names
    1240             :  * \param[in] num_names number of table names
    1241             :  */
    1242             : static TDSRET
    1243         298 : tds_process_colinfo(TDSSOCKET * tds, char **names, int num_names)
    1244             : {
    1245             :         unsigned int hdrsize, l;
    1246             :         TDSCOLUMN *curcol;
    1247             :         TDSRESULTINFO *info;
    1248         298 :         unsigned int bytes_read = 0;
    1249             :         struct {
    1250             :                 unsigned char num_col;
    1251             :                 unsigned char num_table;
    1252             :                 unsigned char flags;
    1253             :         } col_info;
    1254             : 
    1255         298 :         CHECK_TDS_EXTRA(tds);
    1256             : 
    1257         298 :         hdrsize = tds_get_usmallint(tds);
    1258             : 
    1259         298 :         info = tds->current_results;
    1260             : 
    1261        1722 :         while (bytes_read < hdrsize) {
    1262             : 
    1263        1126 :                 tds_get_n(tds, &col_info, 3);
    1264        1126 :                 bytes_read += 3;
    1265             : 
    1266        1126 :                 curcol = NULL;
    1267        1126 :                 if (info && col_info.num_col > 0 && col_info.num_col <= info->num_cols)
    1268        1126 :                         curcol = info->columns[col_info.num_col - 1];
    1269             : 
    1270        1126 :                 if (curcol) {
    1271        1126 :                         curcol->column_writeable = (col_info.flags & 0x4) == 0;
    1272        1126 :                         curcol->column_key = (col_info.flags & 0x8) > 0;
    1273        1126 :                         curcol->column_hidden = (col_info.flags & 0x10) > 0;
    1274             : 
    1275        1126 :                         if (names && col_info.num_table > 0 && col_info.num_table <= num_names)
    1276         814 :                                 if (!tds_dstr_copy(&curcol->table_name, names[col_info.num_table - 1]))
    1277             :                                         return TDS_FAIL;
    1278             :                 }
    1279             :                 /* read real column name */
    1280        1126 :                 if (col_info.flags & 0x20) {
    1281          36 :                         l = tds_get_byte(tds);
    1282          36 :                         if (curcol) {
    1283          36 :                                 tds_dstr_get(tds, &curcol->table_column_name, l);
    1284          36 :                                 if (IS_TDS7_PLUS(tds->conn))
    1285          32 :                                         l *= 2;
    1286             :                         } else {
    1287           0 :                                 if (IS_TDS7_PLUS(tds->conn))
    1288           0 :                                         l *= 2;
    1289             :                                 /* discard silently */
    1290           0 :                                 tds_get_n(tds, NULL, l);
    1291             :                         }
    1292          36 :                         bytes_read += l + 1;
    1293             :                 }
    1294             :         }
    1295             : 
    1296             :         return TDS_SUCCESS;
    1297             : }
    1298             : 
    1299             : /**
    1300             :  * process output parameters of a stored 
    1301             :  * procedure. This differs from regular row/compute results in that there
    1302             :  * is no total number of parameters given, they just show up singly.
    1303             :  * \tds
    1304             :  * \param[out] pinfo output parameter.
    1305             :  *             Should point to a not allocated structure
    1306             :  */
    1307             : static TDSRET
    1308       12544 : tds_process_param_result(TDSSOCKET * tds, TDSPARAMINFO ** pinfo)
    1309             : {
    1310             :         TDSCOLUMN *curparam;
    1311             :         TDSPARAMINFO *info;
    1312             :         TDSRET token;
    1313             : 
    1314       12544 :         tdsdump_log(TDS_DBG_FUNC, "tds_process_param_result(%p, %p)\n", tds, pinfo);
    1315             : 
    1316       12544 :         CHECK_TDS_EXTRA(tds);
    1317       12544 :         if (*pinfo)
    1318        7294 :                 CHECK_PARAMINFO_EXTRA(*pinfo);
    1319             : 
    1320             :         /* TODO check if current_results is a param result */
    1321             : 
    1322             :         /* limited to 64K but possible types are always smaller (not TEXT/IMAGE) */
    1323       12544 :         tds_get_smallint(tds);  /* header size */
    1324       12544 :         if ((info = tds_alloc_param_result(*pinfo)) == NULL)
    1325             :                 return TDS_FAIL;
    1326             : 
    1327       12544 :         *pinfo = info;
    1328       12544 :         curparam = info->columns[info->num_cols - 1];
    1329             : 
    1330             :         /*
    1331             :          * FIXME check support for tds7+ (seem to use same format of tds5 for data...)
    1332             :          * perhaps varint_size can be 2 or collation can be specified ??
    1333             :          */
    1334       12544 :         TDS_PROPAGATE(tds_get_data_info(tds, curparam, 1));
    1335             : 
    1336       12544 :         curparam->column_cur_size = curparam->column_size;        /* needed ?? */
    1337             : 
    1338       12544 :         if (tds_alloc_param_data(curparam) == NULL)
    1339             :                 return TDS_FAIL;
    1340             : 
    1341       12544 :         token = curparam->funcs->get_data(tds, curparam);
    1342       12544 :         if (TDS_UNLIKELY(tds_write_dump))
    1343           0 :                 tdsdump_col(curparam);
    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       25088 :         if (!tds_dstr_isempty(&curparam->column_name) && tds_dstr_cstr(&curparam->column_name)[0] != '@')
    1351          18 :                 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         834 : tds_process_param_result_tokens(TDSSOCKET * tds)
    1365             : {
    1366             :         int marker;
    1367             :         TDSPARAMINFO **pinfo;
    1368             : 
    1369         834 :         CHECK_TDS_EXTRA(tds);
    1370             : 
    1371         834 :         if (tds->cur_dyn)
    1372           0 :                 pinfo = &(tds->cur_dyn->res_info);
    1373             :         else
    1374         834 :                 pinfo = &(tds->param_info);
    1375             : 
    1376        1924 :         while ((marker = tds_get_byte(tds)) == TDS_PARAM_TOKEN) {
    1377        1090 :                 TDS_PROPAGATE(tds_process_param_result(tds, pinfo));
    1378             :         }
    1379         834 :         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         834 :         tds_set_current_results(tds, *pinfo);
    1385         834 :         tds_unget_byte(tds);
    1386         834 :         return TDS_SUCCESS;
    1387             : }
    1388             : 
    1389             : /**
    1390             :  * tds_process_params_result_token() processes params on TDS5.
    1391             :  * \tds
    1392             :  */
    1393             : static TDSRET
    1394         100 : tds_process_params_result_token(TDSSOCKET * tds)
    1395             : {
    1396             :         unsigned int i;
    1397             :         TDSPARAMINFO *info;
    1398             : 
    1399         100 :         CHECK_TDS_EXTRA(tds);
    1400             : 
    1401             :         /* TODO check if current_results is a param result */
    1402         100 :         info = tds->current_results;
    1403         100 :         if (!info)
    1404             :                 return TDS_FAIL;
    1405             : 
    1406         158 :         for (i = 0; i < info->num_cols; i++) {
    1407         158 :                 TDSCOLUMN *curcol = info->columns[i];
    1408         158 :                 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       43907 : tds7_get_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol)
    1521             : {
    1522       43907 :         CHECK_TDS_EXTRA(tds);
    1523       43907 :         CHECK_COLUMN_EXTRA(curcol);
    1524             : 
    1525             :         /*  User defined data type of the column */
    1526       43907 :         curcol->column_usertype = IS_TDS72_PLUS(tds->conn) ? tds_get_int(tds) : tds_get_smallint(tds);
    1527             : 
    1528       43907 :         curcol->column_flags = tds_get_smallint(tds);        /*  Flags */
    1529             : 
    1530       43907 :         curcol->column_nullable = curcol->column_flags & 0x01;
    1531       43907 :         curcol->column_writeable = (curcol->column_flags & 0x08) > 0;
    1532       43907 :         curcol->column_identity = (curcol->column_flags & 0x10) > 0;
    1533       43907 :         curcol->column_computed = (curcol->column_flags & 0x20) > 0;
    1534             : 
    1535       87814 :         TDS_GET_COLUMN_TYPE(curcol);    /* sets "cardinal" type */
    1536             : 
    1537       43907 :         curcol->column_timestamp = (curcol->column_type == SYBBINARY && curcol->column_usertype == TDS_UT_TIMESTAMP);
    1538             : 
    1539       43907 :         TDS_GET_COLUMN_INFO(tds, curcol);
    1540             : 
    1541             :         /* Adjust column size according to client's encoding */
    1542       43907 :         curcol->on_server.column_size = curcol->column_size;
    1543             : 
    1544             :         /* NOTE adjustements must be done after curcol->char_conv initialization */
    1545       43907 :         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       43907 :         tds_dstr_get(tds, &curcol->column_name, tds_get_byte(tds));
    1552             : 
    1553       43927 :         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           4 :                     tds_dstr_cstr(&curcol->column_name),
    1560           4 :                     curcol->column_type, tds_prtype(curcol->column_type), 
    1561           4 :                     curcol->on_server.column_type, tds_prtype(curcol->on_server.column_type), 
    1562           4 :                     curcol->column_varint_size,
    1563             :                     curcol->column_size, curcol->on_server.column_size);
    1564             : 
    1565       43907 :         CHECK_COLUMN_EXTRA(curcol);
    1566             : 
    1567       43907 :         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       25321 : tds7_process_result(TDSSOCKET * tds)
    1578             : {
    1579             :         int col, num_cols;
    1580             :         TDSRET result;
    1581             :         TDSRESULTINFO *info;
    1582             : 
    1583       25321 :         CHECK_TDS_EXTRA(tds);
    1584       25321 :         tdsdump_log(TDS_DBG_INFO1, "processing TDS7 result metadata.\n");
    1585             : 
    1586             :         /* read number of columns and allocate the columns structure */
    1587             : 
    1588       25321 :         num_cols = tds_get_smallint(tds);
    1589             : 
    1590             :         /* This can be a DUMMY results token from a cursor fetch */
    1591             : 
    1592       25321 :         if (num_cols < 0) {
    1593         824 :                 tdsdump_log(TDS_DBG_INFO1, "no meta data\n");
    1594             :                 return TDS_SUCCESS;
    1595             :         }
    1596             : 
    1597       24497 :         tds_free_all_results(tds);
    1598       24497 :         tds->rows_affected = TDS_NO_COUNT;
    1599             : 
    1600       24497 :         if ((info = tds_alloc_results(num_cols)) == NULL)
    1601             :                 return TDS_FAIL;
    1602       24497 :         tds_set_current_results(tds, info);
    1603       24497 :         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       24193 :                 tds->res_info = info;
    1609       24193 :                 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       24497 :         tdsdump_log(TDS_DBG_INFO1, "setting up %d columns\n", num_cols);
    1617       43853 :         for (col = 0; col < num_cols; col++) {
    1618       43853 :                 TDSCOLUMN *curcol = info->columns[col];
    1619             : 
    1620       43853 :                 TDS_PROPAGATE(tds7_get_data_info(tds, curcol));
    1621             :         }
    1622             :                 
    1623       24497 :         if (num_cols > 0) {
    1624             :                 static const char dashes[31] = "------------------------------";
    1625       24497 :                 tdsdump_log(TDS_DBG_INFO1, " %-20s %-15s %-15s %-7s\n", "name", "size/wsize", "type/wtype", "utype");
    1626       24497 :                 tdsdump_log(TDS_DBG_INFO1, " %-20s %15s %15s %7s\n", dashes+10, dashes+30-15, dashes+30-15, dashes+30-7);
    1627             :         }
    1628       43853 :         for (col = 0; col < num_cols; col++) {
    1629       43853 :                 TDSCOLUMN *curcol = info->columns[col];
    1630             : 
    1631       43865 :                 tdsdump_log(TDS_DBG_INFO1, " %-20s %7d/%-7d %7d/%-7d %7d\n", 
    1632           4 :                                                 tds_dstr_cstr(&curcol->column_name), 
    1633             :                                                 curcol->column_size, curcol->on_server.column_size, 
    1634           4 :                                                 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       24497 :         result = tds_alloc_row(info);
    1640       24497 :         CHECK_TDS_EXTRA(tds);
    1641       24497 :         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       13268 : tds_get_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int is_param)
    1653             : {
    1654       13268 :         CHECK_TDS_EXTRA(tds);
    1655       13268 :         CHECK_COLUMN_EXTRA(curcol);
    1656             : 
    1657       13268 :         tdsdump_log(TDS_DBG_INFO1, "tds_get_data_info(%p, %p, %d) %s\n", tds, curcol, is_param, is_param? "[for parameter]" : "");
    1658             : 
    1659       13268 :         tds_dstr_get(tds, &curcol->column_name, tds_get_byte(tds));
    1660             : 
    1661       13268 :         curcol->column_flags = tds_get_byte(tds);    /*  Flags */
    1662       13268 :         if (!is_param) {
    1663             :                 /* TODO check if all flags are the same for all TDS versions */
    1664         696 :                 if (IS_TDS50(tds->conn))
    1665         696 :                         curcol->column_hidden = curcol->column_flags & 0x1;
    1666         696 :                 curcol->column_key = (curcol->column_flags & 0x2) > 1;
    1667         696 :                 curcol->column_writeable = (curcol->column_flags & 0x10) > 1;
    1668         696 :                 curcol->column_nullable = (curcol->column_flags & 0x20) > 1;
    1669         696 :                 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       13268 :         if (IS_TDS72_PLUS(tds->conn)) {
    1703        6328 :                 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       13268 :         curcol->column_usertype = tds_get_int(tds);
    1717       26536 :         TDS_GET_COLUMN_TYPE(curcol);
    1718             : 
    1719       13268 :         tdsdump_log(TDS_DBG_INFO1, "processing result. type = %d(%s), varint_size %d\n",
    1720           0 :                     curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
    1721             : 
    1722       13268 :         TDS_GET_COLUMN_INFO(tds, curcol);
    1723             : 
    1724       13268 :         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       13268 :         curcol->on_server.column_size = curcol->column_size;
    1728       13268 :         adjust_character_column_size(tds, curcol);
    1729             : 
    1730       13268 :         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          58 : tds5_process_result(TDSSOCKET * tds)
    1741             : {
    1742             :         unsigned int col, num_cols;
    1743             :         TDSCOLUMN *curcol;
    1744             :         TDSRESULTINFO *info;
    1745             : 
    1746          58 :         CHECK_TDS_EXTRA(tds);
    1747             : 
    1748          58 :         tds_free_all_results(tds);
    1749          58 :         tds->rows_affected = TDS_NO_COUNT;
    1750             : 
    1751          58 :         tds_get_usmallint(tds); /* header size */
    1752             : 
    1753             :         /* read number of columns and allocate the columns structure */
    1754          58 :         num_cols = tds_get_usmallint(tds);
    1755             : 
    1756          58 :         if ((info = tds_alloc_results(num_cols)) == NULL)
    1757             :                 return TDS_FAIL;
    1758          58 :         tds_set_current_results(tds, info);
    1759          58 :         if (tds->cur_cursor)
    1760           0 :                 tds->cur_cursor->res_info = info;
    1761             :         else
    1762          58 :                 tds->res_info = info;
    1763             : 
    1764             :         /*
    1765             :          * loop through the columns populating COLINFO struct from
    1766             :          * server response
    1767             :          */
    1768         696 :         for (col = 0; col < info->num_cols; col++) {
    1769         696 :                 curcol = info->columns[col];
    1770             : 
    1771         696 :                 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         696 :                 tds_get_n(tds, NULL, tds_get_byte(tds));
    1776             :         }
    1777          58 :         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        6798 : tds5_process_result2(TDSSOCKET * tds)
    1788             : {
    1789             :         unsigned int colnamelen;
    1790             :         TDS_USMALLINT col, num_cols;
    1791             :         TDSCOLUMN *curcol;
    1792             :         TDSRESULTINFO *info;
    1793             : 
    1794        6798 :         CHECK_TDS_EXTRA(tds);
    1795             : 
    1796        6798 :         tdsdump_log(TDS_DBG_INFO1, "tds5_process_result2\n");
    1797             : 
    1798             :         /*
    1799             :          * free previous resultset
    1800             :          */
    1801        6798 :         tds_free_all_results(tds);
    1802        6798 :         tds->rows_affected = TDS_NO_COUNT;
    1803             : 
    1804             :         /*
    1805             :          * read length of packet (4 bytes)
    1806             :          */
    1807        6798 :         tds_get_uint(tds);
    1808             : 
    1809             :         /* read number of columns and allocate the columns structure */
    1810        6798 :         num_cols = tds_get_usmallint(tds);
    1811             : 
    1812        6798 :         if ((info = tds_alloc_results(num_cols)) == NULL)
    1813             :                 return TDS_FAIL;
    1814        6798 :         tds_set_current_results(tds, info);
    1815        6798 :         if (tds->cur_cursor)
    1816           8 :                 tds->cur_cursor->res_info = info;
    1817             :         else
    1818        6790 :                 tds->res_info = info;
    1819             : 
    1820        6798 :         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       11488 :         for (col = 0; col < info->num_cols; col++) {
    1828       11488 :                 curcol = info->columns[col];
    1829             : 
    1830             :                 /* label */
    1831       11488 :                 tds_dstr_get(tds, &curcol->column_name, tds_get_byte(tds));
    1832             : 
    1833             :                 /* TODO save information somewhere */
    1834             :                 /* database */
    1835       11488 :                 colnamelen = tds_get_byte(tds);
    1836       11488 :                 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       11488 :                 colnamelen = tds_get_byte(tds);
    1844       11488 :                 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       11488 :                 tds_dstr_get(tds, &curcol->table_name, tds_get_byte(tds));
    1853             : 
    1854             :                 /* table column name */
    1855       11488 :                 tds_dstr_get(tds, &curcol->table_column_name, tds_get_byte(tds));
    1856             : 
    1857             :                 /* if label is empty, use the table column name */
    1858       22976 :                 if (tds_dstr_isempty(&curcol->column_name))
    1859        8472 :                         if (!tds_dstr_dup(&curcol->column_name, &curcol->table_column_name))
    1860             :                                 return TDS_FAIL;
    1861             : 
    1862             :                 /* flags (4 bytes) */
    1863       11488 :                 curcol->column_flags = tds_get_int(tds);
    1864       11488 :                 curcol->column_hidden = curcol->column_flags & 0x1;
    1865       11488 :                 curcol->column_key = (curcol->column_flags & 0x2) > 1;
    1866       11488 :                 curcol->column_writeable = (curcol->column_flags & 0x10) > 1;
    1867       11488 :                 curcol->column_nullable = (curcol->column_flags & 0x20) > 1;
    1868       11488 :                 curcol->column_identity = (curcol->column_flags & 0x40) > 1;
    1869             : 
    1870       11488 :                 curcol->column_usertype = tds_get_int(tds);
    1871             : 
    1872       22976 :                 TDS_GET_COLUMN_TYPE(curcol);
    1873             : 
    1874       11488 :                 TDS_GET_COLUMN_INFO(tds, curcol);
    1875             : 
    1876             :                 /* Adjust column size according to client's encoding */
    1877       11488 :                 curcol->on_server.column_size = curcol->column_size;
    1878       11488 :                 adjust_character_column_size(tds, curcol);
    1879             : 
    1880             :                 /* discard Locale */
    1881       11488 :                 tds_get_n(tds, NULL, tds_get_byte(tds));
    1882             : 
    1883             :                 /* 
    1884             :                  *  Dump all information on this column
    1885             :                  */
    1886       11488 :                 tdsdump_log(TDS_DBG_INFO1, "col %d:\n", col);
    1887       11488 :                 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       11488 :                 tdsdump_log(TDS_DBG_INFO1, "\tflags=%x utype=%d type=%d server type %d varint=%d\n",
    1894           0 :                             curcol->column_flags, curcol->column_usertype, curcol->column_type, curcol->on_server.column_type,
    1895           0 :                             curcol->column_varint_size);
    1896             : 
    1897       11488 :                 tdsdump_log(TDS_DBG_INFO1, "\tcolsize=%d prec=%d scale=%d\n",
    1898           0 :                             curcol->column_size, curcol->column_prec, curcol->column_scale);
    1899             :         }
    1900        6798 :         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      358885 : tds_process_row(TDSSOCKET * tds)
    1949             : {
    1950             :         unsigned int i;
    1951             :         TDSCOLUMN *curcol;
    1952             :         TDSRESULTINFO *info;
    1953             : 
    1954      358885 :         CHECK_TDS_EXTRA(tds);
    1955             : 
    1956      358885 :         info = tds->current_results;
    1957      358885 :         if (!info || info->num_cols <= 0)
    1958             :                 return TDS_FAIL;
    1959             : 
    1960     1150347 :         for (i = 0; i < info->num_cols; i++) {
    1961     1150347 :                 tdsdump_log(TDS_DBG_INFO1, "tds_process_row(): reading column %d \n", i);
    1962     1150347 :                 curcol = info->columns[i];
    1963     1150347 :                 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        4940 : tds_process_nbcrow(TDSSOCKET * tds)
    1973             : {
    1974             :         unsigned int i;
    1975             :         TDSCOLUMN *curcol;
    1976             :         TDSRESULTINFO *info;
    1977             :         char *nbcbuf;
    1978             : 
    1979        4940 :         CHECK_TDS_EXTRA(tds);
    1980             : 
    1981        4940 :         info = tds->current_results;
    1982        4940 :         if (!info || info->num_cols <= 0)
    1983             :                 return TDS_FAIL;
    1984             : 
    1985        4940 :         nbcbuf = (char *) alloca((info->num_cols + 7) / 8);
    1986        4940 :         tds_get_n(tds, nbcbuf, (info->num_cols + 7) / 8);
    1987       41748 :         for (i = 0; i < info->num_cols; i++) {
    1988       36808 :                 curcol = info->columns[i];
    1989       36808 :                 tdsdump_log(TDS_DBG_INFO1, "tds_process_nbcrow(): reading column %d \n", i);
    1990       36808 :                 if (nbcbuf[i / 8] & (1 << (i % 8))) {
    1991        9828 :                         curcol->column_cur_size = -1;
    1992             :                 } else {
    1993       26980 :                         TDS_PROPAGATE(curcol->funcs->get_data(tds, curcol));
    1994             :                 }
    1995             :         }
    1996             :         return TDS_SUCCESS;
    1997             : }
    1998             : 
    1999             : static TDSRET
    2000         714 : tds_process_featureextack(TDSSOCKET * tds)
    2001             : {
    2002         714 :         CHECK_TDS_EXTRA(tds);
    2003             : 
    2004             :         /* TODO do something with it */
    2005         714 :         for (;;) {
    2006             :                 TDS_UINT data_len;
    2007             :                 TDS_TINYINT feature_id;
    2008             : 
    2009        1428 :                 feature_id = tds_get_byte(tds);
    2010        1428 :                 if (feature_id == 0xff)
    2011             :                         break;
    2012             : 
    2013         714 :                 data_len = tds_get_uint(tds);
    2014         714 :                 tds_get_n(tds, NULL, data_len);
    2015             :         }
    2016         714 :         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      181627 : 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      181627 :         CHECK_TDS_EXTRA(tds);
    2095             : 
    2096      181627 :         status = tds_get_usmallint(tds);
    2097             : 
    2098      181627 :         tds_get_smallint(tds);  /* state/command */
    2099             : 
    2100      181627 :         more_results = (status & TDS_DONE_MORE_RESULTS) != 0;
    2101      181627 :         was_cancelled = (status & TDS_DONE_CANCELLED) != 0;
    2102      181627 :         error = (status & TDS_DONE_ERROR) != 0;
    2103      181627 :         done_count_valid = (status & TDS_DONE_COUNT) != 0;
    2104             : 
    2105             : 
    2106      181627 :         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      181627 :         tds->in_row = false;
    2112             : 
    2113      181627 :         if (tds->res_info) {
    2114       38242 :                 tds->res_info->more_results = more_results;
    2115             :                 /* FIXME this should not happen !!! */
    2116       38242 :                 if (tds->current_results == NULL)
    2117           0 :                         tds_set_current_results(tds, tds->res_info);
    2118             : 
    2119             :         }
    2120             : 
    2121      181627 :         if (flags_parm)
    2122      156955 :                 *flags_parm = status;
    2123             : 
    2124      181627 :         rows_affected = IS_TDS72_PLUS(tds->conn) ? tds_get_int8(tds) : tds_get_int(tds);
    2125      181627 :         tdsdump_log(TDS_DBG_FUNC, "                rows_affected = %" PRId64 "\n", rows_affected);
    2126             : 
    2127      181627 :         if (was_cancelled || (!more_results && !tds->in_cancel)) {
    2128       79441 :                 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       79441 :                 tds->in_cancel = 0;
    2131       79441 :                 if (tds->bulk_query) {
    2132         400 :                         tds->out_flag = TDS_BULK;
    2133         400 :                         tds_set_state(tds, TDS_SENDING);
    2134         400 :                         tds->bulk_query = false;
    2135             :                 } else {
    2136       79041 :                         tds_set_state(tds, TDS_IDLE);
    2137       79041 :                         if (tds->conn->pending_close)
    2138           8 :                                 tds_process_pending_closes(tds);
    2139             :                 }
    2140             :         }
    2141             : 
    2142      181627 :         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      181627 :         if (done_count_valid)
    2151       51895 :                 tds->rows_affected = rows_affected;
    2152             :         else
    2153      129732 :                 tds->rows_affected = TDS_NO_COUNT;
    2154             : 
    2155             :         if (IS_TDSDEAD(tds))
    2156             :                 return TDS_FAIL;
    2157             : 
    2158      181627 :         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       20409 : tds_process_env_chg(TDSSOCKET * tds)
    2202             : {
    2203             :         unsigned int size;
    2204             :         TDS_TINYINT type;
    2205       20409 :         char *oldval = NULL;
    2206       20409 :         char *newval = NULL;
    2207             :         char **dest;
    2208             :         int new_block_size;
    2209       20409 :         int memrc = 0;
    2210             : 
    2211       20409 :         CHECK_TDS_EXTRA(tds);
    2212             : 
    2213       20409 :         size = tds_get_usmallint(tds);
    2214       20409 :         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       20409 :         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       20409 :         if (type == TDS_ENV_SQLCOLLATION) {
    2234             :                 /* save new collation */
    2235        5522 :                 size = tds_get_byte(tds);
    2236        5522 :                 tdsdump_log(TDS_DBG_ERROR, "tds_process_env_chg(): %d bytes of collation data received\n", size);
    2237        5522 :                 tdsdump_dump_buf(TDS_DBG_NETWORK, "tds->conn->collation was", tds->conn->collation, 5);
    2238        5522 :                 memset(tds->conn->collation, 0, 5);
    2239        5522 :                 if (size < 5) {
    2240           0 :                         tds_get_n(tds, tds->conn->collation, size);
    2241             :                 } else {
    2242        5522 :                         tds_get_n(tds, tds->conn->collation, 5);
    2243        5522 :                         tds_get_n(tds, NULL, size - 5);
    2244        5522 :                         tds7_srv_charset_changed(tds->conn, tds->conn->collation);
    2245             :                 }
    2246        5522 :                 tdsdump_dump_buf(TDS_DBG_NETWORK, "tds->conn->collation now", tds->conn->collation, 5);
    2247             :                 /* discard old one */
    2248        5522 :                 tds_get_n(tds, NULL, tds_get_byte(tds));
    2249        5522 :                 return TDS_SUCCESS;
    2250             :         }
    2251             : 
    2252       14887 :         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       14543 :         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       14233 :         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       14233 :         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       14233 :         memrc += tds_alloc_get_string(tds, &newval, tds_get_byte(tds));
    2280             : 
    2281             :         /* fetch the old value */
    2282       14233 :         memrc += tds_alloc_get_string(tds, &oldval, tds_get_byte(tds));
    2283             : 
    2284       14233 :         if (memrc != 0) {
    2285           0 :                 free(newval);
    2286           0 :                 free(oldval);
    2287           0 :                 return TDS_FAIL;
    2288             :         }
    2289             : 
    2290       14233 :         dest = NULL;
    2291       14233 :         switch (type) {
    2292        3638 :         case TDS_ENV_PACKSIZE:
    2293        7276 :                 new_block_size = atoi(newval);
    2294        3638 :                 if (new_block_size >= 512) {
    2295        3638 :                         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        3638 :                         tds_realloc_socket(tds, new_block_size);
    2302             :                 }
    2303             :                 break;
    2304        7131 :         case TDS_ENV_DATABASE:
    2305        7131 :                 dest = &tds->conn->env.database;
    2306        7131 :                 break;
    2307        2922 :         case TDS_ENV_LANG:
    2308        2922 :                 dest = &tds->conn->env.language;
    2309        2922 :                 break;
    2310         542 :         case TDS_ENV_CHARSET:
    2311         542 :                 tdsdump_log(TDS_DBG_FUNC, "server indicated charset change to \"%s\"\n", newval);
    2312         542 :                 dest = &tds->conn->env.charset;
    2313         542 :                 tds_srv_charset_changed(tds->conn, newval);
    2314         542 :                 break;
    2315             :         }
    2316       14233 :         if (tds->env_chg_func) {
    2317        7905 :                 (*(tds->env_chg_func)) (tds, type, oldval, newval);
    2318             :         }
    2319             : 
    2320       14233 :         free(oldval);
    2321       14233 :         if (newval) {
    2322       14233 :                 if (dest) {
    2323       10595 :                         free(*dest);
    2324       10595 :                         *dest = newval;
    2325             :                 } else
    2326        3638 :                         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       15703 : tds_process_info(TDSSOCKET * tds, int marker)
    2339             : {
    2340             :         int rc;
    2341             :         unsigned int len_sqlstate;
    2342       15703 :         int has_eed = 0;
    2343             :         TDSMESSAGE msg;
    2344       15703 :         unsigned int packet_len, char_len, readed_len = 10;
    2345             : 
    2346       15703 :         CHECK_TDS_EXTRA(tds);
    2347             : 
    2348       15703 :         if (!tds->in_row)
    2349       15421 :                 tds_free_all_results(tds);
    2350             : 
    2351             :         /* make sure message has been freed */
    2352       15703 :         memset(&msg, 0, sizeof(TDSMESSAGE));
    2353             : 
    2354             :         /* packet length */
    2355       15703 :         packet_len = tds_get_usmallint(tds);
    2356             : 
    2357             :         /* message number */
    2358       15703 :         msg.msgno = tds_get_int(tds);
    2359             : 
    2360             :         /* msg state */
    2361       15703 :         msg.state = tds_get_byte(tds);
    2362             : 
    2363             :         /* msg level */
    2364       15703 :         msg.severity = tds_get_byte(tds);
    2365             : 
    2366             :         /* determine if msg or error */
    2367       15703 :         switch (marker) {
    2368        2467 :         case TDS_EED_TOKEN:
    2369        2467 :                 if (msg.severity <= 10)
    2370        2243 :                         msg.priv_msg_type = 0;
    2371             :                 else
    2372         224 :                         msg.priv_msg_type = 1;
    2373             : 
    2374             :                 /* read SQL state */
    2375        2467 :                 len_sqlstate = tds_get_byte(tds);
    2376        2467 :                 msg.sql_state = tds_new(char, len_sqlstate + 1);
    2377        2467 :                 if (!msg.sql_state) {
    2378           0 :                         tds_free_msg(&msg);
    2379           0 :                         return TDS_FAIL;
    2380             :                 }
    2381             : 
    2382        2467 :                 tds_get_n(tds, msg.sql_state, len_sqlstate);
    2383        2467 :                 msg.sql_state[len_sqlstate] = '\0';
    2384             : 
    2385             :                 /* do a better mapping using native errors */
    2386        2467 :                 if (strcmp(msg.sql_state, "ZZZZZ") == 0)
    2387        2364 :                         TDS_ZERO_FREE(msg.sql_state);
    2388             : 
    2389             :                 /* if has_eed = 1, extended error data follows */
    2390        2467 :                 has_eed = tds_get_byte(tds);
    2391             : 
    2392             :                 /* junk status and transaction state */
    2393        2467 :                 tds_get_smallint(tds);
    2394        2467 :                 readed_len += 4 + len_sqlstate;
    2395        2467 :                 break;
    2396       11838 :         case TDS_INFO_TOKEN:
    2397       11838 :                 msg.priv_msg_type = 0;
    2398       11838 :                 break;
    2399        1398 :         case TDS_ERROR_TOKEN:
    2400        1398 :                 msg.priv_msg_type = 1;
    2401        1398 :                 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       15703 :         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       15703 :         char_len = 0;
    2417       15703 :         rc = 0;
    2418             : 
    2419             :         /* the message */
    2420       15703 :         GET_STRING(&msg.message, usmallint);
    2421             : 
    2422             :         /* server name */
    2423       15703 :         GET_STRING(&msg.server, byte);
    2424             : 
    2425       15703 :         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       15703 :         GET_STRING(&msg.proc_name, byte);
    2435             : 
    2436       15703 :         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       22813 :         if (tds->conn->product_version == 0 ?
    2441        7110 :             IS_TDS7_PLUS(tds->conn) && readed_len + 4 <= packet_len :
    2442             :             IS_TDS72_PLUS(tds->conn)) {
    2443        6714 :                 msg.line_number = tds_get_int(tds);
    2444        6714 :                 readed_len += 4;
    2445             :         } else {
    2446        8989 :                 msg.line_number = tds_get_smallint(tds);
    2447        8989 :                 readed_len += 2;
    2448             :         }
    2449             :         /* discard additional bytes */
    2450       15703 :         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       15703 :         if (msg.sql_state == NULL)
    2461       15600 :                 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       15703 :         if (has_eed == 1) {
    2466             :                 int 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       15703 :         if (rc != 0) {
    2488           0 :                 tds_free_msg(&msg);
    2489           0 :                 return TDS_FAIL;
    2490             :         }
    2491             : 
    2492             :         /* special case, */
    2493       15703 :         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       15643 :         } 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       13585 :                 if (tds_get_ctx(tds)->msg_handler) {
    2503       13174 :                         tdsdump_log(TDS_DBG_ERROR, "tds_process_info() calling client msg handler\n");
    2504       13174 :                         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           0 :                                     msg.severity ,
    2510           0 :                                     msg.state, msg.server, msg.line_number, msg.message);
    2511             :                 }
    2512             :         }
    2513             : 
    2514       15703 :         if (!tds->conn->server) {
    2515        3648 :                 tds->conn->server = msg.server;
    2516        3648 :                 msg.server = NULL;
    2517             :         }
    2518       15703 :         tds_free_msg(&msg);
    2519             :         
    2520       15703 :         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       79553 : tds_alloc_get_string(TDSSOCKET * tds, char **string, size_t len)
    2534             : {
    2535             :         char *s;
    2536             :         size_t out_len;
    2537             : 
    2538       79553 :         CHECK_TDS_EXTRA(tds);
    2539             : 
    2540             :         /* assure sufficient space for every conversion */
    2541       79553 :         s = tds_new(char, len * 4 + 1);
    2542       79553 :         out_len = tds_get_string(tds, len, s, len * 4);
    2543       79553 :         if (!s) {
    2544           0 :                 *string = NULL;
    2545           0 :                 return -1;
    2546             :         }
    2547       79553 :         s = (char*) realloc(s, out_len + 1);
    2548       79553 :         s[out_len] = '\0';
    2549       79553 :         *string = s;
    2550       79553 :         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       11642 : tds_process_cancel(TDSSOCKET * tds)
    2561             : {
    2562       11642 :         CHECK_TDS_EXTRA(tds);
    2563             : 
    2564             :         /* silly cases, nothing to do */
    2565       11642 :         if (!tds->in_cancel)
    2566             :                 return TDS_SUCCESS;
    2567             :         /* TODO handle cancellation sending data */
    2568        1556 :         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        1540 :                 switch (tds_process_tokens(tds, &result_type, NULL, 0)) {
    2576             :                 case TDS_FAIL:
    2577        1540 :                         return TDS_FAIL;
    2578        1540 :                 case TDS_CANCELLED:
    2579             :                 case TDS_SUCCESS:
    2580             :                 case TDS_NO_MORE_RESULTS:
    2581        1540 :                         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      657820 : tds_lookup_dynamic(TDSCONNECTION * conn, const char *id)
    2594             : {
    2595             :         TDSDYNAMIC *curr;
    2596             : 
    2597             :         CHECK_CONN_EXTRA(conn);
    2598             :         
    2599     1314234 :         for (curr = conn->dyns; curr != NULL; curr = curr->next) {
    2600      656424 :                 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         962 : tds_process_dynamic(TDSSOCKET * tds)
    2614             : {
    2615             :         unsigned int token_sz;
    2616             :         unsigned char type;
    2617         962 :         TDS_TINYINT id_len, drain = 0;
    2618             :         char id[TDS_MAX_DYNID_LEN + 1];
    2619             : 
    2620         962 :         CHECK_TDS_EXTRA(tds);
    2621             : 
    2622         962 :         token_sz = tds_get_usmallint(tds);
    2623         962 :         type = tds_get_byte(tds);
    2624         962 :         tds_get_byte(tds);      /* status */
    2625             :         /* handle only acknowledge */
    2626         962 :         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         962 :         id_len = tds_get_byte(tds);
    2632         962 :         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         962 :         id_len = tds_get_string(tds, id_len, id, TDS_MAX_DYNID_LEN);
    2637         962 :         id[id_len] = '\0';
    2638         962 :         if (drain) {
    2639           0 :                 tds_get_n(tds, NULL, drain);
    2640             :         }
    2641         962 :         return tds_lookup_dynamic(tds->conn, id);
    2642             : }
    2643             : 
    2644             : /**
    2645             :  * Process results from dynamic.
    2646             :  * \tds
    2647             :  */
    2648             : static TDSRET
    2649          20 : tds_process_dyn_result(TDSSOCKET * tds)
    2650             : {
    2651             :         unsigned int col, num_cols;
    2652             :         TDSCOLUMN *curcol;
    2653             :         TDSPARAMINFO *info;
    2654             :         TDSDYNAMIC *dyn;
    2655             : 
    2656          20 :         CHECK_TDS_EXTRA(tds);
    2657             : 
    2658          20 :         tds_get_usmallint(tds); /* header size */
    2659          20 :         num_cols = tds_get_usmallint(tds);
    2660             : 
    2661             :         /* read number of columns and allocate the columns structure */
    2662          20 :         if ((info = tds_alloc_results(num_cols)) == NULL)
    2663             :                 return TDS_FAIL;
    2664          20 :         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          20 :                 tds_free_param_results(tds->param_info);
    2670          20 :                 tds->param_info = info;
    2671             :         }
    2672          20 :         tds_set_current_results(tds, info);
    2673             : 
    2674          48 :         for (col = 0; col < info->num_cols; col++) {
    2675          28 :                 curcol = info->columns[col];
    2676             : 
    2677          28 :                 TDS_PROPAGATE(tds_get_data_info(tds, curcol, 1));
    2678             : 
    2679             :                 /* skip locale information */
    2680          28 :                 tds_get_n(tds, NULL, tds_get_byte(tds));
    2681             :         }
    2682             : 
    2683          20 :         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         334 : tds5_process_dyn_result2(TDSSOCKET * tds)
    2692             : {
    2693             :         unsigned int col, num_cols;
    2694             :         TDSCOLUMN *curcol;
    2695             :         TDSPARAMINFO *info;
    2696             : 
    2697         334 :         CHECK_TDS_EXTRA(tds);
    2698             : 
    2699         334 :         tds_get_uint(tds);      /* header size */
    2700         334 :         num_cols = tds_get_usmallint(tds);
    2701             : 
    2702             :         /* read number of columns and allocate the columns structure */
    2703         334 :         if ((info = tds_alloc_results(num_cols)) == NULL)
    2704             :                 return TDS_FAIL;
    2705         334 :         if (tds->cur_dyn) {
    2706         254 :                 TDSDYNAMIC *dyn = tds->cur_dyn;
    2707         254 :                 tds_free_param_results(dyn->res_info);
    2708         254 :                 dyn->res_info = info;
    2709             :         } else {
    2710          80 :                 tds_free_param_results(tds->param_info);
    2711          80 :                 tds->param_info = info;
    2712             :         }
    2713         334 :         tds_set_current_results(tds, info);
    2714             : 
    2715         768 :         for (col = 0; col < info->num_cols; col++) {
    2716         434 :                 curcol = info->columns[col];
    2717             : 
    2718             :                 /* TODO reuse tds_get_data_info code, sligthly different */
    2719             : 
    2720             :                 /* column name */
    2721         434 :                 tds_dstr_get(tds, &curcol->column_name, tds_get_byte(tds));
    2722             : 
    2723             :                 /* column status */
    2724         434 :                 curcol->column_flags = tds_get_int(tds);
    2725         434 :                 curcol->column_nullable = (curcol->column_flags & 0x20) > 0;
    2726             : 
    2727             :                 /* user type */
    2728         434 :                 curcol->column_usertype = tds_get_int(tds);
    2729             : 
    2730             :                 /* column type */
    2731         868 :                 TDS_GET_COLUMN_TYPE(curcol);
    2732             : 
    2733         434 :                 TDS_GET_COLUMN_INFO(tds, curcol);
    2734             : 
    2735             :                 /* Adjust column size according to client's encoding */
    2736         434 :                 curcol->on_server.column_size = curcol->column_size;
    2737         434 :                 adjust_character_column_size(tds, curcol);
    2738             : 
    2739             :                 /* discard Locale */
    2740         434 :                 tds_get_n(tds, NULL, tds_get_byte(tds));
    2741             : 
    2742         434 :                 tdsdump_log(TDS_DBG_INFO1, "elem %d:\n", col);
    2743         434 :                 tdsdump_log(TDS_DBG_INFO1, "\tcolumn_name=[%s]\n", tds_dstr_cstr(&curcol->column_name));
    2744         434 :                 tdsdump_log(TDS_DBG_INFO1, "\tflags=%x utype=%d type=%d server type %d varint=%d\n",
    2745           0 :                             curcol->column_flags, curcol->column_usertype, curcol->column_type, curcol->on_server.column_type,
    2746           0 :                             curcol->column_varint_size);
    2747         434 :                 tdsdump_log(TDS_DBG_INFO1, "\tcolsize=%d prec=%d scale=%d\n",
    2748           0 :                             curcol->column_size, curcol->column_prec, curcol->column_scale);
    2749             :         }
    2750             : 
    2751         334 :         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       69115 : adjust_character_column_size(TDSSOCKET * tds, TDSCOLUMN * curcol)
    3211             : {
    3212       69115 :         CHECK_TDS_EXTRA(tds);
    3213       69115 :         CHECK_COLUMN_EXTRA(curcol);
    3214             : 
    3215       69115 :         if (is_ascii_type(curcol->on_server.column_type)) {
    3216             :                 /* don't override setting from column collation */
    3217       23304 :                 if (!curcol->char_conv)
    3218        5526 :                         curcol->char_conv = tds->conn->char_convs[client2server_chardata];
    3219             :                 goto compute;
    3220             :         }
    3221             : 
    3222       45811 :         if (IS_TDS7_PLUS(tds->conn)) {
    3223       38453 :                 if (is_unicode_type(curcol->on_server.column_type))
    3224        4081 :                         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        7358 :         if (is_unicode_type(curcol->on_server.column_type) ||
    3230         806 :                 (curcol->on_server.column_type == SYBLONGBINARY && (
    3231         806 :                  curcol->column_usertype == USER_UNICHAR_TYPE ||
    3232             :                  curcol->column_usertype == USER_UNIVARCHAR_TYPE))) {
    3233         798 :                 const int canonic_client = tds->conn->char_convs[client2ucs2]->from.charset.canonic;
    3234         798 :                 const int sybase_utf16 = TDS_CHARSET_UTF_16LE;
    3235             : 
    3236        1596 :                 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         798 :                 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         798 :                 if (!curcol->char_conv)
    3246           0 :                         curcol->char_conv = tds->conn->char_convs[client2ucs2];
    3247             :         }
    3248             : 
    3249       76473 : compute:
    3250       69115 :         if (!USE_ICONV || !curcol->char_conv)
    3251             :                 return;
    3252             : 
    3253       19520 :         curcol->on_server.column_size = curcol->column_size;
    3254       39040 :         curcol->column_size = determine_adjusted_size(curcol->char_conv, curcol->column_size);
    3255             : 
    3256       19520 :         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       19520 :         if ((char_conv->flags & TDS_ENCODING_MEMCPY) != 0
    3285       16130 :             || char_conv->to.charset.canonic == char_conv->from.charset.canonic)
    3286             :                 return size;
    3287             : 
    3288             :         /* avoid possible overflow */
    3289       16130 :         if (size >= 0x10000000)
    3290             :                 return 0x7fffffff;
    3291             : 
    3292       15986 :         size *= char_conv->from.charset.max_bytes_per_char;
    3293       15986 :         if (size % char_conv->to.charset.min_bytes_per_char)
    3294           0 :                 size += char_conv->to.charset.min_bytes_per_char;
    3295       15986 :         size /= char_conv->to.charset.min_bytes_per_char;
    3296             : 
    3297             :         return size;
    3298             : }
    3299             : 
    3300             : /** @} */

Generated by: LCOV version 1.13