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