LCOV - code coverage report
Current view: top level - src/tds - token.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 1100 1461 75.3 %
Date: 2024-03-23 08:24:27 Functions: 41 45 91.1 %

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

Generated by: LCOV version 1.13