1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001  Brian Bruns
3  * Copyright (C) 2002, 2003, 2004, 2005  James K. Lowden
4  * Copyright (C) 2011-2015  Frediano Ziglio
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
22 #include <config.h>
23 
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <assert.h>
27 
28 #if HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif /* HAVE_STDLIB_H */
31 
32 #if HAVE_STRING_H
33 #include <string.h>
34 #endif /* HAVE_STRING_H */
35 
36 #include "ctpublic.h"
37 #include "ctlib.h"
38 #include <freetds/string.h>
39 #include <freetds/enum_cap.h>
40 #include <freetds/data.h>
41 #include "replacements.h"
42 
43 
44 static const char * ct_describe_cmd_state(CS_INT state);
45 /**
46  * Read a row of data
47  * @return 0 on success
48  */
49 static int _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read);
50 static int _ct_fetchable_results(CS_COMMAND * cmd);
51 static TDSRET _ct_process_return_status(TDSSOCKET * tds);
52 
53 static int _ct_fill_param(CS_INT cmd_type, CS_PARAM * param, CS_DATAFMT * datafmt, CS_VOID * data,
54 			  CS_INT * datalen, CS_SMALLINT * indicator, CS_BYTE byvalue);
55 void _ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number,
56 			  const char *fmt, ...);
57 int _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset);
58 static void _ct_initialise_cmd(CS_COMMAND *cmd);
59 static CS_RETCODE _ct_cancel_cleanup(CS_COMMAND * cmd);
60 
61 /* Added for CT_DIAG */
62 /* Code changes starts here - CT_DIAG - 01 */
63 
64 static CS_INT ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message);
65 static CS_INT ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message);
66 static CS_INT ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count);
67 static CS_INT ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message);
68 static CS_INT ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message);
69 
70 /* Code changes ends here - CT_DIAG - 01 */
71 
72 /* Added code for RPC functionality -SUHA */
73 /* RPC Code changes starts here */
74 
75 static void rpc_clear(CSREMOTE_PROC * rpc);
76 static void param_clear(CSREMOTE_PROC_PARAM * pparam);
77 
78 static TDSPARAMINFO *paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param);
79 
80 static CS_DYNAMIC * _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen);
81 static CS_INT  _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn);
82 static CS_DYNAMIC * _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen);
83 
84 /* RPC Code changes ends here */
85 
86 static const char *
_ct_get_layer(int layer)87 _ct_get_layer(int layer)
88 {
89 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_layer(%d)\n", layer);
90 
91 	switch (layer) {
92 	case 1:
93 		return "user api layer";
94 		break;
95 	case 2:
96 		return "blk layer";
97 		break;
98 	default:
99 		break;
100 	}
101 	return "unrecognized layer";
102 }
103 
104 static const char *
_ct_get_origin(int origin)105 _ct_get_origin(int origin)
106 {
107 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_origin(%d)\n", origin);
108 
109 	switch (origin) {
110 	case 1:
111 		return "external error";
112 		break;
113 	case 2:
114 		return "internal CT-Library error";
115 		break;
116 	case 4:
117 		return "common library error";
118 		break;
119 	case 5:
120 		return "intl library error";
121 		break;
122 	case 6:
123 		return "user error";
124 		break;
125 	case 7:
126 		return "internal BLK-Library error";
127 		break;
128 	default:
129 		break;
130 	}
131 	return "unrecognized origin";
132 }
133 
134 static const char *
_ct_get_user_api_layer_error(int error)135 _ct_get_user_api_layer_error(int error)
136 {
137 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_user_api_layer_error(%d)\n", error);
138 
139 	switch (error) {
140 	case 137:
141 		return  "A bind count of %1! is not consistent with the count supplied for existing binds. "
142 			"The current bind count is %2!.";
143 		break;
144 	case 138:
145 		return "Use direction CS_BLK_IN or CS_BLK_OUT for a bulk copy operation.";
146 		break;
147 	case 139:
148 		return "The parameter tblname cannot be NULL.";
149 		break;
150 	case 140:
151 		return "Failed when processing results from server.";
152 		break;
153 	case 141:
154 		return "Parameter %1! has an illegal value of %2!";
155 		break;
156 	case 142:
157 		return "No value or default value available and NULL not allowed. col = %1! row = %2! .";
158 		break;
159 	case 143:
160 		return "parameter name(s) must be supplied for LANGUAGE command.";
161 		break;
162 	case 16843163:
163 		return "This routine cannot be called when the command structure is idle.";
164 		break;
165 	default:
166 		break;
167 	}
168 	return "unrecognized error";
169 }
170 
171 static char *
_ct_get_msgstr(const char * funcname,int layer,int origin,int severity,int number)172 _ct_get_msgstr(const char *funcname, int layer, int origin, int severity, int number)
173 {
174 	char *m;
175 
176 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_msgstr(%s, %d, %d, %d, %d)\n", funcname, layer, origin, severity, number);
177 
178 	if (asprintf(&m,
179 		     "%s: %s: %s: %s", funcname, _ct_get_layer(layer), _ct_get_origin(origin), _ct_get_user_api_layer_error(number)
180 	    ) < 0) {
181 		return NULL;
182 	}
183 	return m;
184 }
185 
186 void
_ctclient_msg(CS_CONNECTION * con,const char * funcname,int layer,int origin,int severity,int number,const char * fmt,...)187 _ctclient_msg(CS_CONNECTION * con, const char *funcname, int layer, int origin, int severity, int number, const char *fmt, ...)
188 {
189 	CS_CONTEXT *ctx = con->ctx;
190 	va_list ap;
191 	CS_CLIENTMSG cm;
192 	char *msgstr;
193 
194 	tdsdump_log(TDS_DBG_FUNC, "_ctclient_msg(%p, %s, %d, %d, %d, %d, %s)\n", con, funcname, layer, origin, severity, number, fmt);
195 
196 	va_start(ap, fmt);
197 
198 	if (ctx->_clientmsg_cb) {
199 		cm.severity = severity;
200 		cm.msgnumber = (((layer << 24) & 0xFF000000)
201 				| ((origin << 16) & 0x00FF0000)
202 				| ((severity << 8) & 0x0000FF00)
203 				| ((number) & 0x000000FF));
204 		msgstr = _ct_get_msgstr(funcname, layer, origin, severity, number);
205 		tds_vstrbuild(cm.msgstring, CS_MAX_MSG, &(cm.msgstringlen), msgstr, CS_NULLTERM, fmt, CS_NULLTERM, ap);
206 		cm.msgstring[cm.msgstringlen] = '\0';
207 		free(msgstr);
208 		cm.osnumber = 0;
209 		cm.osstring[0] = '\0';
210 		cm.osstringlen = 0;
211 		cm.status = 0;
212 		/* cm.sqlstate */
213 		cm.sqlstatelen = 0;
214 		ctx->_clientmsg_cb(ctx, con, &cm);
215 	}
216 
217 	va_end(ap);
218 }
219 
220 static CS_RETCODE
ct_set_command_state(CS_COMMAND * cmd,CS_INT state)221 ct_set_command_state(CS_COMMAND *cmd, CS_INT state)
222 {
223 	tdsdump_log(TDS_DBG_FUNC, "setting command state to %s (from %s)\n",
224 		    ct_describe_cmd_state(state),
225 		    ct_describe_cmd_state(cmd->command_state));
226 
227 	cmd->command_state = state;
228 
229 	return CS_SUCCEED;
230 }
231 
232 static const char *
ct_describe_cmd_state(CS_INT state)233 ct_describe_cmd_state(CS_INT state)
234 {
235 	tdsdump_log(TDS_DBG_FUNC, "ct_describe_cmd_state(%d)\n", state);
236 
237 	switch (state) {
238 	case _CS_COMMAND_IDLE:
239 		return "IDLE";
240 	case _CS_COMMAND_BUILDING:
241 		return "BUILDING";
242 	case _CS_COMMAND_READY:
243 		return "READY";
244 	case _CS_COMMAND_SENT:
245 		return "SENT";
246 	}
247 	return "???";
248 }
249 
250 CS_RETCODE
ct_exit(CS_CONTEXT * ctx,CS_INT unused)251 ct_exit(CS_CONTEXT * ctx, CS_INT unused)
252 {
253 	tdsdump_log(TDS_DBG_FUNC, "ct_exit(%p, %d)\n", ctx, unused);
254 
255 	return CS_SUCCEED;
256 }
257 
258 CS_RETCODE
ct_init(CS_CONTEXT * ctx,CS_INT version)259 ct_init(CS_CONTEXT * ctx, CS_INT version)
260 {
261 	/* uncomment the next line to get pre-login trace */
262 	/* tdsdump_open("/tmp/tds2.log"); */
263 	tdsdump_log(TDS_DBG_FUNC, "ct_init(%p, %d)\n", ctx, version);
264 
265 	ctx->tds_ctx->msg_handler = _ct_handle_server_message;
266 	ctx->tds_ctx->err_handler = _ct_handle_client_message;
267 
268 	return CS_SUCCEED;
269 }
270 
271 CS_RETCODE
ct_con_alloc(CS_CONTEXT * ctx,CS_CONNECTION ** con)272 ct_con_alloc(CS_CONTEXT * ctx, CS_CONNECTION ** con)
273 {
274 	TDSLOGIN *login;
275 
276 	tdsdump_log(TDS_DBG_FUNC, "ct_con_alloc(%p, %p)\n", ctx, con);
277 
278 	login = tds_alloc_login(1);
279 	if (!login)
280 		return CS_FAIL;
281 	*con = (CS_CONNECTION *) calloc(1, sizeof(CS_CONNECTION));
282 	if (!*con) {
283 		tds_free_login(login);
284 		return CS_FAIL;
285 	}
286 	(*con)->tds_login = login;
287 	(*con)->server_addr = NULL;
288 
289 	/* so we know who we belong to */
290 	(*con)->ctx = ctx;
291 
292 	/* set default values */
293 	tds_set_library((*con)->tds_login, "CT-Library");
294 	/* tds_set_client_charset((*con)->tds_login, "iso_1"); */
295 	/* tds_set_packet((*con)->tds_login, TDS_DEF_BLKSZ); */
296 	return CS_SUCCEED;
297 }
298 
299 CS_RETCODE
ct_callback(CS_CONTEXT * ctx,CS_CONNECTION * con,CS_INT action,CS_INT type,CS_VOID * func)300 ct_callback(CS_CONTEXT * ctx, CS_CONNECTION * con, CS_INT action, CS_INT type, CS_VOID * func)
301 {
302 	int (*funcptr) (void *, void *, void *) = (int (*)(void *, void *, void *)) func;
303 
304 	tdsdump_log(TDS_DBG_FUNC, "ct_callback(%p, %p, %d, %d, %p)\n", ctx, con, action, type, func);
305 
306 	tdsdump_log(TDS_DBG_FUNC, "ct_callback() action = %s\n", CS_GET ? "CS_GET" : "CS_SET");
307 	/* one of these has to be defined */
308 	if (!ctx && !con)
309 		return CS_FAIL;
310 
311 	if (action == CS_GET) {
312 		switch (type) {
313 		case CS_CLIENTMSG_CB:
314 			*(void **) func = (CS_VOID *) (con ? con->_clientmsg_cb : ctx->_clientmsg_cb);
315 			return CS_SUCCEED;
316 		case CS_SERVERMSG_CB:
317 			*(void **) func = (CS_VOID *) (con ? con->_servermsg_cb : ctx->_servermsg_cb);
318 			return CS_SUCCEED;
319 		default:
320             _csclient_msg(ctx, "ct_callback", 2, 1, 16, 27, "%d", type);
321 			*(void **) func = NULL;
322 			return CS_SUCCEED;
323 		}
324 	}
325 	/* CS_SET */
326 	switch (type) {
327 	case CS_CLIENTMSG_CB:
328 		if (con)
329 			con->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
330 		else
331 			ctx->_clientmsg_cb = (CS_CLIENTMSG_FUNC) funcptr;
332 		break;
333 	case CS_SERVERMSG_CB:
334 		if (con)
335 			con->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
336 		else
337 			ctx->_servermsg_cb = (CS_SERVERMSG_FUNC) funcptr;
338 		break;
339 	}
340 	return CS_SUCCEED;
341 }
342 
343 CS_RETCODE
ct_con_props(CS_CONNECTION * con,CS_INT action,CS_INT property,CS_VOID * buffer,CS_INT buflen,CS_INT * out_len)344 ct_con_props(CS_CONNECTION * con, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
345 {
346 	CS_INT intval, maxcp;
347 	TDSSOCKET *tds;
348 	TDSLOGIN *tds_login;
349 
350 	tdsdump_log(TDS_DBG_FUNC, "ct_con_props(%p, %d, %d, %p, %d, %p)\n", con, action, property, buffer, buflen, out_len);
351 
352 	tdsdump_log(TDS_DBG_FUNC, "ct_con_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property);
353 
354 	tds = con->tds_socket;
355 	tds_login = con->tds_login;
356 
357 	if (action == CS_SET) {
358 		char *set_buffer = NULL;
359 
360 		if (property == CS_USERNAME || property == CS_PASSWORD || property == CS_APPNAME ||
361 			property == CS_HOSTNAME || property == CS_SERVERADDR) {
362 			if (buflen == CS_NULLTERM) {
363 				set_buffer = strdup((char *) buffer);
364 			} else if (buflen == CS_UNUSED) {
365 				return CS_SUCCEED;
366 			} else {
367 				set_buffer = (char *) malloc(buflen + 1);
368 				strncpy(set_buffer, (char *) buffer, buflen);
369 				set_buffer[buflen] = '\0';
370 			}
371 		}
372 
373 		/*
374 		 * XXX "login" properties shouldn't be set after
375 		 * login.  I don't know if it should fail silently
376 		 * or return an error.
377 		 */
378 		switch (property) {
379 		case CS_USERNAME:
380 			tds_set_user(tds_login, set_buffer);
381 			break;
382 		case CS_PASSWORD:
383 			tds_set_passwd(tds_login, set_buffer);
384 			break;
385 		case CS_APPNAME:
386 			tds_set_app(tds_login, set_buffer);
387 			break;
388 		case CS_HOSTNAME:
389 			tds_set_host(tds_login, set_buffer);
390 			break;
391 		case CS_PORT:
392 			tds_set_port(tds_login, *((int *) buffer));
393 			break;
394 		case CS_SERVERADDR: {
395 			/* Format of this property: "[hostname] [port]" */
396 			char *host, *port, *lasts = NULL;
397 			int portno;
398 			host= strtok_r(set_buffer, " ", &lasts);
399 			port= strtok_r(NULL, " ", &lasts);
400 			if (!host || !port) {
401 				free(set_buffer);
402 				return CS_FAIL;
403 			}
404 
405 			portno = (int)strtol(port, NULL, 10);
406 			if (portno < 1 || portno >= 65536) {
407 				free(set_buffer);
408 				return CS_FAIL;
409 			}
410 			con->server_addr = strdup(host);
411 			tds_set_port(tds_login, portno);
412 			break;
413 		}
414 		case CS_LOC_PROP:
415 			/* sybase docs say that this structure must be copied, not referenced */
416 			if (!buffer)
417 				return CS_FAIL;
418 
419 			if (con->locale)
420 				_cs_locale_free(con->locale);
421 			con->locale = _cs_locale_copy((CS_LOCALE *) buffer);
422 			if (!con->locale)
423 				return CS_FAIL;
424 			break;
425 		case CS_USERDATA:
426 			free(con->userdata);
427 			con->userdata = (void *) malloc(buflen + 1);
428 			tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, con->userdata);
429 			con->userdata_len = buflen;
430 			memcpy(con->userdata, buffer, buflen);
431 			break;
432 		case CS_BULK_LOGIN:
433 			memcpy(&intval, buffer, sizeof(intval));
434 			if (intval)
435 				tds_set_bulk(tds_login, 1);
436 			else
437 				tds_set_bulk(tds_login, 0);
438 			break;
439 		case CS_PACKETSIZE:
440 			memcpy(&intval, buffer, sizeof(intval));
441 			tds_set_packet(tds_login, (short) intval);
442 			break;
443 		case CS_TDS_VERSION:
444 			/*
445 			 * FIXME
446 			 * (a) We don't support all versions in tds/login.c -
447 			 *     I tried to pick reasonable versions.
448 			 * (b) Might need support outside of tds/login.c
449 			 * (c) It's a "negotiated" property so probably
450 			 *     needs tds_process_env_chg() support
451 			 * (d) Minor - we don't check against context
452 			 *     which should limit the acceptable values
453 			 */
454             if (*(int *) buffer == 0) {
455                 tds_set_version(tds_login, 0, 0);
456             } else if (*(int *) buffer == CS_TDS_40) {
457 				tds_set_version(tds_login, 4, 2);
458 			} else if (*(int *) buffer == CS_TDS_42) {
459 				tds_set_version(tds_login, 4, 2);
460 			} else if (*(int *) buffer == CS_TDS_46) {
461 				tds_set_version(tds_login, 4, 6);
462 			} else if (*(int *) buffer == CS_TDS_495) {
463 				tds_set_version(tds_login, 4, 6);
464 			} else if (*(int *) buffer == CS_TDS_50) {
465 				tds_set_version(tds_login, 5, 0);
466 			} else if (*(int *) buffer == CS_TDS_70) {
467 				tds_set_version(tds_login, 7, 0);
468 			} else if (*(int *) buffer == CS_TDS_71) {
469 				tds_set_version(tds_login, 7, 1);
470 			} else if (*(int *) buffer == CS_TDS_72) {
471 				tds_set_version(tds_login, 7, 2);
472 			} else if (*(int *) buffer == CS_TDS_73) {
473 				tds_set_version(tds_login, 7, 3);
474 			} else {
475 				return CS_FAIL;
476 			}
477 			break;
478 		default:
479 			tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
480 			break;
481 		}
482 		free(set_buffer);
483 	} else if (action == CS_GET) {
484 		DSTR *s;
485 
486 		switch (property) {
487 		case CS_USERNAME:
488 			s = &tds_login->user_name;
489 			goto str_copy;
490 		case CS_PASSWORD:
491 			s = &tds_login->password;
492 			goto str_copy;
493 		case CS_APPNAME:
494 			s = &tds_login->app_name;
495 			goto str_copy;
496 		case CS_HOSTNAME:
497 			s = &tds_login->client_host_name;
498 			goto str_copy;
499 		case CS_SERVERNAME:
500 			s = &tds_login->server_name;
501 		str_copy:
502 			if (out_len)
503 				*out_len = tds_dstr_len(s);
504 			tds_strlcpy((char *) buffer, tds_dstr_cstr(s), buflen);
505 			break;
506 		case CS_LOC_PROP:
507 			if (buflen != CS_UNUSED || !con->locale || !buffer)
508 				return CS_FAIL;
509 
510 			if (!_cs_locale_copy_inplace((CS_LOCALE *) buffer, con->locale))
511 				return CS_FAIL;
512 			break;
513 		case CS_USERDATA:
514 			tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", con->userdata);
515 			maxcp = con->userdata_len;
516 			if (out_len)
517 				*out_len = maxcp;
518 			if (maxcp > buflen)
519 				maxcp = buflen;
520 			memcpy(buffer, con->userdata, maxcp);
521 			break;
522 		case CS_CON_STATUS:
523 			intval = 0;
524 			if (!(IS_TDSDEAD(tds)))
525 				intval |= CS_CONSTAT_CONNECTED;
526 			if (tds && tds->state == TDS_DEAD)
527 				intval |= CS_CONSTAT_DEAD;
528 			memcpy(buffer, &intval, sizeof(intval));
529 			break;
530 		case CS_BULK_LOGIN:
531 			if (tds_login->bulk_copy)
532 				intval = CS_FALSE;
533 			else
534 				intval = CS_TRUE;
535 			memcpy(buffer, &intval, sizeof(intval));
536 			break;
537 		case CS_PACKETSIZE:
538 			if (tds)
539 				intval = tds->conn->env.block_size;
540 			else
541 				intval = tds_login->block_size;
542 			memcpy(buffer, &intval, sizeof(intval));
543 			if (out_len)
544 				*out_len = sizeof(intval);
545 			break;
546 		case CS_TDS_VERSION:
547 			switch (tds->conn->tds_version) {
548 			case 0x400:
549 				(*(int *) buffer = CS_TDS_40);
550 				break;
551 			case 0x402:
552 				(*(int *) buffer = CS_TDS_42);
553 				break;
554 			case 0x406:
555 				(*(int *) buffer = CS_TDS_46);
556 				break;
557 			case 0x400 + 95:
558 				(*(int *) buffer = CS_TDS_495);
559 				break;
560 			case 0x500:
561 				(*(int *) buffer = CS_TDS_50);
562 				break;
563 			case 0x700:
564 				(*(int *) buffer = CS_TDS_70);
565 				break;
566 			case 0x701:
567 				(*(int *) buffer = CS_TDS_71);
568 				break;
569 			case 0x702:
570 				(*(int *) buffer = CS_TDS_72);
571 				break;
572 			case 0x703:
573 				(*(int *) buffer = CS_TDS_73);
574 				break;
575 			default:
576 				return CS_FAIL;
577 			}
578 			break;
579 		case CS_PARENT_HANDLE:
580 			*(CS_CONTEXT **) buffer = con->ctx;
581 			break;
582 
583 		default:
584 			tdsdump_log(TDS_DBG_ERROR, "Unknown property %d\n", property);
585 			break;
586 		}
587 	}
588 	return CS_SUCCEED;
589 }
590 
591 CS_RETCODE
ct_connect(CS_CONNECTION * con,CS_CHAR * servername,CS_INT snamelen)592 ct_connect(CS_CONNECTION * con, CS_CHAR * servername, CS_INT snamelen)
593 {
594 	char *server;
595 	int needfree = 0;
596 	CS_CONTEXT *ctx;
597 	TDSLOGIN *login;
598 
599 	tdsdump_log(TDS_DBG_FUNC, "ct_connect(%p, %s, %d)\n", con, servername ? servername : "NULL", snamelen);
600 
601 	if (con->server_addr) {
602 		server = "";
603     } else if (servername == NULL || snamelen == 0 || snamelen == CS_UNUSED) {
604 		server = NULL;
605 	} else if (snamelen == CS_NULLTERM) {
606 		server = (char *) servername;
607 	} else {
608 		server = (char *) malloc(snamelen + 1);
609 		needfree++;
610 		strncpy(server, servername, snamelen);
611 		server[snamelen] = '\0';
612 	}
613 	tds_set_server(con->tds_login, server);
614 	if (needfree)
615 		free(server);
616 	ctx = con->ctx;
617 	if (!(con->tds_socket = tds_alloc_socket(ctx->tds_ctx, 512)))
618 		return CS_FAIL;
619 	tds_set_parent(con->tds_socket, (void *) con);
620 	if (!(login = tds_read_config_info(con->tds_socket, con->tds_login, ctx->tds_ctx->locale))) {
621 		tds_free_socket(con->tds_socket);
622 		con->tds_socket = NULL;
623 		return CS_FAIL;
624 	}
625 	if (con->server_addr)
626 		if (!tds_dstr_copy(&login->server_host_name, con->server_addr))
627 			goto Cleanup;
628 
629     /* Timeouts ... */
630     if (ctx->login_timeout > 0) {
631         login->connect_timeout = ctx->login_timeout;
632     }
633 
634     if (ctx->query_timeout > 0) {
635         login->query_timeout = ctx->query_timeout;
636     }
637 
638 	/* override locale settings with CS_CONNECTION settings, if any */
639 	if (con->locale) {
640 		if (con->locale->charset) {
641             if (!tds_dstr_copy(&login->server_charset, con->locale->charset)
642                 ||  !tds_dstr_copy(&login->client_charset, con->locale->charset))
643 				goto Cleanup;
644 		}
645 		if (con->locale->language) {
646 			if (!tds_dstr_copy(&login->language, con->locale->language))
647 				goto Cleanup;
648 		}
649 		if (con->locale->time && tds_get_ctx(con->tds_socket)) {
650 			TDSLOCALE *locale = tds_get_ctx(con->tds_socket)->locale;
651 			free(locale->date_fmt);
652 			/* TODO convert format from CTLib to libTDS */
653 			locale->date_fmt = strdup(con->locale->time);
654 			if (!locale->date_fmt)
655 				goto Cleanup;
656 		}
657 		/* TODO how to handle this?
658 		if (con->locale->collate) {
659 		}
660 		*/
661 	}
662 
663 	if (TDS_FAILED(tds_connect_and_login(con->tds_socket, login)))
664 		goto Cleanup;
665 
666 	tds_free_login(login);
667 
668 	tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_SUCCEED);
669 	return CS_SUCCEED;
670 
671 Cleanup:
672 	tds_free_socket(con->tds_socket);
673 	con->tds_socket = NULL;
674 	tds_free_login(login);
675 	tdsdump_log(TDS_DBG_FUNC, "leaving ct_connect() returning %d\n", CS_FAIL);
676 	return CS_FAIL;
677 }
678 
679 CS_RETCODE
ct_cmd_alloc(CS_CONNECTION * con,CS_COMMAND ** cmd)680 ct_cmd_alloc(CS_CONNECTION * con, CS_COMMAND ** cmd)
681 {
682 	CS_COMMAND_LIST *command_list;
683 	CS_COMMAND_LIST *pcommand;
684 
685 	tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc(%p, %p)\n", con, cmd);
686 
687 	*cmd = (CS_COMMAND *) calloc(1, sizeof(CS_COMMAND));
688 	if (!*cmd)
689 		return CS_FAIL;
690 
691 	/* so we know who we belong to */
692 	(*cmd)->con = con;
693 
694 	/* initialise command state */
695 	ct_set_command_state(*cmd, _CS_COMMAND_IDLE);
696 
697 	command_list = (CS_COMMAND_LIST*) calloc(1, sizeof(CS_COMMAND_LIST));
698 	command_list->cmd = *cmd;
699 	command_list->next = NULL;
700 
701 	if ( con->cmds == NULL ) {
702 		tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc() : allocating command list to head\n");
703 		con->cmds = command_list;
704 	} else {
705 		pcommand = con->cmds;
706 		for (;;) {
707 			tdsdump_log(TDS_DBG_FUNC, "ct_cmd_alloc() : stepping thru existing commands\n");
708 			if (pcommand->next == NULL)
709 				break;
710 			pcommand = pcommand->next;
711 		}
712 		pcommand->next = command_list;
713 	}
714 
715 	return CS_SUCCEED;
716 }
717 
718 CS_RETCODE
ct_command(CS_COMMAND * cmd,CS_INT type,const CS_VOID * buffer,CS_INT buflen,CS_INT option)719 ct_command(CS_COMMAND * cmd, CS_INT type, const CS_VOID * buffer, CS_INT buflen, CS_INT option)
720 {
721     ssize_t query_len, current_query_len;
722 
723 	tdsdump_log(TDS_DBG_FUNC, "ct_command(%p, %d, %p, %d, %d)\n", cmd, type, buffer, buflen, option);
724 
725 	/*
726 	 * Unless we are in the process of building a CS_LANG_CMD command,
727 	 * clear everything, ready to start anew
728 	 */
729 	if (cmd->command_state != _CS_COMMAND_BUILDING) {
730 		_ct_initialise_cmd(cmd);
731 		ct_set_command_state(cmd, _CS_COMMAND_IDLE);
732 	}
733 
734 	switch (type) {
735 	case CS_LANG_CMD:
736 		switch (option) {
737 		case CS_MORE:	/* The text in buffer is only part of the language command to be executed. */
738 		case CS_END:	/* The text in buffer is the last part of the language command to be executed. */
739 		case CS_UNUSED:	/* Equivalent to CS_END. */
740 			if (buflen == CS_NULLTERM) {
741 				query_len = strlen((const char *) buffer);
742 			} else {
743 				query_len = buflen;
744 			}
745 			/* small fix for no crash */
746 			if (query_len == CS_UNUSED) {
747 				cmd->query = NULL;
748 				return CS_FAIL;
749 			}
750 			switch (cmd->command_state) {
751 			case _CS_COMMAND_IDLE:
752 				cmd->query = malloc(query_len + 1);
753 				strncpy(cmd->query, (const char *) buffer, query_len);
754 				cmd->query[query_len] = '\0';
755 				if (option == CS_MORE) {
756 					ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
757 				} else {
758 					ct_set_command_state(cmd, _CS_COMMAND_READY);
759 				}
760 				break;
761 			case _CS_COMMAND_BUILDING:
762 				current_query_len = strlen(cmd->query);
763 				cmd->query = realloc(cmd->query, current_query_len + query_len + 1);
764 				strncat(cmd->query, (const char *) buffer, query_len);
765 				cmd->query[current_query_len + query_len] = '\0';
766 				if (option == CS_MORE) {
767 					ct_set_command_state(cmd, _CS_COMMAND_BUILDING);
768 				} else {
769 					ct_set_command_state(cmd, _CS_COMMAND_READY);
770 				}
771 				break;
772 			}
773 			break;
774 		default:
775 			return CS_FAIL;
776 		}
777 		break;
778 
779 	case CS_RPC_CMD:
780 		/* Code changed for RPC functionality -SUHA */
781 		/* RPC code changes starts here */
782 		if (cmd == NULL)
783 			return CS_FAIL;
784 
785 		cmd->rpc = (CSREMOTE_PROC *) calloc(1, sizeof(CSREMOTE_PROC));
786 		if (cmd->rpc == NULL)
787 			return CS_FAIL;
788 
789 		if (buflen == CS_NULLTERM) {
790 			cmd->rpc->name = strdup((const char*) buffer);
791 			if (cmd->rpc->name == NULL)
792 				return CS_FAIL;
793 		} else if (buflen > 0) {
794 			cmd->rpc->name = calloc(1, buflen + 1);
795 			if (cmd->rpc->name == NULL)
796 				return CS_FAIL;
797 			strncpy(cmd->rpc->name, (const char *) buffer, buflen);
798 		} else {
799 			return CS_FAIL;
800 		}
801 
802 		cmd->rpc->param_list = NULL;
803 
804 		tdsdump_log(TDS_DBG_INFO1, "ct_command() added rpcname \"%s\"\n", cmd->rpc->name);
805 
806 		/* FIXME: I don't know the value for RECOMPILE, NORECOMPILE options. Hence assigning zero  */
807 		switch (option) {
808 		case CS_RECOMPILE:	/* Recompile the stored procedure before executing it. */
809 			cmd->rpc->options = 0;
810 			break;
811 		case CS_NO_RECOMPILE:	/* Do not recompile the stored procedure before executing it. */
812 			cmd->rpc->options = 0;
813 			break;
814 		case CS_UNUSED:	/* Equivalent to CS_NO_RECOMPILE. */
815 			cmd->rpc->options = 0;
816 			break;
817 		default:
818 			return CS_FAIL;
819 		}
820 		ct_set_command_state(cmd, _CS_COMMAND_READY);
821 		break;
822 		/* RPC code changes ends here */
823 
824 	case CS_SEND_DATA_CMD:
825 		switch (option) {
826 		case CS_COLUMN_DATA:	/* The data will be used for a text or image column update. */
827 			cmd->send_data_started = 0;
828 			break;
829 		case CS_BULK_DATA:	/* For internal Sybase use only. The data will be used for a bulk copy operation. */
830 		default:
831 			return CS_FAIL;
832 		}
833 		ct_set_command_state(cmd, _CS_COMMAND_READY);
834 		break;
835 
836 	case CS_SEND_BULK_CMD:
837 		switch (option) {
838 		case CS_BULK_INIT:	/* For internal Sybase use only. Initialize a bulk copy operation. */
839 		case CS_BULK_CONT:	/* For internal Sybase use only. Continue a bulk copy operation. */
840 		default:
841 			return CS_FAIL;
842 		}
843 		ct_set_command_state(cmd, _CS_COMMAND_READY);
844 		break;
845 
846 	default:
847 		return CS_FAIL;
848 	}
849 
850 	cmd->command_type = type;
851 
852 
853 	return CS_SUCCEED;
854 }
855 
856 static void
_ct_initialise_cmd(CS_COMMAND * cmd)857 _ct_initialise_cmd(CS_COMMAND *cmd)
858 {
859 	free(cmd->query);
860 	cmd->query = NULL;
861 
862 	tdsdump_log(TDS_DBG_FUNC, "_ct_initialise_cmd(%p)\n", cmd);
863 
864 	if (cmd->input_params) {
865 		param_clear(cmd->input_params);
866 		cmd->input_params = NULL;
867 	}
868 	ct_set_command_state(cmd, _CS_COMMAND_IDLE);
869 
870 	rpc_clear(cmd->rpc);
871 	cmd->rpc = NULL;
872 }
873 
874 CS_RETCODE
ct_send(CS_COMMAND * cmd)875 ct_send(CS_COMMAND * cmd)
876 {
877 	TDSSOCKET *tds;
878     TDSRET ret = TDS_FAIL;
879 	TDSPARAMINFO *pparam_info;
880 
881 	tdsdump_log(TDS_DBG_FUNC, "ct_send(%p)\n", cmd);
882 
883 	tdsdump_log(TDS_DBG_FUNC, "ct_send() command_type = %d\n", cmd->command_type);
884 
885 	if (!cmd->con || !cmd->con->tds_socket)
886 		return CS_FAIL;
887 
888 	tds = cmd->con->tds_socket;
889 
890 	if (cmd->cancel_state == _CS_CANCEL_PENDING) {
891 		_ct_cancel_cleanup(cmd);
892 		return CS_CANCELED;
893 	}
894 
895 	if (cmd->command_state == _CS_COMMAND_IDLE) {
896 		tdsdump_log(TDS_DBG_FUNC, "ct_send() command_state = IDLE\n");
897 		_ctclient_msg(cmd->con, "ct_send", 1, 1, 1, 16843163, "");
898 		return CS_FAIL;
899 	}
900 
901 	cmd->results_state = _CS_RES_NONE;
902 
903 	if (cmd->command_type == CS_DYNAMIC_CMD) {
904 		CS_DYNAMIC *dyn = cmd->dyn;
905 		TDSDYNAMIC *tdsdyn;
906 
907 		if (dyn == NULL)
908 			return CS_FAIL;
909 
910 		switch (cmd->dynamic_cmd) {
911 		case CS_PREPARE:
912 			if (TDS_FAILED(tds_submit_prepare(tds, dyn->stmt, dyn->id, &dyn->tdsdyn, NULL)))
913 				return CS_FAIL;
914 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
915 			return CS_SUCCEED;
916 			break;
917 		case CS_EXECUTE:
918 			pparam_info = paraminfoalloc(tds, dyn->param_list);
919 			tdsdyn = dyn->tdsdyn;
920 			if (!tdsdyn) {
921 				tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_EXECUTE) no tdsdyn!\n");
922 				return CS_FAIL;
923 			}
924 			tds_free_input_params(tdsdyn);
925 			tdsdyn->params = pparam_info;
926 			if (TDS_FAILED(tds_submit_execute(tds, tdsdyn)))
927 				return CS_FAIL;
928 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
929 			return CS_SUCCEED;
930 			break;
931 		case CS_DESCRIBE_INPUT:
932 			tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_INPUT)\n");
933 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
934 			cmd->results_state = _CS_RES_DESCRIBE_RESULT;
935 			if (tds->cur_dyn)
936 				tds_set_current_results(tds, tds->cur_dyn->res_info);
937 			else
938 				tds_set_current_results(tds, tds->param_info);
939 			break;
940 
941 		case CS_DESCRIBE_OUTPUT:
942 			tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DESCRIBE_OUTPUT)\n");
943 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
944 			cmd->results_state = _CS_RES_DESCRIBE_RESULT;
945 			tds_set_current_results(tds, tds->res_info);
946 			break;
947 
948 		case CS_DEALLOC:
949 			tdsdyn = dyn->tdsdyn;
950 			if (!tdsdyn) {
951 				tdsdump_log(TDS_DBG_INFO1, "ct_send(CS_DEALLOC) no tdsdyn!\n");
952 				return CS_FAIL;
953 			}
954 			if (TDS_FAILED(tds_submit_unprepare(tds, tdsdyn)))
955 				return CS_FAIL;
956 
957 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
958 			return CS_SUCCEED;
959 			break;
960 
961 		default:
962 			return CS_FAIL;
963 		}
964 	}
965 
966 	if (cmd->command_type == CS_RPC_CMD) {
967 		CSREMOTE_PROC *rpc;
968 
969 		/* sanity */
970 		if (cmd == NULL || (rpc=cmd->rpc) == NULL	/* ct_command should allocate pointer */
971 		    || rpc->name == NULL) {	/* can't be ready without a name      */
972 			return CS_FAIL;
973 		}
974 
975 		pparam_info = paraminfoalloc(tds, rpc->param_list);
976 		ret = tds_submit_rpc(tds, rpc->name, pparam_info, NULL);
977 
978 		tds_free_param_results(pparam_info);
979 
980 		ct_set_command_state(cmd, _CS_COMMAND_SENT);
981 
982 		if (TDS_FAILED(ret))
983 			return CS_FAIL;
984 
985 		return CS_SUCCEED;
986 	}
987 
988 	/* RPC Code changes ends here */
989 
990 	if (cmd->command_type == CS_LANG_CMD) {
991 		ret = TDS_FAIL;
992 		if (cmd->input_params) {
993 			pparam_info = paraminfoalloc(tds, cmd->input_params);
994 			ret = tds_submit_query_params(tds, cmd->query, pparam_info, NULL);
995 			tds_free_param_results(pparam_info);
996 		} else {
997 			ret = tds_submit_query(tds, cmd->query);
998 		}
999 
1000 		ct_set_command_state(cmd, _CS_COMMAND_SENT);
1001 
1002 		if (TDS_FAILED(ret)) {
1003 			tdsdump_log(TDS_DBG_WARN, "ct_send() failed\n");
1004 			return CS_FAIL;
1005 		}
1006 		tdsdump_log(TDS_DBG_INFO2, "ct_send() succeeded\n");
1007 		return CS_SUCCEED;
1008 	}
1009 
1010 	/* Code added for CURSOR support */
1011 
1012 	if (cmd->command_type == CS_CUR_CMD) {
1013 		TDSCURSOR *cursor;
1014 
1015 		/* sanity */
1016 		/*
1017 		 * ct_cursor declare should allocate cursor pointer
1018 		 * cursor stmt cannot be NULL
1019 		 * cursor name cannot be NULL
1020 		 */
1021 
1022 		int something_to_send = 0;
1023 
1024 		tdsdump_log(TDS_DBG_FUNC, "ct_send() : CS_CUR_CMD\n");
1025 
1026 		cursor = cmd->cursor;
1027 		if (!cursor) {
1028 			tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor not present\n");
1029 			return CS_FAIL;
1030 		}
1031 
1032 		if (cmd == NULL ) {
1033 			tdsdump_log(TDS_DBG_FUNC, "ct_send() : cmd is null\n");
1034 			return CS_FAIL;
1035 		}
1036 		if (cursor->query == NULL ) {
1037 			tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->query is null\n");
1038 			return CS_FAIL;
1039 		}
1040 		if ( cursor->cursor_name == NULL ) {
1041 			tdsdump_log(TDS_DBG_FUNC, "ct_send() : cursor->name is null\n");
1042 			return CS_FAIL;
1043 		}
1044 
1045 		if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED) {
1046 			ret =  tds_cursor_declare(tds, cursor, NULL, &something_to_send);
1047 			if (TDS_SUCCEED(ret)){
1048 				cursor->status.declare = _CS_CURS_TYPE_SENT; /* Cursor is declared */
1049 				if (something_to_send == 0) {
1050 					cmd->results_state = _CS_RES_END_RESULTS;
1051 				}
1052 			}
1053 			else {
1054 				tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor declare failed \n");
1055 				return CS_FAIL;
1056 			}
1057 		}
1058 
1059 		if (cursor->status.cursor_row == _CS_CURS_TYPE_REQUESTED &&
1060 			cursor->status.declare == _CS_CURS_TYPE_SENT) {
1061 
1062  			ret = tds_cursor_setrows(tds, cursor, &something_to_send);
1063 			if (TDS_SUCCEED(ret)){
1064 				cursor->status.cursor_row = _CS_CURS_TYPE_SENT; /* Cursor rows set */
1065 				if (something_to_send == 0) {
1066 					cmd->results_state = _CS_RES_END_RESULTS;
1067 				}
1068 			}
1069 			else {
1070 				tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor set rows failed\n");
1071 				return CS_FAIL;
1072 			}
1073 		}
1074 
1075 		if (cursor->status.open == _CS_CURS_TYPE_REQUESTED &&
1076 			cursor->status.declare == _CS_CURS_TYPE_SENT) {
1077 
1078 			ret = tds_cursor_open(tds, cursor, NULL, &something_to_send);
1079  			if (TDS_SUCCEED(ret)){
1080 				cursor->status.open = _CS_CURS_TYPE_SENT;
1081 				cmd->results_state = _CS_RES_INIT;
1082 			}
1083 			else {
1084 				tdsdump_log(TDS_DBG_WARN, "ct_send(): cursor open failed\n");
1085 				return CS_FAIL;
1086 			}
1087 		}
1088 
1089 		if (something_to_send) {
1090 			tdsdump_log(TDS_DBG_WARN, "ct_send(): sending cursor commands\n");
1091 			tds_flush_packet(tds);
1092 			tds_set_state(tds, TDS_PENDING);
1093 			something_to_send = 0;
1094 
1095 			ct_set_command_state(cmd, _CS_COMMAND_SENT);
1096 
1097 			return CS_SUCCEED;
1098 		}
1099 
1100 		if (cursor->status.close == _CS_CURS_TYPE_REQUESTED){
1101 			if (cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
1102 				/* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
1103 				ret = tds_cursor_close(tds, cursor);
1104 				tds_release_cursor(&cmd->cursor);
1105 				cursor = NULL;
1106 			} else {
1107 				ret = tds_cursor_close(tds, cursor);
1108 				cursor->status.close = _CS_CURS_TYPE_SENT;
1109 			}
1110 		}
1111 
1112 		if (cursor && cursor->status.dealloc == _CS_CURS_TYPE_REQUESTED) {
1113 			/* FIXME what happen if tds_cursor_dealloc return TDS_FAIL ?? */
1114 			ret = tds_cursor_dealloc(tds, cursor);
1115 			tds_release_cursor(&cmd->cursor);
1116 			tds_free_all_results(tds);
1117 		}
1118 
1119 		if (TDS_SUCCEED(ret))
1120 			cmd->results_state = _CS_RES_INIT;
1121 
1122 		ct_set_command_state(cmd, _CS_COMMAND_SENT);
1123 		return CS_SUCCEED;
1124 	}
1125 
1126 	if (cmd->command_type == CS_SEND_DATA_CMD) {
1127 		tds_writetext_end(tds);
1128 		ct_set_command_state(cmd, _CS_COMMAND_SENT);
1129 	}
1130 
1131 	return CS_SUCCEED;
1132 }
1133 
1134 
1135 CS_RETCODE
ct_results(CS_COMMAND * cmd,CS_INT * result_type)1136 ct_results(CS_COMMAND * cmd, CS_INT * result_type)
1137 {
1138 	TDSSOCKET *tds;
1139 	CS_CONTEXT *context;
1140 	TDSRET tdsret;
1141 	CS_INT res_type;
1142 	CS_INT done_flags;
1143 	TDS_INT8 rows_affected;
1144 
1145 	tdsdump_log(TDS_DBG_FUNC, "ct_results(%p, %p)\n", cmd, result_type);
1146 
1147 	if (cmd->cancel_state == _CS_CANCEL_PENDING) {
1148 		_ct_cancel_cleanup(cmd);
1149 		return CS_CANCELED;
1150 	}
1151 
1152 	if (!cmd->con || !cmd->con->tds_socket)
1153 		return CS_FAIL;
1154 
1155 	cmd->bind_count = CS_UNUSED;
1156 
1157 	context = cmd->con->ctx;
1158 
1159 	tds = cmd->con->tds_socket;
1160 	cmd->row_prefetched = 0;
1161 
1162 	/*
1163 	 * depending on the current results state, we may
1164 	 * not need to call tds_process_tokens...
1165 	 */
1166 
1167 	switch (cmd->results_state) {
1168 	case _CS_RES_CMD_SUCCEED:
1169 		*result_type = CS_CMD_SUCCEED;
1170 		cmd->results_state = _CS_RES_CMD_DONE;
1171 		return CS_SUCCEED;
1172 	case _CS_RES_CMD_DONE:
1173 		*result_type = CS_CMD_DONE;
1174 		cmd->results_state = _CS_RES_INIT;
1175 		return CS_SUCCEED;
1176 	case _CS_RES_END_RESULTS:
1177 		*result_type = CS_CMD_DONE;
1178 		cmd->results_state = _CS_RES_INIT;
1179 		return CS_END_RESULTS;
1180 	case _CS_RES_DESCRIBE_RESULT:
1181 		*result_type = CS_DESCRIBE_RESULT;
1182 		cmd->results_state = _CS_RES_CMD_DONE;
1183 		return CS_SUCCEED;
1184 	case _CS_RES_NONE:				/* first time in after ct_send */
1185 		cmd->results_state = _CS_RES_INIT;
1186 		tds->rows_affected = TDS_NO_COUNT;
1187 		break;
1188 	case _CS_RES_INIT:
1189 		tds->rows_affected = TDS_NO_COUNT;
1190 		break;
1191 	default:
1192 		break;
1193 	}
1194 
1195 	rows_affected = tds->rows_affected;
1196 
1197 	/*
1198 	 * see what "result" tokens we have. a "result" in ct-lib terms also
1199 	 * includes row data. Some result types always get reported back  to
1200 	 * the calling program, others are only reported back if the relevant
1201 	 * config flag is set.
1202 	 */
1203 
1204 	for (;;) {
1205 
1206 		tdsret = tds_process_tokens(tds, &res_type, &done_flags, TDS_TOKEN_RESULTS);
1207 
1208 		tdsdump_log(TDS_DBG_FUNC, "ct_results() process_result_tokens returned %d (type %d) \n",
1209 			    tdsret, res_type);
1210 
1211 		switch (tdsret) {
1212 
1213 		case TDS_SUCCESS:
1214 
1215 			cmd->curr_result_type = res_type;
1216 
1217 			switch (res_type) {
1218 
1219 			case CS_COMPUTEFMT_RESULT:
1220 
1221 				/*
1222 				 * set results state to indicate that we
1223 				 * have a result set (empty for the moment)
1224 				 * If the CS_EXPOSE_FMTS  property has been
1225 				 * set in ct_config(), we need to return an
1226 				 * appropraite format result, otherwise just
1227 				 * carry on and get the next token.....
1228 				 */
1229 
1230 				cmd->results_state = _CS_RES_RESULTSET_EMPTY;
1231 
1232 				if (context->config.cs_expose_formats) {
1233 					*result_type = res_type;
1234 					return CS_SUCCEED;
1235 				}
1236 				break;
1237 
1238 			case CS_ROWFMT_RESULT:
1239 				if (cmd->command_type == CS_CUR_CMD ||
1240 				    cmd->command_type == CS_DYNAMIC_CMD)
1241 					break;
1242 
1243 			case CS_ROW_RESULT:
1244 
1245 				/*
1246 				 * we've hit a data row. pass back that fact
1247 				 * to the calling program. set results state
1248 				 * to show that the result set has rows...
1249 				 */
1250 
1251 				cmd->results_state = _CS_RES_RESULTSET_ROWS;
1252 				if (cmd->command_type == CS_CUR_CMD) {
1253 					*result_type = CS_CURSOR_RESULT;
1254 				} else {
1255 					*result_type = CS_ROW_RESULT;
1256 				}
1257 				return CS_SUCCEED;
1258 				break;
1259 
1260 			case CS_COMPUTE_RESULT:
1261 
1262 				/*
1263 				 * we've hit a compute data row. We have to get hold of this
1264 				 * data now, as it's necessary  to tie this data back to its
1265 				 * result format...the user may call ct_res_info() & friends
1266 				 * after getting back a compute "result".
1267 				 *
1268 				 * but first, if we've hit this compute row without having
1269 				 * hit a data row first, we need to return a  CS_ROW_RESULT
1270 				 * before letting them have the compute row...
1271 				 */
1272 
1273 				if (cmd->results_state == _CS_RES_RESULTSET_EMPTY) {
1274 					*result_type = CS_ROW_RESULT;
1275 					tds_set_current_results(tds, tds->res_info);
1276 					cmd->results_state = _CS_RES_RESULTSET_ROWS;
1277 					return CS_SUCCEED;
1278 				}
1279 
1280 				tdsret = tds_process_tokens(tds, &res_type, NULL,
1281 							 TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
1282 
1283 				/* set results state to show that the result set has rows... */
1284 
1285 				cmd->results_state = _CS_RES_RESULTSET_ROWS;
1286 
1287 				*result_type = res_type;
1288 				if (tdsret == TDS_SUCCESS && (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT)) {
1289 					if (res_type == TDS_COMPUTE_RESULT) {
1290 						cmd->row_prefetched = 1;
1291 						return CS_SUCCEED;
1292 					} else {
1293 						/* this couldn't really happen, but... */
1294 						return CS_FAIL;
1295 					}
1296 				} else
1297 					return CS_FAIL;
1298 				break;
1299 
1300 			case TDS_DONE_RESULT:
1301 
1302 				/*
1303 				 * A done token signifies the end of a logical
1304 				 * command. There are three possibilities...
1305 				 * 1. Simple command with no result set, i.e.
1306 				 *    update, delete, insert
1307 				 * 2. Command with result set but no rows
1308 				 * 3. Command with result set and rows
1309 				 * in these cases we need to:
1310 				 * 1. return CS_CMD_FAIL/SUCCED depending on
1311 				 *    the status returned in done_flags
1312 				 * 2. "manufacture" a CS_ROW_RESULT return,
1313 				 *    and set the results state to DONE
1314 				 * 3. return with CS_CMD_DONE and reset the
1315 				 *    results_state
1316 				 */
1317 
1318 				tdsdump_log(TDS_DBG_FUNC, "ct_results() results state = %d\n",cmd->results_state);
1319 				tdsdump_log(TDS_DBG_FUNC, "ct_results() command type  = %d\n",cmd->command_type);
1320 				tdsdump_log(TDS_DBG_FUNC, "ct_results() dynamic cmd   = %d\n",cmd->dynamic_cmd);
1321 
1322 				if ((cmd->command_type == CS_DYNAMIC_CMD) &&
1323 					(cmd->dynamic_cmd == CS_PREPARE || cmd->dynamic_cmd == CS_DEALLOC)) {
1324 					*result_type = CS_CMD_SUCCEED;
1325 					cmd->results_state = _CS_RES_CMD_DONE;
1326 					return CS_SUCCEED;
1327 				}
1328 
1329 				if (tds->rows_affected != TDS_NO_COUNT)
1330 					rows_affected = tds->rows_affected;
1331 				tds->rows_affected = rows_affected;
1332 
1333 				switch (cmd->results_state) {
1334 
1335 				case _CS_RES_INIT:
1336 				case _CS_RES_STATUS:
1337 					if (done_flags & TDS_DONE_ERROR)
1338 						*result_type = CS_CMD_FAIL;
1339 					else
1340 						*result_type = CS_CMD_SUCCEED;
1341 					cmd->results_state = _CS_RES_CMD_DONE;
1342 					break;
1343 
1344 				case _CS_RES_RESULTSET_EMPTY:
1345 					if (cmd->command_type == CS_CUR_CMD) {
1346 						*result_type = CS_CURSOR_RESULT;
1347 						cmd->results_state = _CS_RES_RESULTSET_ROWS;
1348 					} else {
1349 						*result_type = CS_ROW_RESULT;
1350 						cmd->results_state = _CS_RES_CMD_DONE;
1351 					}
1352 					break;
1353 
1354 				case _CS_RES_RESULTSET_ROWS:
1355 					*result_type = CS_CMD_DONE;
1356 					cmd->results_state = _CS_RES_INIT;
1357 					break;
1358 
1359 				}
1360 				return CS_SUCCEED;
1361 				break;
1362 
1363 			case TDS_DONEINPROC_RESULT:
1364 
1365 				/*
1366 				 * A doneinproc token may signify the end of a
1367 				 * logical command if the command had a result
1368 				 * set. Otherwise it is ignored....
1369 				 */
1370 
1371 				if (tds->rows_affected != TDS_NO_COUNT)
1372 					rows_affected = tds->rows_affected;
1373 				tds->rows_affected = rows_affected;
1374 
1375 				switch (cmd->results_state) {
1376 				case _CS_RES_INIT:   /* command had no result set */
1377 					break;
1378 				case _CS_RES_RESULTSET_EMPTY:
1379 					if (cmd->command_type == CS_CUR_CMD) {
1380 						*result_type = CS_CURSOR_RESULT;
1381 					} else {
1382 						*result_type = CS_ROW_RESULT;
1383 					}
1384 					cmd->results_state = _CS_RES_CMD_DONE;
1385 					return CS_SUCCEED;
1386 					break;
1387 				case _CS_RES_RESULTSET_ROWS:
1388 					*result_type = CS_CMD_DONE;
1389 					cmd->results_state = _CS_RES_INIT;
1390 					return CS_SUCCEED;
1391 					break;
1392 				}
1393 				break;
1394 
1395 			case TDS_DONEPROC_RESULT:
1396 
1397 				/*
1398 				 * A DONEPROC result means the end of a logical
1399 				 * command only if it was one of the commands
1400 				 * directly sent from ct_send, not as a result
1401 				 * of a nested stored procedure call. We know
1402 				 * if this is the case if a STATUS_RESULT was
1403 				 * received immediately prior to the DONE_PROC
1404 				 */
1405 
1406 				if (tds->rows_affected != TDS_NO_COUNT)
1407 					rows_affected = tds->rows_affected;
1408 				tds->rows_affected = rows_affected;
1409 
1410 				if (done_flags & TDS_DONE_ERROR)
1411 					*result_type = CS_CMD_FAIL;
1412 				else
1413 					*result_type = CS_CMD_SUCCEED;
1414 				cmd->results_state = _CS_RES_CMD_DONE;
1415 				return CS_SUCCEED;
1416 				break;
1417 
1418 			case TDS_PARAM_RESULT:
1419 				cmd->row_prefetched = 1;
1420 				*result_type = res_type;
1421 				return CS_SUCCEED;
1422 				break;
1423 
1424 			case TDS_STATUS_RESULT:
1425 				_ct_process_return_status(tds);
1426 				cmd->row_prefetched = 1;
1427 				*result_type = res_type;
1428 				cmd->results_state = _CS_RES_STATUS;
1429 				return CS_SUCCEED;
1430 				break;
1431 
1432 			case TDS_DESCRIBE_RESULT:
1433 				if (cmd->dynamic_cmd == CS_DESCRIBE_INPUT ||
1434 					cmd->dynamic_cmd == CS_DESCRIBE_OUTPUT) {
1435 					*result_type = res_type;
1436 					return CS_SUCCEED;
1437 				}
1438 				break;
1439 			default:
1440 				*result_type = res_type;
1441 				return CS_SUCCEED;
1442 				break;
1443 			}
1444 
1445 			break;
1446 
1447 		case TDS_NO_MORE_RESULTS:
1448 
1449 			/* some commands can be re-sent once completed */
1450 			/* so mark the command state as 'ready'...     */
1451 
1452 			if (cmd->command_type == CS_LANG_CMD ||
1453 				cmd->command_type == CS_RPC_CMD ||
1454 				cmd->command_type == CS_CUR_CMD ||
1455 				cmd->command_type == CS_DYNAMIC_CMD) {
1456 				ct_set_command_state(cmd, _CS_COMMAND_READY);
1457 			}
1458 			/* if we have just completed processing a dynamic deallocate */
1459 			/* get rid of our dynamic statement structure...             */
1460 
1461 			if (cmd->command_type == CS_DYNAMIC_CMD &&
1462 				cmd->dynamic_cmd  == CS_DEALLOC) {
1463 				_ct_deallocate_dynamic(cmd->con, cmd->dyn);
1464 				cmd->dyn = NULL;
1465 			}
1466 			return CS_END_RESULTS;
1467 			break;
1468 
1469 		case TDS_CANCELLED:
1470 			cmd->cancel_state = _CS_CANCEL_NOCANCEL;
1471 			return CS_CANCELED;
1472 			break;
1473 
1474 		default:
1475 			return CS_FAIL;
1476 			break;
1477 
1478 		}  /* switch (tdsret) */
1479 	}      /* for (;;)        */
1480 }
1481 
1482 
1483 CS_RETCODE
ct_bind(CS_COMMAND * cmd,CS_INT item,CS_DATAFMT * datafmt,CS_VOID * buffer,CS_INT * copied,CS_SMALLINT * indicator)1484 ct_bind(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt, CS_VOID * buffer, CS_INT * copied, CS_SMALLINT * indicator)
1485 {
1486 	TDSCOLUMN *colinfo;
1487 	TDSRESULTINFO *resinfo;
1488 	TDSSOCKET *tds;
1489 	CS_CONNECTION *con = cmd->con;
1490 	CS_INT bind_count;
1491 
1492 	tdsdump_log(TDS_DBG_FUNC, "ct_bind(%p, %d, %p, %p, %p, %p)\n", cmd, item, datafmt, buffer, copied, indicator);
1493 
1494 	tdsdump_log(TDS_DBG_FUNC, "ct_bind() datafmt count = %d column_number = %d\n", datafmt->count, item);
1495 
1496 	if (!con || !con->tds_socket)
1497 		return CS_FAIL;
1498 
1499 	tds = con->tds_socket;
1500 	resinfo = tds->current_results;
1501 
1502 	/* check item value */
1503 	if (!resinfo || item <= 0 || item > resinfo->num_cols)
1504 		return CS_FAIL;
1505 
1506 	colinfo = resinfo->columns[item - 1];
1507 
1508 	/*
1509 	 * Check whether the request is for array binding, and ensure that the user
1510 	 * supplies the same datafmt->count to the subsequent ct_bind calls
1511 	 */
1512 
1513 	bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
1514 
1515 	/* first bind for this result set */
1516 
1517 	if (cmd->bind_count == CS_UNUSED) {
1518 		cmd->bind_count = bind_count;
1519 	} else {
1520 		/* all subsequent binds for this result set - the bind counts must be the same */
1521 		if (cmd->bind_count != bind_count) {
1522 			_ctclient_msg(con, "ct_bind", 1, 1, 1, 137, "%d, %d", bind_count, cmd->bind_count);
1523 			return CS_FAIL;
1524 		}
1525 	}
1526 
1527 	/* bind the column_varaddr to the address of the buffer */
1528 
1529 	colinfo = resinfo->columns[item - 1];
1530 	colinfo->column_varaddr = (char *) buffer;
1531 	colinfo->column_bindtype = datafmt->datatype;
1532 	colinfo->column_bindfmt = datafmt->format;
1533 	colinfo->column_bindlen = datafmt->maxlength;
1534 	if (indicator) {
1535 		colinfo->column_nullbind = indicator;
1536 	}
1537 	if (copied) {
1538 		colinfo->column_lenbind = copied;
1539 	}
1540 	return CS_SUCCEED;
1541 }
1542 
1543 CS_RETCODE
ct_fetch(CS_COMMAND * cmd,CS_INT type,CS_INT offset,CS_INT option,CS_INT * prows_read)1544 ct_fetch(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * prows_read)
1545 {
1546 	TDS_INT ret_type;
1547 	TDSRET ret;
1548 	TDS_INT marker;
1549 	TDS_INT temp_count;
1550 	TDSSOCKET *tds;
1551 	CS_INT rows_read_dummy;
1552 
1553 	tdsdump_log(TDS_DBG_FUNC, "ct_fetch(%p, %d, %d, %d, %p)\n", cmd, type, offset, option, prows_read);
1554 
1555 	if (!cmd->con || !cmd->con->tds_socket)
1556 		return CS_FAIL;
1557 
1558 	if (cmd->command_state == _CS_COMMAND_IDLE) {
1559 		_ctclient_msg(cmd->con, "ct_fetch", 1, 1, 1, 16843163, "");
1560 		return CS_FAIL;
1561 	}
1562 
1563 	if (cmd->cancel_state == _CS_CANCEL_PENDING) {
1564 		_ct_cancel_cleanup(cmd);
1565 		return CS_CANCELED;
1566 	}
1567 
1568 	if( prows_read == NULL )
1569 		prows_read = &rows_read_dummy;
1570 
1571 	tds = cmd->con->tds_socket;
1572 
1573 	/*
1574 	 * Call a special function for fetches from a cursor because
1575 	 * the processing is too incompatible to patch into a single function
1576 	 */
1577 	if (cmd->command_type == CS_CUR_CMD) {
1578 		return _ct_fetch_cursor(cmd, type, offset, option, prows_read);
1579 	}
1580 
1581 	*prows_read = 0;
1582 
1583 	if ( cmd->bind_count == CS_UNUSED )
1584 		cmd->bind_count = 1;
1585 
1586 	/* compute rows and parameter results have been pre-fetched by ct_results() */
1587 
1588 	if (cmd->row_prefetched) {
1589 		cmd->row_prefetched = 0;
1590 		cmd->get_data_item = 0;
1591 		cmd->get_data_bytes_returned = 0;
1592 		if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, 0))
1593 			return CS_ROW_FAIL;
1594 		*prows_read = 1;
1595 		return CS_SUCCEED;
1596 	}
1597 
1598 	if (cmd->results_state == _CS_RES_CMD_DONE)
1599 		return CS_END_DATA;
1600 	if (cmd->curr_result_type == CS_COMPUTE_RESULT)
1601 		return CS_END_DATA;
1602 	if (cmd->curr_result_type == CS_CMD_FAIL)
1603 		return CS_CMD_FAIL;
1604 
1605 
1606 	marker = tds_peek(tds);
1607 	if ((cmd->curr_result_type == CS_ROW_RESULT    && marker != TDS_ROW_TOKEN && marker != TDS_NBC_ROW_TOKEN)
1608 	||  (cmd->curr_result_type == CS_STATUS_RESULT && marker != TDS_RETURNSTATUS_TOKEN) )
1609 		return CS_END_DATA;
1610 
1611 	/* Array Binding Code changes start here */
1612 
1613 	for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
1614 
1615 		ret = tds_process_tokens(tds, &ret_type, NULL,
1616 					 TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
1617 
1618 		tdsdump_log(TDS_DBG_FUNC, "inside ct_fetch() process_row_tokens returned %d\n", ret);
1619 
1620 		switch (ret) {
1621 			case TDS_SUCCESS:
1622 				if (ret_type == TDS_ROW_RESULT || ret_type == TDS_COMPUTE_RESULT) {
1623 					cmd->get_data_item = 0;
1624 					cmd->get_data_bytes_returned = 0;
1625 					if (_ct_bind_data(cmd->con->ctx, tds->current_results, tds->current_results, temp_count))
1626 						return CS_ROW_FAIL;
1627 					(*prows_read)++;
1628 					break;
1629 				}
1630 			case TDS_NO_MORE_RESULTS:
1631 				return CS_END_DATA;
1632 				break;
1633 
1634 			case TDS_CANCELLED:
1635 				cmd->cancel_state = _CS_CANCEL_NOCANCEL;
1636 				return CS_CANCELED;
1637 				break;
1638 
1639 			default:
1640 				return CS_FAIL;
1641 				break;
1642 		}
1643 
1644 		/* have we reached the end of the rows ? */
1645 
1646 		marker = tds_peek(tds);
1647 
1648 		if (cmd->curr_result_type == CS_ROW_RESULT && marker != TDS_ROW_TOKEN && marker != TDS_NBC_ROW_TOKEN)
1649 			break;
1650 
1651 	}
1652 
1653 	/* Array Binding Code changes end here */
1654 
1655 	return CS_SUCCEED;
1656 }
1657 
1658 static CS_RETCODE
_ct_fetch_cursor(CS_COMMAND * cmd,CS_INT type,CS_INT offset,CS_INT option,CS_INT * rows_read)1659 _ct_fetch_cursor(CS_COMMAND * cmd, CS_INT type, CS_INT offset, CS_INT option, CS_INT * rows_read)
1660 {
1661 	TDSSOCKET * tds;
1662 	TDSCURSOR *cursor;
1663 	TDS_INT restype;
1664 	TDSRET ret;
1665 	TDS_INT temp_count;
1666 	TDS_INT done_flags;
1667 	TDS_INT rows_this_fetch = 0;
1668 
1669 	tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor(%p, %d, %d, %d, %p)\n", cmd, type, offset, option, rows_read);
1670 
1671 	if (!cmd->con || !cmd->con->tds_socket)
1672 		return CS_FAIL;
1673 
1674 	tds = cmd->con->tds_socket;
1675 
1676 	if (rows_read)
1677 		*rows_read = 0;
1678 
1679 	/* taking a copy of the cmd->bind_count value. */
1680 	temp_count = cmd->bind_count;
1681 
1682 	if ( cmd->bind_count == CS_UNUSED )
1683 		cmd->bind_count = 1;
1684 
1685 	cursor = cmd->cursor;
1686 	if (!cursor) {
1687 		tdsdump_log(TDS_DBG_FUNC, "ct_fetch_cursor() : cursor not present\n");
1688 		return CS_FAIL;
1689 	}
1690 
1691 	/* currently we are placing this restriction on cursor fetches.  */
1692 	/* the alternatives are too awful to contemplate at the moment   */
1693 	/* i.e. buffering all the rows from the fetch internally...      */
1694 
1695 	if (cmd->bind_count < cursor->cursor_rows) {
1696 		tdsdump_log(TDS_DBG_WARN, "_ct_fetch_cursor(): bind count must equal cursor rows \n");
1697 		return CS_FAIL;
1698 	}
1699 
1700 	if (TDS_FAILED(tds_cursor_fetch(tds, cursor, TDS_CURSOR_FETCH_NEXT, 0))) {
1701 		tdsdump_log(TDS_DBG_WARN, "ct_fetch(): cursor fetch failed\n");
1702 		return CS_FAIL;
1703 	}
1704 	cursor->status.fetch = _CS_CURS_TYPE_SENT;
1705 
1706 	while ((tds_process_tokens(tds, &restype, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
1707 		switch (restype) {
1708 			case CS_ROWFMT_RESULT:
1709 				break;
1710 			case CS_ROW_RESULT:
1711 				for (temp_count = 0; temp_count < cmd->bind_count; temp_count++) {
1712 
1713 					ret = tds_process_tokens(tds, &restype, NULL,
1714 							 TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
1715 
1716 					tdsdump_log(TDS_DBG_FUNC, "_ct_fetch_cursor() tds_process_tokens returned %d\n", ret);
1717 
1718 					if (ret == TDS_SUCCESS && (restype == TDS_ROW_RESULT || restype == TDS_COMPUTE_RESULT)) {
1719 						cmd->get_data_item = 0;
1720 						cmd->get_data_bytes_returned = 0;
1721 						if (restype == TDS_ROW_RESULT) {
1722 							if (_ct_bind_data(cmd->con->ctx, tds->current_results,
1723 									  tds->current_results, temp_count))
1724 								return CS_ROW_FAIL;
1725 							if (rows_read)
1726 								*rows_read = *rows_read + 1;
1727 							rows_this_fetch++;
1728 						}
1729 					} else {
1730 						if (TDS_FAILED(ret))
1731 							return CS_FAIL;
1732 						break;
1733 					}
1734 				}
1735 				break;
1736 			case TDS_DONE_RESULT:
1737 				break;
1738 		}
1739 	}
1740 	if (rows_this_fetch)
1741 		return CS_SUCCEED;
1742 
1743 	cmd->results_state = _CS_RES_CMD_SUCCEED;
1744 	return CS_END_DATA;
1745 }
1746 
1747 
1748 int
_ct_bind_data(CS_CONTEXT * ctx,TDSRESULTINFO * resinfo,TDSRESULTINFO * bindinfo,CS_INT offset)1749 _ct_bind_data(CS_CONTEXT *ctx, TDSRESULTINFO * resinfo, TDSRESULTINFO *bindinfo, CS_INT offset)
1750 {
1751 	TDSCOLUMN *curcol, *bindcol;
1752 	unsigned char *src, *dest, *temp_add;
1753 	int i, result = 0;
1754 	CS_DATAFMT srcfmt, destfmt;
1755 	TDS_INT datalen_dummy, *pdatalen = &datalen_dummy;
1756 	TDS_SMALLINT nullind_dummy, *nullind = &nullind_dummy;
1757 
1758 	tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data(%p, %p, %p, %d)\n", ctx, resinfo, bindinfo, offset);
1759 
1760 	for (i = 0; i < resinfo->num_cols; i++) {
1761 
1762 		curcol = resinfo->columns[i];
1763 		bindcol = bindinfo->columns[i];
1764 
1765 		tdsdump_log(TDS_DBG_FUNC, "_ct_bind_data(): column %d is type %d and has length %d\n",
1766 						i, curcol->column_type, curcol->column_cur_size);
1767 
1768 		if (curcol->column_hidden)
1769 			continue;
1770 
1771 		/*
1772 		 * Retrieve the initial bound column_varaddress and increment it if offset specified
1773 		 */
1774 
1775 		temp_add = (unsigned char *) bindcol->column_varaddr;
1776 		dest = temp_add + (offset * bindcol->column_bindlen);
1777 
1778 		if (bindcol->column_nullbind) {
1779 			nullind = bindcol->column_nullbind;
1780 			assert(nullind);
1781 			nullind += offset;
1782         } else {
1783             nullind = &nullind_dummy;
1784 		}
1785 		if (bindcol->column_lenbind) {
1786 			pdatalen = bindcol->column_lenbind;
1787 			assert(pdatalen);
1788 			pdatalen += offset;
1789         } else {
1790             pdatalen = &datalen_dummy;
1791 		}
1792 
1793 		if (dest) {
1794 			if (curcol->column_cur_size < 0) {
1795 				*nullind = -1;
1796 				*pdatalen = 0;
1797 			} else {
1798 
1799 				src = curcol->column_data;
1800 				if (is_blob_col(curcol))
1801 					src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
1802 
1803                 srcfmt.datatype = _ct_get_client_type(ctx, curcol);
1804 				srcfmt.maxlength = curcol->column_cur_size;
1805 
1806 				destfmt.datatype = bindcol->column_bindtype;
1807 				destfmt.maxlength = bindcol->column_bindlen;
1808 				destfmt.format = bindcol->column_bindfmt;
1809 
1810 				/* if convert return FAIL mark error but process other columns */
1811 				if ((result= cs_convert(ctx, &srcfmt, src, &destfmt, dest, pdatalen) != CS_SUCCEED)) {
1812 					tdsdump_log(TDS_DBG_FUNC, "cs_convert-result = %d\n", result);
1813 					result = 1;
1814 					tdsdump_log(TDS_DBG_INFO1, "error: converted only %d bytes for type %d \n",
1815 									*pdatalen, srcfmt.datatype);
1816 				}
1817 
1818 				*nullind = 0;
1819 			}
1820 		} else {
1821 			*pdatalen = 0;
1822 		}
1823 	}
1824 	return result;
1825 }
1826 
1827 CS_RETCODE
ct_cmd_drop(CS_COMMAND * cmd)1828 ct_cmd_drop(CS_COMMAND * cmd)
1829 {
1830 	CS_COMMAND_LIST *victim = NULL;
1831 	CS_COMMAND_LIST *prev = NULL;
1832 	CS_COMMAND_LIST *next = NULL;
1833 	CS_CONNECTION *con;
1834 
1835 	tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop(%p)\n", cmd);
1836 
1837 	if (cmd) {
1838 		free(cmd->query);
1839 		if (cmd->input_params)
1840 			param_clear(cmd->input_params);
1841 		free(cmd->userdata);
1842 		if (cmd->rpc) {
1843 			if (cmd->rpc->param_list)
1844 				param_clear(cmd->rpc->param_list);
1845 			free(cmd->rpc->name);
1846 			free(cmd->rpc);
1847 		}
1848 		free(cmd->iodesc);
1849 
1850 		/* now remove this command from the list of commands in the connection */
1851 		if (cmd->con) {
1852 			con = cmd->con;
1853 			victim = con->cmds;
1854 
1855 			for (;;) {
1856 				if (victim->cmd == cmd)
1857 					break;
1858 				prev = victim;
1859 				victim = victim->next;
1860 				if (victim == NULL) {
1861 					tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : cannot find command entry in list \n");
1862 					return CS_FAIL;
1863 				}
1864 			}
1865 
1866 			tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : command entry found in list\n");
1867 
1868 			next = victim->next;
1869 			free(victim);
1870 
1871 			tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : relinking list\n");
1872 
1873 			if (prev)
1874 				prev->next = next;
1875 			else
1876 				con->cmds = next;
1877 
1878 			tdsdump_log(TDS_DBG_FUNC, "ct_cmd_drop() : relinked list\n");
1879 		}
1880 
1881 		free(cmd);
1882 	}
1883 	return CS_SUCCEED;
1884 }
1885 
1886 CS_RETCODE
ct_close(CS_CONNECTION * con,CS_INT option)1887 ct_close(CS_CONNECTION * con, CS_INT option)
1888 {
1889 	tdsdump_log(TDS_DBG_FUNC, "ct_close(%p, %d)\n", con, option);
1890 
1891 	tds_close_socket(con->tds_socket);
1892 	tds_free_socket(con->tds_socket);
1893 	con->tds_socket = NULL;
1894 	return CS_SUCCEED;
1895 }
1896 
1897 CS_RETCODE
ct_con_drop(CS_CONNECTION * con)1898 ct_con_drop(CS_CONNECTION * con)
1899 {
1900 	CS_COMMAND_LIST *currptr, *freeptr;
1901 
1902 	tdsdump_log(TDS_DBG_FUNC, "ct_con_drop(%p)\n", con);
1903 
1904 	if (con) {
1905 		free(con->userdata);
1906 		if (con->tds_login)
1907 			tds_free_login(con->tds_login);
1908 		if (con->cmds) {
1909 			currptr = con->cmds;
1910 			while (currptr != NULL) {
1911 				freeptr = currptr;
1912 				if (currptr->cmd) {
1913 					currptr->cmd->con = NULL;
1914 					currptr->cmd->dyn = NULL;
1915 				}
1916 				currptr = currptr->next;
1917 				free(freeptr);
1918 			}
1919 		}
1920 		while (con->dynlist)
1921 			_ct_deallocate_dynamic(con, con->dynlist);
1922 		if (con->locale)
1923 			_cs_locale_free(con->locale);
1924 		tds_free_socket(con->tds_socket);
1925 		con->tds_socket = NULL;
1926 		free(con->server_addr);
1927 		free(con);
1928 	}
1929 	return CS_SUCCEED;
1930 }
1931 
1932 int
_ct_get_client_type(CS_CONTEXT * ctx,TDSCOLUMN * col)1933 _ct_get_client_type(CS_CONTEXT *ctx, TDSCOLUMN *col)
1934 {
1935 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_client_type(type %d, user %d, size %d)\n", col->column_type, col->column_usertype, col->column_size);
1936 
1937 	switch (col->column_type) {
1938 	case SYBBIT:
1939 	case SYBBITN:
1940 		return CS_BIT_TYPE;
1941 		break;
1942 	case SYBCHAR:
1943 	case SYBVARCHAR:
1944 		return CS_CHAR_TYPE;
1945 		break;
1946 	case SYBINT8:
1947     case SYBUINT8:
1948 		return CS_BIGINT_TYPE;
1949 		break;
1950 	case SYBINT4:
1951     case SYBUINT4:
1952 		return CS_INT_TYPE;
1953 		break;
1954 	case SYBINT2:
1955     case SYBUINT2:
1956 		return CS_SMALLINT_TYPE;
1957 		break;
1958 	case SYBINT1:
1959 		return CS_TINYINT_TYPE;
1960 		break;
1961 	case SYBINTN:
1962 		switch (col->column_size) {
1963 		case 8:
1964 			return CS_BIGINT_TYPE;
1965 		case 4:
1966 			return CS_INT_TYPE;
1967 		case 2:
1968 			return CS_SMALLINT_TYPE;
1969 		case 1:
1970 			return CS_TINYINT_TYPE;
1971 		default:
1972             _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 28,
1973                           "%d", col->column_size);
1974 		}
1975 		break;
1976 	case SYBREAL:
1977 		return CS_REAL_TYPE;
1978 		break;
1979 	case SYBFLT8:
1980 		return CS_FLOAT_TYPE;
1981 		break;
1982 	case SYBFLTN:
1983 		if (col->column_size == 4) {
1984 			return CS_REAL_TYPE;
1985 		} else if (col->column_size == 8) {
1986 			return CS_FLOAT_TYPE;
1987 		}
1988         _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 29,
1989                       "%d", col->column_size);
1990 		break;
1991 	case SYBMONEY:
1992 		return CS_MONEY_TYPE;
1993 		break;
1994 	case SYBMONEY4:
1995 		return CS_MONEY4_TYPE;
1996 		break;
1997 	case SYBMONEYN:
1998 		if (col->column_size == 4) {
1999 			return CS_MONEY4_TYPE;
2000 		} else if (col->column_size == 8) {
2001 			return CS_MONEY_TYPE;
2002 		}
2003         _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 30,
2004                       "%d", col->column_size);
2005 		break;
2006 	case SYBDATETIME:
2007 		return CS_DATETIME_TYPE;
2008 		break;
2009 	case SYBDATETIME4:
2010 		return CS_DATETIME4_TYPE;
2011 		break;
2012 	case SYBDATETIMN:
2013 		if (col->column_size == 4) {
2014 			return CS_DATETIME4_TYPE;
2015 		} else if (col->column_size == 8) {
2016 			return CS_DATETIME_TYPE;
2017 		}
2018         _csclient_msg(ctx, "_ct_get_client_type", 2, 1, 16, 31,
2019                       "%d", col->column_size);
2020 		break;
2021 	case SYBNUMERIC:
2022 		return CS_NUMERIC_TYPE;
2023 		break;
2024 	case SYBDECIMAL:
2025 		return CS_DECIMAL_TYPE;
2026 		break;
2027 	case SYBBINARY:
2028 	case SYBVARBINARY:
2029 		return CS_BINARY_TYPE;
2030 		break;
2031 	case SYBIMAGE:
2032 		return CS_IMAGE_TYPE;
2033 		break;
2034 	case SYBTEXT:
2035 		return CS_TEXT_TYPE;
2036 		break;
2037 	case SYBUNIQUE:
2038 		return CS_UNIQUE_TYPE;
2039 		break;
2040 	case SYBLONGBINARY:
2041 		if (col->column_usertype == USER_UNICHAR_TYPE || col->column_usertype == USER_UNIVARCHAR_TYPE)
2042 			return CS_UNICHAR_TYPE;
2043 		return CS_LONGBINARY_TYPE;
2044 		break;
2045 	}
2046 
2047 	return CS_FAIL;
2048 }
2049 
2050 TDS_SERVER_TYPE
_ct_get_server_type(TDSSOCKET * tds,int datatype)2051 _ct_get_server_type(TDSSOCKET *tds, int datatype)
2052 {
2053 	tdsdump_log(TDS_DBG_FUNC, "_ct_get_server_type(%d)\n", datatype);
2054 
2055 	switch (datatype) {
2056 	case CS_IMAGE_TYPE:		return SYBIMAGE;
2057 	case CS_BINARY_TYPE:		return SYBBINARY;
2058 	case CS_BIT_TYPE:		return SYBBIT;
2059 	case CS_CHAR_TYPE:		return SYBCHAR;
2060 	case CS_VARCHAR_TYPE:		return SYBVARCHAR;
2061     case CS_NVARCHAR_TYPE:  return SYBNVARCHAR;
2062 	case CS_LONG_TYPE:
2063 	case CS_UBIGINT_TYPE:
2064 		if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT8))
2065 			return SYBUINT8;
2066 		return SYBINT8;
2067 	case CS_UINT_TYPE:
2068 		if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT4))
2069 			return SYBUINT4;
2070 		return SYBINT4;
2071 	case CS_USMALLINT_TYPE:
2072 		if (!tds || tds_capability_has_req(tds->conn, TDS_REQ_DATA_UINT2))
2073 			return SYBUINT2;
2074 		return SYBINT2;
2075 	case CS_BIGINT_TYPE:		return SYBINT8;
2076 	case CS_INT_TYPE:		return SYBINT4;
2077 	case CS_SMALLINT_TYPE:		return SYBINT2;
2078 	case CS_TINYINT_TYPE:		return SYBINT1;
2079 	case CS_REAL_TYPE:		return SYBREAL;
2080 	case CS_FLOAT_TYPE:		return SYBFLT8;
2081 	case CS_MONEY_TYPE:		return SYBMONEY;
2082 	case CS_MONEY4_TYPE:		return SYBMONEY4;
2083 	case CS_DATETIME_TYPE:		return SYBDATETIME;
2084 	case CS_DATETIME4_TYPE:		return SYBDATETIME4;
2085 	case CS_NUMERIC_TYPE:		return SYBNUMERIC;
2086 	case CS_DECIMAL_TYPE:		return SYBDECIMAL;
2087 	case CS_VARBINARY_TYPE:		return SYBVARBINARY;
2088 	case CS_TEXT_TYPE:		return SYBTEXT;
2089 	case CS_UNIQUE_TYPE:		return SYBUNIQUE;
2090 	case CS_LONGBINARY_TYPE:	return SYBLONGBINARY;
2091     case CS_UNICHAR_TYPE:       return SYBNVARCHAR;
2092     case CS_LONGCHAR_TYPE:
2093         return (!tds || IS_TDS7_PLUS(tds->conn)) ? SYBVARCHAR : SYBLONGCHAR;
2094     case CS_NLONGCHAR_TYPE:     return SYBNVARCHAR;
2095 
2096 	default:
2097         /*
2098          * SENSITIVITY, BOUNDARY, VOID, USHORT, BLOB, DATE, TIME, UNITEXT,
2099          * XML, USER
2100          */
2101         return (TDS_SERVER_TYPE)-1;
2102 		break;
2103 	}
2104 }
2105 
2106 CS_RETCODE
ct_cancel(CS_CONNECTION * conn,CS_COMMAND * cmd,CS_INT type)2107 ct_cancel(CS_CONNECTION * conn, CS_COMMAND * cmd, CS_INT type)
2108 {
2109 	CS_RETCODE ret;
2110 	CS_COMMAND_LIST *cmds;
2111 	CS_COMMAND *conn_cmd;
2112 	CS_CONNECTION *cmd_conn;
2113 
2114 	tdsdump_log(TDS_DBG_FUNC, "ct_cancel(%p, %p, %d)\n", conn, cmd, type);
2115 
2116 	/*
2117 	 * Comments taken from Sybase ct-library reference manual
2118 	 * ------------------------------------------------------
2119 	 *
2120 	 * "To cancel current results, an application calls ct_cancel
2121 	 *  with type as CT_CANCEL CURRENT. This is equivalent to
2122 	 *  calling ct_fetch until it returns CS_END_DATA"
2123 	 *
2124 	 * "For CS_CANCEL_CURRENT cancels, cmd must be supplied"
2125 	 * "For CS_CANCEL_CURRENT cancels, connection must be NULL"
2126 	 */
2127 
2128 	if (type == CS_CANCEL_CURRENT) {
2129 
2130 
2131 		tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_CURRENT\n");
2132 		if (conn || !cmd)
2133 			return CS_FAIL;
2134 
2135 
2136 		if (!_ct_fetchable_results(cmd)) {
2137 			tdsdump_log(TDS_DBG_FUNC, "ct_cancel() no fetchable results - return()\n");
2138 			return CS_SUCCEED;
2139 		}
2140 
2141 		tdsdump_log(TDS_DBG_FUNC, "ct_cancel() - fetching results()\n");
2142 		do {
2143 			ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, NULL);
2144 		} while ((ret == CS_SUCCEED) || (ret == CS_ROW_FAIL));
2145 
2146 		if (cmd->con && cmd->con->tds_socket)
2147 			tds_free_all_results(cmd->con->tds_socket);
2148 
2149 		if (ret == CS_END_DATA) {
2150 			return CS_SUCCEED;
2151 		}
2152 		return CS_FAIL;
2153 	}
2154 
2155 	/*
2156 	 * Comments taken from Sybase ct-library reference manual
2157 	 * ------------------------------------------------------
2158 	 *
2159 	 * "To cancel the current command and all results generated
2160 	 *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
2161 	 *  CS_CANCEL_ALL. Both of these calls tell client library
2162 	 *  to :
2163 	 *  * Send an attention to the server
2164 	 *  * discard any results already generated by the command
2165 	 *  Both types of cancel return CS_SUCCEED immediately, w/o
2166 	 *  sending an attention, if no command is in progress.
2167 	 *  If an application has not yet called ct_send to send an
2168 	 *  initiated command, a CS_CANCEL_ATTN has no effect.
2169 	 *
2170 	 *  If a command has been sent and ct_results has not been
2171 	 *  called, a ct_cancel (CS_CANCEL_ATTN) has no effect."
2172 	 *
2173 	 * "For CS_CANCEL_ATTN cancels, one of connection or cmd
2174 	 *  must be NULL. if cmd is supplied and connection is NULL
2175 	 *  the cancel operation applies only to the command pend-
2176 	 *  ing for this command structure. If cmd is NULL and
2177 	 *  connection is supplied, the cancel operation applies to
2178 	 *  all commands pending for this connection.
2179 	 */
2180 
2181 	if (type == CS_CANCEL_ATTN) {
2182 		if ((conn && cmd) || (!conn && !cmd)) {
2183 			return CS_FAIL;
2184 		}
2185 		if (cmd) {
2186 			tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with cmd\n");
2187 			cmd_conn = cmd->con;
2188 			switch (cmd->command_state) {
2189 				case _CS_COMMAND_IDLE:
2190 				case _CS_COMMAND_READY:
2191 					tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
2192 					break;
2193 				case _CS_COMMAND_SENT:
2194 					tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT results_state %d\n",
2195 								   cmd->results_state);
2196 					if (cmd->results_state != _CS_RES_NONE) {
2197 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
2198 						tds_send_cancel(cmd_conn->tds_socket);
2199 						cmd->cancel_state = _CS_CANCEL_PENDING;
2200 					}
2201 					break;
2202 			}
2203 		}
2204 		if (conn) {
2205 			tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ATTN with connection\n");
2206 			for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
2207 				conn_cmd = cmds->cmd;
2208 				switch (conn_cmd->command_state) {
2209 					case _CS_COMMAND_IDLE:
2210 					case _CS_COMMAND_READY:
2211 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
2212 						break;
2213 					case _CS_COMMAND_SENT:
2214 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
2215 						if (conn_cmd->results_state != _CS_RES_NONE) {
2216 							tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
2217 							tds_send_cancel(conn->tds_socket);
2218 							conn_cmd->cancel_state = _CS_CANCEL_PENDING;
2219 						}
2220 					break;
2221 				}
2222 			}
2223 		}
2224 
2225 		return CS_SUCCEED;
2226 	}
2227 
2228 	/*
2229 	 * Comments taken from Sybase ct-library reference manual
2230 	 * ------------------------------------------------------
2231 	 *
2232 	 * "To cancel the current command and all results generated
2233 	 *  by it, call ct_cancel with type as CS_CANCEL_ATTN or
2234 	 *  CS_CANCEL_ALL. Both of these calls tell client library
2235 	 *  to :
2236 	 *  * Send an attention to the server
2237 	 *  * discard any results already generated by the command
2238 	 *  Both types of cancel return CS_SUCCEED immediately, w/o
2239 	 *  sending an attention, if no command is in progress.
2240 	 *
2241 	 *  If an application has not yet called ct_send to send an
2242 	 *  initiated command, a CS_CANCEL_ALL cancel discards the
2243 	 *  initiated command without sending an attention to the
2244 	 *  server.
2245 	 *
2246 	 *  CS_CANCEL_ALL leaves the command structure in a 'clean'
2247 	 *  state, available for use in another operation.
2248 	 *
2249 	 * "For CS_CANCEL_ALL cancels, one of connection or cmd
2250 	 *  must be NULL. if cmd is supplied and connection is NULL
2251 	 *  the cancel operation applies only to the command pend-
2252 	 *  ing for this command structure. If cmd is NULL and
2253 	 *  connection is supplied, the cancel operation applies to
2254 	 *  all commands pending for this connection.
2255 	 */
2256 
2257 	if (type == CS_CANCEL_ALL) {
2258 
2259 		if ((conn && cmd) || (!conn && !cmd)) {
2260 			return CS_FAIL;
2261 		}
2262 		if (cmd) {
2263 			tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with cmd\n");
2264 			cmd_conn = cmd->con;
2265 			switch (cmd->command_state) {
2266 				case _CS_COMMAND_IDLE:
2267 				case _CS_COMMAND_BUILDING:
2268 				case _CS_COMMAND_READY:
2269 					tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state READY/IDLE\n");
2270 					_ct_initialise_cmd(cmd);
2271 					break;
2272 				case _CS_COMMAND_SENT:
2273 					tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
2274 					tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
2275 					tds_send_cancel(cmd_conn->tds_socket);
2276 					tds_process_cancel(cmd_conn->tds_socket);
2277 					_ct_initialise_cmd(cmd);
2278 					cmd->cancel_state = _CS_CANCEL_PENDING;
2279 					break;
2280 			}
2281 		}
2282 		if (conn) {
2283 			tdsdump_log(TDS_DBG_FUNC, "CS_CANCEL_ALL with connection\n");
2284 			for (cmds = conn->cmds; cmds != NULL; cmds = cmds->next) {
2285 				tdsdump_log(TDS_DBG_FUNC, "ct_cancel() cancelling a command for a connection\n");
2286 				conn_cmd = cmds->cmd;
2287 				switch (conn_cmd->command_state) {
2288 					case _CS_COMMAND_IDLE:
2289 					case _CS_COMMAND_BUILDING:
2290 					case _CS_COMMAND_READY:
2291 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
2292 						_ct_initialise_cmd(conn_cmd);
2293 						break;
2294 					case _CS_COMMAND_SENT:
2295 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() command state SENT\n");
2296 						tdsdump_log(TDS_DBG_FUNC, "ct_cancel() sending a cancel \n");
2297 						tds_send_cancel(conn->tds_socket);
2298 						tds_process_cancel(conn->tds_socket);
2299 						_ct_initialise_cmd(conn_cmd);
2300 						conn_cmd->cancel_state = _CS_CANCEL_PENDING;
2301 					break;
2302 				}
2303 			}
2304 		}
2305 
2306 		return CS_SUCCEED;
2307 	}
2308 	return CS_FAIL;
2309 }
2310 
2311 static CS_RETCODE
_ct_cancel_cleanup(CS_COMMAND * cmd)2312 _ct_cancel_cleanup(CS_COMMAND * cmd)
2313 {
2314 	CS_CONNECTION * con;
2315 
2316 	tdsdump_log(TDS_DBG_FUNC, "_ct_cancel_cleanup(%p)\n", cmd);
2317 
2318 	con = cmd->con;
2319 
2320 	if (con && !IS_TDSDEAD(con->tds_socket))
2321 		tds_process_cancel(con->tds_socket);
2322 
2323 	cmd->cancel_state = _CS_CANCEL_NOCANCEL;
2324 
2325 	return CS_SUCCEED;
2326 
2327 }
2328 
2329 CS_RETCODE
ct_describe(CS_COMMAND * cmd,CS_INT item,CS_DATAFMT * datafmt)2330 ct_describe(CS_COMMAND * cmd, CS_INT item, CS_DATAFMT * datafmt)
2331 {
2332 	TDSSOCKET *tds;
2333 	TDSRESULTINFO *resinfo;
2334 	TDSCOLUMN *curcol;
2335     size_t len;
2336 
2337 	tdsdump_log(TDS_DBG_FUNC, "ct_describe(%p, %d, %p)\n", cmd, item, datafmt);
2338 
2339 	if (!cmd->con || !cmd->con->tds_socket)
2340 		return CS_FAIL;
2341 
2342 	tds = cmd->con->tds_socket;
2343 	resinfo = tds->current_results;;
2344 
2345 	if (item < 1 || item > resinfo->num_cols)
2346 		return CS_FAIL;
2347 
2348 	curcol = resinfo->columns[item - 1];
2349 	len = tds_dstr_len(&curcol->column_name);
2350 	if (len >= CS_MAX_NAME)
2351 		len = CS_MAX_NAME - 1;
2352 	strncpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), len);
2353 	/* name is always null terminated */
2354 	datafmt->name[len] = 0;
2355     datafmt->namelen = (TDS_INT) len;
2356 	/* need to turn the SYBxxx into a CS_xxx_TYPE */
2357     datafmt->datatype = _ct_get_client_type(cmd->con->ctx, curcol);
2358 	tdsdump_log(TDS_DBG_INFO1, "ct_describe() datafmt->datatype = %d server type %d\n", datafmt->datatype,
2359 		    curcol->column_type);
2360 	if (is_numeric_type(curcol->column_type))
2361 		datafmt->maxlength = sizeof(CS_NUMERIC);
2362 	else
2363 		datafmt->maxlength = curcol->column_size;
2364 	datafmt->usertype = curcol->column_usertype;
2365 	datafmt->precision = curcol->column_prec;
2366 	datafmt->scale = curcol->column_scale;
2367     datafmt->format = curcol->column_bindfmt;
2368 
2369 	/*
2370 	 * There are other options that can be returned, but these are the
2371 	 * only two being noted via the TDS layer.
2372 	 */
2373 	datafmt->status = 0;
2374 	if (curcol->column_nullable)
2375 		datafmt->status |= CS_CANBENULL;
2376 	if (curcol->column_identity)
2377 		datafmt->status |= CS_IDENTITY;
2378 	if (curcol->column_writeable)
2379 		datafmt->status |= CS_UPDATABLE;
2380 	if (curcol->column_key)
2381 		datafmt->status |= CS_KEY;
2382 	if (curcol->column_hidden)
2383 		datafmt->status |= CS_HIDDEN;
2384 	if (curcol->column_timestamp)
2385 		datafmt->status |= CS_TIMESTAMP;
2386 
2387 	datafmt->count = 1;
2388 	datafmt->locale = NULL;
2389 
2390 	return CS_SUCCEED;
2391 }
2392 
2393 CS_RETCODE
ct_res_info(CS_COMMAND * cmd,CS_INT type,CS_VOID * buffer,CS_INT buflen,CS_INT * out_len)2394 ct_res_info(CS_COMMAND * cmd, CS_INT type, CS_VOID * buffer, CS_INT buflen, CS_INT * out_len)
2395 {
2396 	TDSSOCKET *tds;
2397 	TDSRESULTINFO *resinfo;
2398 	TDSCOLUMN *curcol;
2399 	CS_INT int_val;
2400 	int i;
2401 
2402 	tdsdump_log(TDS_DBG_FUNC, "ct_res_info(%p, %d, %p, %d, %p)\n", cmd, type, buffer, buflen, out_len);
2403 
2404 	if (!cmd->con || !cmd->con->tds_socket)
2405 		return CS_FAIL;
2406 
2407 	tds = cmd->con->tds_socket;
2408 	resinfo = tds->current_results;
2409 
2410 	switch (type) {
2411 	case CS_NUMDATA:
2412 		int_val = 0;
2413 		if (resinfo) {
2414 			for (i = 0; i < resinfo->num_cols; i++) {
2415 				curcol = resinfo->columns[i];
2416 				if (!curcol->column_hidden) {
2417 					int_val++;
2418 				}
2419 			}
2420 		}
2421 		tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of columns is %d\n", int_val);
2422 		memcpy(buffer, &int_val, sizeof(CS_INT));
2423 		break;
2424 	case CS_ROW_COUNT:
2425 		if (cmd->results_state == _CS_RES_STATUS)
2426 			return CS_FAIL;
2427 		/* 64 -> 32 bit conversion saturate to the maximum */
2428 		int_val = tds->rows_affected > 0x7fffffff ? 0x7fffffff : (CS_INT) tds->rows_affected;
2429 		tdsdump_log(TDS_DBG_FUNC, "ct_res_info(): Number of rows is %d\n", int_val);
2430 		memcpy(buffer, &int_val, sizeof(CS_INT));
2431 		break;
2432 	default:
2433         _csclient_msg(cmd->con->ctx, "ct_res_info", 2, 1, 16, 32, "%d", type);
2434 		return CS_FAIL;
2435 		break;
2436 	}
2437 	return CS_SUCCEED;
2438 
2439 }
2440 
2441 CS_RETCODE
ct_config(CS_CONTEXT * ctx,CS_INT action,CS_INT property,CS_VOID * buffer,CS_INT buflen,CS_INT * outlen)2442 ct_config(CS_CONTEXT * ctx, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
2443 {
2444 	CS_RETCODE ret = CS_SUCCEED;
2445 	CS_INT *buf = (CS_INT *) buffer;
2446 
2447 	tdsdump_log(TDS_DBG_FUNC, "ct_config(%p, %d, %d, %p, %d, %p)\n", ctx, action, property, buffer, buflen, outlen);
2448 
2449 	tdsdump_log(TDS_DBG_FUNC, "ct_config() action = %s property = %d\n",
2450 		    CS_GET ? "CS_GET" : CS_SET ? "CS_SET" : CS_SUPPORTED ? "CS_SUPPORTED" : "CS_CLEAR", property);
2451 
2452 	switch (property) {
2453 	case CS_EXPOSE_FMTS:
2454 		switch (action) {
2455 		case CS_SUPPORTED:
2456 			*buf = CS_TRUE;
2457 			break;
2458 		case CS_SET:
2459 			if (*buf != CS_TRUE && *buf != CS_FALSE)
2460 				ret = CS_FAIL;
2461 			else
2462 				ctx->config.cs_expose_formats = *buf;
2463 			break;
2464 		case CS_GET:
2465 			if (buf)
2466 				*buf = ctx->config.cs_expose_formats;
2467 			else
2468 				ret = CS_FAIL;
2469 			break;
2470 		case CS_CLEAR:
2471 			ctx->config.cs_expose_formats = CS_FALSE;
2472 			break;
2473 		default:
2474 			ret = CS_FAIL;
2475 		}
2476 		break;
2477 	case CS_VER_STRING: {
2478 		ret = CS_FAIL;
2479 		switch (action) {
2480 			case CS_GET: {
2481 				if (buffer && buflen > 0 && outlen) {
2482 					const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
2483 					*outlen= snprintf((char*)buffer, buflen, "%s (%s, default tds version=%s)",
2484 						settings->freetds_version,
2485 						(settings->threadsafe ? "threadsafe" : "non-threadsafe"),
2486 						settings->tdsver
2487 					);
2488 					((char*)buffer)[buflen - 1]= 0;
2489 					if (*outlen < 0)
2490                         *outlen = (CS_INT) strlen((char*) buffer);
2491 					ret = CS_SUCCEED;
2492 				}
2493 				break;
2494 				default:
2495 					ret = CS_FAIL;
2496 					break;
2497 				}
2498 			}
2499 		}
2500 		break;
2501 	case CS_VERSION:
2502 		ret = CS_FAIL;
2503 		switch (action) {
2504 			case CS_GET: {
2505 				if (buffer && buflen > 0 && outlen) {
2506 					const TDS_COMPILETIME_SETTINGS *settings= tds_get_compiletime_settings();
2507 					*outlen= snprintf((char*) buffer, buflen, "%s", settings->freetds_version);
2508 					((char*)buffer)[buflen - 1]= 0;
2509 					if (*outlen < 0)
2510                         *outlen = (CS_INT) strlen((char*) buffer);
2511 					ret = CS_SUCCEED;
2512 				}
2513 				break;
2514 			default:
2515 				ret = CS_FAIL;
2516 				break;
2517 			}
2518 		}
2519 		break;
2520     case CS_TIMEOUT:
2521         switch (action) {
2522         case CS_SET:
2523             ctx->query_timeout = *((unsigned int*)buf);
2524             break;
2525         case CS_GET:
2526             *((unsigned int*)buf) = ctx->query_timeout;
2527             break;
2528         case CS_CLEAR:
2529             ctx->query_timeout = -1;
2530             break;
2531         default:
2532             ret = CS_FAIL;
2533             break;
2534         }
2535         break;
2536     case CS_LOGIN_TIMEOUT:
2537         switch (action) {
2538         case CS_SET:
2539             ctx->login_timeout = *((unsigned int*)buf);
2540             break;
2541         case CS_GET:
2542             *((unsigned int*)buf) = ctx->login_timeout;
2543             break;
2544         case CS_CLEAR:
2545             ctx->login_timeout = -1;
2546             break;
2547         default:
2548             ret = CS_FAIL;
2549             break;
2550         }
2551         break;
2552 	default:
2553 		ret = CS_SUCCEED;
2554 		break;
2555 	}
2556 
2557 	return ret;
2558 }
2559 
2560 CS_RETCODE
ct_cmd_props(CS_COMMAND * cmd,CS_INT action,CS_INT property,CS_VOID * buffer,CS_INT buflen,CS_INT * outlen)2561 ct_cmd_props(CS_COMMAND * cmd, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
2562 {
2563 	TDSCURSOR *cursor;
2564 	int maxcp;
2565 
2566 	tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props(%p, %d, %d, %p, %d, %p)\n", cmd, action, property, buffer, buflen, outlen);
2567 
2568 	if (!cmd->con || !cmd->con->tds_socket)
2569 		return CS_FAIL;
2570 
2571 	tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() action = %s property = %d\n", CS_GET ? "CS_GET" : "CS_SET", property);
2572 	if (action == CS_SET) {
2573 		switch (property) {
2574 		case CS_USERDATA:
2575 			free(cmd->userdata);
2576 			cmd->userdata = (void *) malloc(buflen + 1);
2577 			tdsdump_log(TDS_DBG_INFO2, "setting userdata orig %p new %p\n", buffer, cmd->userdata);
2578 			cmd->userdata_len = buflen;
2579 			memcpy(cmd->userdata, buffer, buflen);
2580 			break;
2581 		default:
2582 			break;
2583 		}
2584 	}
2585 	if (action == CS_GET) {
2586 		switch (property) {
2587 
2588 		case CS_PARENT_HANDLE:
2589 			*(CS_CONNECTION **) buffer = cmd->con;
2590 			break;
2591 
2592 		case CS_CUR_STATUS:
2593 		case CS_CUR_ID:
2594 		case CS_CUR_NAME:
2595 		case CS_CUR_ROWCOUNT:
2596 
2597 			cursor = cmd->cursor;
2598 
2599 			if (!cursor) {
2600 				tdsdump_log(TDS_DBG_FUNC, "ct_cmd_props() : cannot find cursor\n");
2601 				if (property == CS_CUR_STATUS) {
2602 					*(CS_INT *)buffer = (CS_INT) CS_CURSTAT_NONE;
2603 					if (outlen) *outlen = sizeof(CS_INT);
2604 					return CS_SUCCEED;
2605 				} else {
2606 					return CS_FAIL;
2607 				}
2608 			}
2609 
2610 			if (property == CS_CUR_STATUS) {
2611 				*(CS_INT *)buffer = cursor->srv_status;
2612 				if (outlen) *outlen = sizeof(CS_INT);
2613 			}
2614 			if (property == CS_CUR_ID) {
2615 				*(CS_INT *)buffer = cursor->cursor_id;
2616 				if (outlen) *outlen = sizeof(CS_INT);
2617 			}
2618 			if (property == CS_CUR_NAME) {
2619 				size_t len = strlen(cursor->cursor_name);
2620 				if ((CS_INT) len >= buflen)
2621 					return CS_FAIL;
2622 				strcpy((char*) buffer, cursor->cursor_name);
2623                 if (outlen) *outlen = (CS_INT)len;
2624 			}
2625 			if (property == CS_CUR_ROWCOUNT) {
2626 				*(CS_INT *)buffer = cursor->cursor_rows;
2627 				if (outlen) *outlen = sizeof(CS_INT);
2628 			}
2629 			break;
2630 
2631 		case CS_USERDATA:
2632 			tdsdump_log(TDS_DBG_INFO2, "fetching userdata %p\n", cmd->userdata);
2633 			maxcp = cmd->userdata_len;
2634 			if (outlen) *outlen = maxcp;
2635 			if (maxcp > buflen)
2636 				maxcp = buflen;
2637 			memcpy(buffer, cmd->userdata, maxcp);
2638 			break;
2639 		default:
2640 			break;
2641 		}
2642 	}
2643 	return CS_SUCCEED;
2644 }
2645 
2646 CS_RETCODE
ct_compute_info(CS_COMMAND * cmd,CS_INT type,CS_INT colnum,CS_VOID * buffer,CS_INT buflen,CS_INT * outlen)2647 ct_compute_info(CS_COMMAND * cmd, CS_INT type, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
2648 {
2649 	TDSSOCKET *tds;
2650 	TDSRESULTINFO *resinfo;
2651 	TDSCOLUMN *curcol;
2652 	CS_INT int_val;
2653 	CS_SMALLINT *dest_by_col_ptr;
2654 	TDS_SMALLINT *src_by_col_ptr;
2655 	int i;
2656 
2657 	tdsdump_log(TDS_DBG_FUNC, "ct_compute_info(%p, %d, %d, %p, %d, %p)\n", cmd, type, colnum, buffer, buflen, outlen);
2658 
2659 	tdsdump_log(TDS_DBG_FUNC, "ct_compute_info() type = %d, colnum = %d\n", type, colnum);
2660 
2661 	if (!cmd->con || !cmd->con->tds_socket)
2662 		return CS_FAIL;
2663 
2664 	tds = cmd->con->tds_socket;
2665 	resinfo = tds->current_results;
2666 
2667 	switch (type) {
2668 	case CS_BYLIST_LEN:
2669 		if (!resinfo) {
2670 			int_val = 0;
2671 		} else {
2672 			int_val = resinfo->by_cols;
2673 		}
2674 		memcpy(buffer, &int_val, sizeof(CS_INT));
2675 		if (outlen)
2676 			*outlen = sizeof(CS_INT);
2677 		break;
2678 	case CS_COMP_BYLIST:
2679 		if (buflen < (CS_INT) (resinfo->by_cols * sizeof(CS_SMALLINT))) {
2680 			return CS_FAIL;
2681 		} else {
2682 			dest_by_col_ptr = (CS_SMALLINT *) buffer;
2683 			src_by_col_ptr = resinfo->bycolumns;
2684 			for (i = 0; i < resinfo->by_cols; i++) {
2685 				*dest_by_col_ptr = *src_by_col_ptr;
2686 				dest_by_col_ptr++;
2687 				src_by_col_ptr++;
2688 			}
2689 			if (outlen)
2690 				*outlen = (resinfo->by_cols * sizeof(CS_SMALLINT));
2691 		}
2692 		break;
2693 	case CS_COMP_COLID:
2694 		if (!resinfo) {
2695 			int_val = 0;
2696 		} else {
2697 			curcol = resinfo->columns[colnum - 1];
2698 			int_val = curcol->column_operand;
2699 		}
2700 		memcpy(buffer, &int_val, sizeof(CS_INT));
2701 		if (outlen)
2702 			*outlen = sizeof(CS_INT);
2703 		break;
2704 	case CS_COMP_ID:
2705 		if (!resinfo) {
2706 			int_val = 0;
2707 		} else {
2708 			int_val = resinfo->computeid;
2709 		}
2710 		memcpy(buffer, &int_val, sizeof(CS_INT));
2711 		if (outlen)
2712 			*outlen = sizeof(CS_INT);
2713 		break;
2714 	case CS_COMP_OP:
2715 		if (!resinfo) {
2716 			int_val = 0;
2717 		} else {
2718 			curcol = resinfo->columns[colnum - 1];
2719 			int_val = curcol->column_operator;
2720 		}
2721 		memcpy(buffer, &int_val, sizeof(CS_INT));
2722 		if (outlen)
2723 			*outlen = sizeof(CS_INT);
2724 		break;
2725 	default:
2726         _csclient_msg(cmd->con->ctx, "ct_compute_info", 2, 1, 16, 32,
2727                       "%d", type);
2728 		return CS_FAIL;
2729 		break;
2730 	}
2731 	return CS_SUCCEED;
2732 }
2733 
2734 CS_RETCODE
ct_get_data(CS_COMMAND * cmd,CS_INT item,CS_VOID * buffer,CS_INT buflen,CS_INT * outlen)2735 ct_get_data(CS_COMMAND * cmd, CS_INT item, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
2736 {
2737 	TDSRESULTINFO *resinfo;
2738 	TDSCOLUMN *curcol;
2739 	unsigned char *src;
2740 	TDS_INT srclen;
2741 
2742 	tdsdump_log(TDS_DBG_FUNC, "ct_get_data(%p, %d, %p, %d, %p)\n", cmd, item, buffer, buflen, outlen);
2743 
2744 	tdsdump_log(TDS_DBG_FUNC, "ct_get_data() item = %d buflen = %d\n", item, buflen);
2745 
2746 	if (cmd->cancel_state == _CS_CANCEL_PENDING) {
2747 		_ct_cancel_cleanup(cmd);
2748 		return CS_CANCELED;
2749 	}
2750 
2751 	/* basic validations... */
2752 
2753 	if (!cmd || !cmd->con || !cmd->con->tds_socket || !(resinfo = cmd->con->tds_socket->current_results))
2754 		return CS_FAIL;
2755 	if (item < 1 || item > resinfo->num_cols)
2756 		return CS_FAIL;
2757 	if (buffer == NULL)
2758 		return CS_FAIL;
2759 	if (buflen == CS_UNUSED)
2760 		return CS_FAIL;
2761 
2762 	/* This is a new column we are being asked to return */
2763 
2764 	if (item != cmd->get_data_item) {
2765 		TDSBLOB *blob = NULL;
2766         TDS_INT table_namelen, column_namelen;
2767 
2768 		/* allocare needed descriptor if needed */
2769 		free(cmd->iodesc);
2770 		cmd->iodesc = (CS_IODESC*) calloc(1, sizeof(CS_IODESC));
2771 		if (!cmd->iodesc)
2772 			return CS_FAIL;
2773 
2774 		/* reset these values */
2775 		cmd->get_data_item = item;
2776 		cmd->get_data_bytes_returned = 0;
2777 
2778 		/* get at the source data and length */
2779 		curcol = resinfo->columns[item - 1];
2780 
2781 		src = curcol->column_data;
2782 		if (is_blob_col(curcol)) {
2783 			blob = (TDSBLOB *) src;
2784 			src = (unsigned char *) blob->textvalue;
2785 		}
2786 
2787 		/* now populate the io_desc structure for this data item */
2788 
2789 		cmd->iodesc->iotype = CS_IODATA;
2790 		cmd->iodesc->datatype = curcol->column_type;
2791 		cmd->iodesc->locale = cmd->con->locale;
2792 		cmd->iodesc->usertype = curcol->column_usertype;
2793 		cmd->iodesc->total_txtlen = curcol->column_cur_size;
2794 		cmd->iodesc->offset = 0;
2795 		cmd->iodesc->log_on_update = CS_FALSE;
2796 
2797 		/* TODO quote needed ?? */
2798 		/* avoid possible buffer overflow */
2799 		table_namelen = tds_dstr_len(&curcol->table_name);
2800 		if (table_namelen + 2 > sizeof(cmd->iodesc->name))
2801 			table_namelen = sizeof(cmd->iodesc->name) - 2;
2802 		column_namelen = tds_dstr_len(&curcol->column_name);
2803 		if (table_namelen + column_namelen + 2 > sizeof(cmd->iodesc->name))
2804 			column_namelen = sizeof(cmd->iodesc->name) - 2 - table_namelen;
2805 
2806 #if 0 /* can be slow */
2807 		sprintf(cmd->iodesc->name, "%*.*s.%*.*s",
2808 			(int) table_namelen, (int) table_namelen, tds_dstr_cstr(&curcol->table_name),
2809 			(int) column_namelen, (int) column_namelen, tds_dstr_cstr(&curcol->column_name));
2810 
2811 		cmd->iodesc->namelen = strlen(cmd->iodesc->name);
2812 #else /* faster */
2813         if (table_namelen) {
2814             memcpy(cmd->iodesc->name, tds_dstr_cstr(&curcol->table_name),
2815                    table_namelen);
2816             cmd->iodesc->namelen = table_namelen;
2817         } else {
2818             cmd->iodesc->namelen = 0;
2819         }
2820 
2821         cmd->iodesc->name[cmd->iodesc->namelen] = '.';
2822         ++cmd->iodesc->namelen;
2823 
2824         if (column_namelen) {
2825             memcpy(cmd->iodesc->name + cmd->iodesc->namelen,
2826                    tds_dstr_cstr(&curcol->column_name), column_namelen);
2827             cmd->iodesc->namelen += column_namelen;
2828         }
2829 
2830         cmd->iodesc->name[cmd->iodesc->namelen] = '\0';
2831 #endif
2832 
2833 		if (blob && blob->valid_ptr) {
2834 			memcpy(cmd->iodesc->timestamp, blob->timestamp, CS_TS_SIZE);
2835 			cmd->iodesc->timestamplen = CS_TS_SIZE;
2836 			memcpy(cmd->iodesc->textptr, blob->textptr, CS_TP_SIZE);
2837 			cmd->iodesc->textptrlen = CS_TP_SIZE;
2838 		}
2839 	} else {
2840 		/* get at the source data */
2841 		curcol = resinfo->columns[item - 1];
2842 		src = curcol->column_data;
2843 		if (is_blob_col(curcol))
2844 			src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
2845 
2846 	}
2847 
2848 	/*
2849 	 * and adjust the data and length based on
2850 	 * what we may have already returned
2851 	 */
2852 
2853 	srclen = curcol->column_cur_size;
2854     if (srclen < 0) {
2855         /* this is NULL */
2856         if (outlen)
2857             *outlen = srclen;
2858         if (item < resinfo->num_cols)
2859             return CS_END_ITEM;
2860         return CS_END_DATA;
2861     }
2862 
2863 	src += cmd->get_data_bytes_returned;
2864 	srclen -= cmd->get_data_bytes_returned;
2865 
2866 	/* if we have enough buffer to cope with all the data */
2867 
2868 	if (buflen >= srclen) {
2869 		memcpy(buffer, src, srclen);
2870 		cmd->get_data_bytes_returned += srclen;
2871 		if (outlen)
2872 			*outlen = srclen;
2873 		if (item < resinfo->num_cols)
2874 			return CS_END_ITEM;
2875 		return CS_END_DATA;
2876 
2877 	}
2878 	memcpy(buffer, src, buflen);
2879 	cmd->get_data_bytes_returned += buflen;
2880 	if (outlen)
2881 		*outlen = buflen;
2882 	return CS_SUCCEED;
2883 }
2884 
2885 CS_RETCODE
ct_send_data(CS_COMMAND * cmd,CS_VOID * buffer,CS_INT buflen)2886 ct_send_data(CS_COMMAND * cmd, CS_VOID * buffer, CS_INT buflen)
2887 {
2888 	TDSSOCKET *tds;
2889 
2890 	char textptr_string[35];	/* 16 * 2 + 2 (0x) + 1 */
2891 	char timestamp_string[19];	/* 8 * 2 + 2 (0x) + 1 */
2892 	char *c;
2893 	int s;
2894 	char hex2[3];
2895 
2896 	tdsdump_log(TDS_DBG_FUNC, "ct_send_data(%p, %p, %d)\n", cmd, buffer, buflen);
2897 
2898 	if (!cmd->con || !cmd->con->tds_socket)
2899 		return CS_FAIL;
2900 
2901 	tds = cmd->con->tds_socket;
2902 
2903 	/* basic validations */
2904 
2905 	if (cmd->command_type != CS_SEND_DATA_CMD)
2906 		return CS_FAIL;
2907 
2908 	if (!cmd->iodesc || !cmd->iodesc->textptrlen)
2909 		return CS_FAIL;
2910 
2911 	/* first ct_send_data for this column */
2912 
2913 	if (!cmd->send_data_started) {
2914 
2915 		/* turn the timestamp and textptr into character format */
2916 
2917 		c = textptr_string;
2918 
2919 		for (s = 0; s < cmd->iodesc->textptrlen; s++) {
2920 			sprintf(hex2, "%02x", cmd->iodesc->textptr[s]);
2921 			*c++ = hex2[0];
2922 			*c++ = hex2[1];
2923 		}
2924 		*c = '\0';
2925 
2926 		c = timestamp_string;
2927 
2928 		for (s = 0; s < cmd->iodesc->timestamplen; s++) {
2929 			sprintf(hex2, "%02x", cmd->iodesc->timestamp[s]);
2930 			*c++ = hex2[0];
2931 			*c++ = hex2[1];
2932 		}
2933 		*c = '\0';
2934 
2935 		/* submit the writetext command */
2936 		if (TDS_FAILED(tds_writetext_start(tds, cmd->iodesc->name,
2937 			textptr_string, timestamp_string, (cmd->iodesc->log_on_update == CS_TRUE), cmd->iodesc->total_txtlen)))
2938 			return CS_FAIL;
2939 
2940 		cmd->send_data_started = 1;
2941 	}
2942 
2943 	if (TDS_FAILED(tds_writetext_continue(tds, (const TDS_UCHAR*) buffer, buflen)))
2944 		return CS_FAIL;
2945 
2946 	return CS_SUCCEED;
2947 }
2948 
2949 CS_RETCODE
ct_data_info(CS_COMMAND * cmd,CS_INT action,CS_INT colnum,CS_IODESC * iodesc)2950 ct_data_info(CS_COMMAND * cmd, CS_INT action, CS_INT colnum, CS_IODESC * iodesc)
2951 {
2952 	TDSSOCKET *tds;
2953 	TDSRESULTINFO *resinfo;
2954 
2955 	tdsdump_log(TDS_DBG_FUNC, "ct_data_info(%p, %d, %d, %p)\n", cmd, action, colnum, iodesc);
2956 
2957 	if (!cmd->con || !cmd->con->tds_socket)
2958 		return CS_FAIL;
2959 
2960 	tds = cmd->con->tds_socket;
2961 	resinfo = tds->current_results;
2962 
2963 	switch (action) {
2964 	case CS_SET:
2965 		if (iodesc->timestamplen < 0 || iodesc->timestamplen > CS_TS_SIZE)
2966 			return CS_FAIL;
2967 		if (iodesc->textptrlen < 0 || iodesc->textptrlen > CS_TP_SIZE)
2968 			return CS_FAIL;
2969 		free(cmd->iodesc);
2970 		cmd->iodesc = (CS_IODESC*) calloc(1, sizeof(CS_IODESC));
2971 
2972 		cmd->iodesc->iotype = CS_IODATA;
2973 
2974         /* cmd->iodesc->datatype = iodesc->datatype; */
2975         cmd->iodesc->datatype = _ct_get_server_type(tds, iodesc->datatype);
2976 
2977 		cmd->iodesc->locale = cmd->con->locale;
2978 		cmd->iodesc->usertype = iodesc->usertype;
2979 		cmd->iodesc->total_txtlen = iodesc->total_txtlen;
2980 		cmd->iodesc->offset = iodesc->offset;
2981 		cmd->iodesc->log_on_update = iodesc->log_on_update;
2982 		strcpy(cmd->iodesc->name, iodesc->name);
2983 		cmd->iodesc->namelen = iodesc->namelen;
2984 		memcpy(cmd->iodesc->timestamp, iodesc->timestamp, iodesc->timestamplen);
2985 		cmd->iodesc->timestamplen = iodesc->timestamplen;
2986 		memcpy(cmd->iodesc->textptr, iodesc->textptr, iodesc->textptrlen);
2987 		cmd->iodesc->textptrlen = iodesc->textptrlen;
2988 		break;
2989 
2990 	case CS_GET:
2991 
2992 		if (colnum < 1 || colnum > resinfo->num_cols)
2993 			return CS_FAIL;
2994 		if (colnum != cmd->get_data_item)
2995 			return CS_FAIL;
2996 
2997 		iodesc->iotype = cmd->iodesc->iotype;
2998 
2999         /* iodesc->datatype = cmd->iodesc->datatype; */
3000         iodesc->datatype = _ct_get_client_type(cmd->con->ctx,
3001                                                resinfo->columns[colnum - 1]);
3002 
3003 		iodesc->locale = cmd->iodesc->locale;
3004 		iodesc->usertype = cmd->iodesc->usertype;
3005 		iodesc->total_txtlen = cmd->iodesc->total_txtlen;
3006 		iodesc->offset = cmd->iodesc->offset;
3007 		iodesc->log_on_update = CS_FALSE;
3008 		strcpy(iodesc->name, cmd->iodesc->name);
3009 		iodesc->namelen = cmd->iodesc->namelen;
3010 		memcpy(iodesc->timestamp, cmd->iodesc->timestamp, cmd->iodesc->timestamplen);
3011 		iodesc->timestamplen = cmd->iodesc->timestamplen;
3012 		memcpy(iodesc->textptr, cmd->iodesc->textptr, cmd->iodesc->textptrlen);
3013 		iodesc->textptrlen = cmd->iodesc->textptrlen;
3014 		break;
3015 
3016 	default:
3017 		return CS_FAIL;
3018 	}
3019 
3020 	return CS_SUCCEED;
3021 }
3022 
3023 CS_RETCODE
ct_capability(CS_CONNECTION * con,CS_INT action,CS_INT type,CS_INT capability,CS_VOID * value)3024 ct_capability(CS_CONNECTION * con, CS_INT action, CS_INT type, CS_INT capability, CS_VOID * value)
3025 {
3026 	TDSLOGIN *login;
3027 	int idx = 0;
3028 	unsigned char bitmask = 0;
3029 	TDS_CAPABILITY_TYPE *cap = NULL;
3030 
3031 	tdsdump_log(TDS_DBG_FUNC, "ct_capability(%p, %d, %d, %d, %p)\n", con, action, type, capability, value);
3032 
3033 	login = (TDSLOGIN *) con->tds_login;
3034 
3035 #define CONV_CAP(ct,tds) case ct: idx=tds; break;
3036 	if (type == CS_CAP_RESPONSE) {
3037 		cap = &login->capabilities.types[1];
3038 		switch (capability) {
3039 		CONV_CAP(CS_DATA_NOBOUNDARY,	TDS_RES_DATA_NOBOUNDARY);
3040 		CONV_CAP(CS_RES_NOTDSDEBUG,	TDS_RES_NOTDSDEBUG);
3041 		CONV_CAP(CS_RES_NOSTRIPBLANKS,	TDS_RES_NOSTRIPBLANKS);
3042 		CONV_CAP(CS_DATA_NOINT8,	TDS_RES_DATA_NOINT8);
3043 
3044 		CONV_CAP(CS_DATA_NOINTN,	TDS_RES_DATA_INTN);
3045 		CONV_CAP(CS_DATA_NODATETIMEN,	TDS_RES_DATA_NODATETIMEN);
3046 		CONV_CAP(CS_DATA_NOMONEYN,	TDS_RES_DATA_NOMONEYN);
3047 		CONV_CAP(CS_CON_NOOOB,		TDS_RES_CON_NOOOB);
3048 		CONV_CAP(CS_CON_NOINBAND,	TDS_RES_CON_NOINBAND);
3049 		CONV_CAP(CS_PROTO_NOTEXT,	TDS_RES_PROTO_NOTEXT);
3050 		CONV_CAP(CS_PROTO_NOBULK,	TDS_RES_PROTO_NOBULK);
3051 		CONV_CAP(CS_DATA_NOSENSITIVITY,	TDS_RES_DATA_NOSENSITIVITY);
3052 
3053 		CONV_CAP(CS_DATA_NOFLT4,	TDS_RES_DATA_NOFLT4);
3054 		CONV_CAP(CS_DATA_NOFLT8,	TDS_RES_DATA_NOFLT8);
3055 		CONV_CAP(CS_DATA_NONUM,		TDS_RES_DATA_NONUM);
3056 		CONV_CAP(CS_DATA_NOTEXT,	TDS_RES_DATA_NOTEXT);
3057 		CONV_CAP(CS_DATA_NOIMAGE,	TDS_RES_DATA_NOIMAGE);
3058 		CONV_CAP(CS_DATA_NODEC,		TDS_RES_DATA_NODEC);
3059 		CONV_CAP(CS_DATA_NOLCHAR,	TDS_RES_DATA_NOLCHAR);
3060 		CONV_CAP(CS_DATA_NOLBIN,	TDS_RES_DATA_NOLBIN);
3061 
3062 		CONV_CAP(CS_DATA_NOCHAR,	TDS_RES_DATA_NOCHAR);
3063 		CONV_CAP(CS_DATA_NOVCHAR,	TDS_RES_DATA_NOVCHAR);
3064 		CONV_CAP(CS_DATA_NOBIN,		TDS_RES_DATA_NOBIN);
3065 		CONV_CAP(CS_DATA_NOVBIN,	TDS_RES_DATA_NOVBIN);
3066 		CONV_CAP(CS_DATA_NOMNY8,	TDS_RES_DATA_NOMNY8);
3067 		CONV_CAP(CS_DATA_NOMNY4,	TDS_RES_DATA_NOMNY4);
3068 		CONV_CAP(CS_DATA_NODATE8,	TDS_RES_DATA_NODATE8);
3069 		CONV_CAP(CS_DATA_NODATE4,	TDS_RES_DATA_NODATE4);
3070 
3071 		CONV_CAP(CS_RES_NOMSG,		TDS_RES_NOMSG);
3072 		CONV_CAP(CS_RES_NOEED,		TDS_RES_NOEED);
3073 		CONV_CAP(CS_RES_NOPARAM,	TDS_RES_NOPARAM);
3074 		CONV_CAP(CS_DATA_NOINT1,	TDS_RES_DATA_NOINT1);
3075 		CONV_CAP(CS_DATA_NOINT2,	TDS_RES_DATA_NOINT2);
3076 		CONV_CAP(CS_DATA_NOINT4,	TDS_RES_DATA_NOINT4);
3077 		CONV_CAP(CS_DATA_NOBIT,		TDS_RES_DATA_NOBIT);
3078 		} /* end capability */
3079 	} /* End handling CS_CAP_RESPONSE (returned) */
3080 
3081 	/*
3082 	 * Begin handling CS_CAP_REQUEST
3083 	 * These capabilities describe the types of requests that a server can support.
3084 	 */
3085 	if (type == CS_CAP_REQUEST) {
3086 		if (action == CS_SET) {
3087 			tdsdump_log(TDS_DBG_SEVERE,
3088 				    "ct_capability -- attempt to set a read-only capability (type %d, action %d)\n",
3089 				    type, action);
3090 			return CS_FAIL;
3091 		}
3092 
3093 		cap = &login->capabilities.types[0];
3094 		switch (capability) {
3095 		CONV_CAP(CS_PROTO_DYNPROC,	TDS_REQ_PROTO_DYNPROC);
3096 		CONV_CAP(CS_DATA_FLTN,		TDS_REQ_DATA_FLTN);
3097 		CONV_CAP(CS_DATA_BITN,		TDS_REQ_DATA_BITN);
3098 		CONV_CAP(CS_DATA_INT8,		TDS_REQ_DATA_INT8);
3099 		CONV_CAP(CS_DATA_VOID,		TDS_REQ_DATA_VOID);
3100 
3101 		CONV_CAP(CS_CON_INBAND,		TDS_REQ_CON_INBAND);
3102 		CONV_CAP(CS_CON_LOGICAL,	TDS_REQ_CON_LOGICAL);
3103 		CONV_CAP(CS_PROTO_TEXT,		TDS_REQ_PROTO_TEXT);
3104 		CONV_CAP(CS_PROTO_BULK,		TDS_REQ_PROTO_BULK);
3105 		CONV_CAP(CS_REQ_URGNOTIF,	TDS_REQ_URGEVT);
3106 		CONV_CAP(CS_DATA_SENSITIVITY,	TDS_REQ_DATA_SENSITIVITY);
3107 		CONV_CAP(CS_DATA_BOUNDARY,	TDS_REQ_DATA_BOUNDARY);
3108 		CONV_CAP(CS_PROTO_DYNAMIC,	TDS_REQ_PROTO_DYNAMIC);
3109 
3110 		CONV_CAP(CS_DATA_MONEYN,	TDS_REQ_DATA_MONEYN);
3111 		CONV_CAP(CS_CSR_PREV,		TDS_REQ_CSR_PREV);
3112 		CONV_CAP(CS_CSR_FIRST,		TDS_REQ_CSR_FIRST);
3113 		CONV_CAP(CS_CSR_LAST,		TDS_REQ_CSR_LAST);
3114 		CONV_CAP(CS_CSR_ABS,		TDS_REQ_CSR_ABS);
3115 		CONV_CAP(CS_CSR_REL,		TDS_REQ_CSR_REL);
3116 		CONV_CAP(CS_CSR_MULTI,		TDS_REQ_CSR_MULTI);
3117 		CONV_CAP(CS_CON_OOB,		TDS_REQ_CON_OOB);
3118 
3119 		CONV_CAP(CS_DATA_NUM,		TDS_REQ_DATA_NUM);
3120 		CONV_CAP(CS_DATA_TEXT,		TDS_REQ_DATA_TEXT);
3121 		CONV_CAP(CS_DATA_IMAGE,		TDS_REQ_DATA_IMAGE);
3122 		CONV_CAP(CS_DATA_DEC,		TDS_REQ_DATA_DEC);
3123 		CONV_CAP(CS_DATA_LCHAR,		TDS_REQ_DATA_LCHAR);
3124 		CONV_CAP(CS_DATA_LBIN,		TDS_REQ_DATA_LBIN);
3125 		CONV_CAP(CS_DATA_INTN,		TDS_REQ_DATA_INTN);
3126 		CONV_CAP(CS_DATA_DATETIMEN,	TDS_REQ_DATA_DATETIMEN);
3127 
3128 		CONV_CAP(CS_DATA_BIN,		TDS_REQ_DATA_BIN);
3129 		CONV_CAP(CS_DATA_VBIN,		TDS_REQ_DATA_VBIN);
3130 		CONV_CAP(CS_DATA_MNY8,		TDS_REQ_DATA_MNY8);
3131 		CONV_CAP(CS_DATA_MNY4,		TDS_REQ_DATA_MNY4);
3132 		CONV_CAP(CS_DATA_DATE8,		TDS_REQ_DATA_DATE8);
3133 		CONV_CAP(CS_DATA_DATE4,		TDS_REQ_DATA_DATE4);
3134 		CONV_CAP(CS_DATA_FLT4,		TDS_REQ_DATA_FLT4);
3135 		CONV_CAP(CS_DATA_FLT8,		TDS_REQ_DATA_FLT8);
3136 
3137 		CONV_CAP(CS_REQ_MSG,		TDS_REQ_MSG);
3138 		CONV_CAP(CS_REQ_PARAM,		TDS_REQ_PARAM);
3139 		CONV_CAP(CS_DATA_INT1,		TDS_REQ_DATA_INT1);
3140 		CONV_CAP(CS_DATA_INT2,		TDS_REQ_DATA_INT2);
3141 		CONV_CAP(CS_DATA_INT4,		TDS_REQ_DATA_INT4);
3142 		CONV_CAP(CS_DATA_BIT,		TDS_REQ_DATA_BIT);
3143 		CONV_CAP(CS_DATA_CHAR,		TDS_REQ_DATA_CHAR);
3144 		CONV_CAP(CS_DATA_VCHAR,		TDS_REQ_DATA_VCHAR);
3145 
3146 		CONV_CAP(CS_REQ_LANG,		TDS_REQ_LANG);
3147 		CONV_CAP(CS_REQ_RPC,		TDS_REQ_RPC);
3148 		CONV_CAP(CS_REQ_NOTIF,		TDS_REQ_EVT);
3149 		CONV_CAP(CS_REQ_MSTMT,		TDS_REQ_MSTMT);
3150 		CONV_CAP(CS_REQ_BCP,		TDS_REQ_BCP);
3151 		CONV_CAP(CS_REQ_CURSOR,		TDS_REQ_CURSOR);
3152 		CONV_CAP(CS_REQ_DYN,		TDS_REQ_DYNF);
3153 		} /* end capability */
3154 	} /* End handling CS_CAP_REQUEST */
3155 #undef CONV_CAP
3156 
3157 	if (cap == NULL) {
3158 		tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown capability type\n");
3159 		return CS_FAIL;
3160 	}
3161 	if (idx == 0) {
3162 		tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- attempt to set/get a non-existant capability\n");
3163 		return CS_FAIL;
3164 	}
3165 
3166 	bitmask = 1 << (idx&7);
3167 	idx = sizeof(cap->values) - 1 - (idx>>3);
3168 	assert(0 <= idx && idx <= sizeof(cap->values));
3169 
3170 	switch (action) {
3171 	case CS_SET:
3172 		/* Having established the offset and the bitmask, we can now turn the capability on or off */
3173 		switch (*(CS_BOOL *) value) {
3174 		case CS_TRUE:
3175 			cap->values[idx] |= bitmask;
3176 			break;
3177 		case CS_FALSE:
3178 			cap->values[idx] &= ~bitmask;
3179 			break;
3180 		default:
3181 			tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown value\n");
3182 			return CS_FAIL;
3183 		}
3184 		break;
3185 	case CS_GET:
3186 		*(CS_BOOL *) value = (cap->values[idx] & bitmask) ? CS_TRUE : CS_FALSE;
3187 		break;
3188 	default:
3189 		tdsdump_log(TDS_DBG_SEVERE, "ct_capability -- unknown action\n");
3190 		return CS_FAIL;
3191 	}
3192 	return CS_SUCCEED;
3193 } /* end ct_capability */
3194 
3195 
3196 CS_RETCODE
ct_dynamic(CS_COMMAND * cmd,CS_INT type,CS_CHAR * id,CS_INT idlen,CS_CHAR * buffer,CS_INT buflen)3197 ct_dynamic(CS_COMMAND * cmd, CS_INT type, CS_CHAR * id, CS_INT idlen, CS_CHAR * buffer, CS_INT buflen)
3198 {
3199     size_t query_len;
3200 	CS_CONNECTION *con;
3201 	CS_DYNAMIC *dyn;
3202 
3203 	tdsdump_log(TDS_DBG_FUNC, "ct_dynamic(%p, %d, %p, %d, %p, %d)\n", cmd, type, id, idlen, buffer, buflen);
3204 
3205 	if (!cmd->con)
3206 		return CS_FAIL;
3207 
3208 	cmd->command_type = CS_DYNAMIC_CMD;
3209 	cmd->dynamic_cmd = type;
3210 
3211 	con = cmd->con;
3212 
3213 	switch (type) {
3214 	case CS_PREPARE:
3215 
3216 		dyn = _ct_allocate_dynamic(con, id, idlen);
3217 
3218 		if (dyn == NULL) {
3219 			return CS_FAIL;
3220 		}
3221 
3222 		/* now the query */
3223 		if (buflen == CS_NULLTERM) {
3224 			query_len = strlen(buffer);
3225 		} else {
3226 			query_len = buflen;
3227 		}
3228 		dyn->stmt = (char *) malloc(query_len + 1);
3229 		strncpy(dyn->stmt, (char *) buffer, query_len);
3230 		dyn->stmt[query_len] = '\0';
3231 
3232 		cmd->dyn = dyn;
3233 
3234 		break;
3235 	case CS_DEALLOC:
3236 		cmd->dyn = _ct_locate_dynamic(con, id, idlen);
3237 		if (cmd->dyn == NULL)
3238 			return CS_FAIL;
3239 		break;
3240 	case CS_DESCRIBE_INPUT:
3241 	case CS_DESCRIBE_OUTPUT:
3242 		cmd->dyn = _ct_locate_dynamic(con, id, idlen);
3243 		if (cmd->dyn == NULL)
3244 			return CS_FAIL;
3245 		break;
3246 	case CS_EXECUTE:
3247 		cmd->dyn = _ct_locate_dynamic(con, id, idlen);
3248 		if (cmd->dyn == NULL)
3249 			return CS_FAIL;
3250 
3251 		tdsdump_log(TDS_DBG_FUNC, "ct_dynamic() calling param_clear\n");
3252 		param_clear(cmd->dyn->param_list);
3253 		cmd->dyn->param_list = NULL;
3254 		break;
3255 	}
3256 
3257 	ct_set_command_state(cmd, _CS_COMMAND_READY);
3258 	return CS_SUCCEED;
3259 }
3260 
3261 CS_RETCODE
ct_param(CS_COMMAND * cmd,CS_DATAFMT * datafmt,CS_VOID * data,CS_INT datalen,CS_SMALLINT indicator)3262 ct_param(CS_COMMAND * cmd, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT datalen, CS_SMALLINT indicator)
3263 {
3264 	CSREMOTE_PROC *rpc;
3265 	CS_DYNAMIC *dyn;
3266 	CS_PARAM **pparam;
3267 	CS_PARAM *param;
3268     int /* bool */ promote = (datafmt->datatype == CS_VARCHAR_TYPE  ||
3269                               datafmt->datatype == CS_LONGCHAR_TYPE);
3270 
3271 	tdsdump_log(TDS_DBG_FUNC, "ct_param(%p, %p, %p, %d, %hd)\n", cmd, datafmt, data, datalen, indicator);
3272 
3273 	tdsdump_log(TDS_DBG_INFO1, "ct_param() data addr = %p data length = %d\n", data, datalen);
3274 
3275     if (cmd == NULL  ||  cmd->con == NULL)
3276 		return CS_FAIL;
3277 
3278     if (promote  &&  IS_TDS7_PLUS(cmd->con->tds_socket->conn)) {
3279         /* Actually promote only if non-ASCII characters are present */
3280         CS_INT i;
3281 
3282         promote = 0;
3283         for (i = 0;  i < datalen;  ++i) {
3284             if (((const char*)data)[i] & 0x80) {
3285                 promote = 1;
3286                 break;
3287             }
3288         }
3289 
3290         if ( !promote ) {
3291             /* pure ASCII, leave as is */
3292         } else if (datafmt->datatype == CS_VARCHAR_TYPE) {
3293             datafmt->datatype = CS_NVARCHAR_TYPE;
3294         } else if (datafmt->datatype == CS_LONGCHAR_TYPE) {
3295             datafmt->datatype = CS_NLONGCHAR_TYPE;
3296         }
3297     }
3298 
3299 
3300 
3301 	switch (cmd->command_type) {
3302 	case CS_RPC_CMD:
3303 		if (cmd->rpc == NULL) {
3304             tdsdump_log(TDS_DBG_ERROR, "RPC is NULL ct_param\n");
3305 			return CS_FAIL;
3306 		}
3307 
3308 		param = (CSREMOTE_PROC_PARAM *) calloc(1, sizeof(CSREMOTE_PROC_PARAM));
3309 		if (!param)
3310 			return CS_FAIL;
3311 
3312 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
3313 			tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add rpc param\n");
3314 			tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add input value\n");
3315 			free(param);
3316 			return CS_FAIL;
3317 		}
3318 
3319 		rpc = cmd->rpc;
3320 		pparam = &rpc->param_list;
3321 		while (*pparam) {
3322 			pparam = &(*pparam)->next;
3323 		}
3324 
3325 		*pparam = param;
3326 		tdsdump_log(TDS_DBG_INFO1, " ct_param() added rpc parameter %s \n", (*param).name);
3327 		return CS_SUCCEED;
3328 		break;
3329 
3330 	case CS_LANG_CMD:
3331 		/* only accept CS_INPUTVALUE as the status */
3332 		if (CS_INPUTVALUE != datafmt->status) {
3333 			tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_param()\n", datafmt->status);
3334 			return CS_FAIL;
3335 		}
3336 
3337 		param = (CSREMOTE_PROC_PARAM *) calloc(1, sizeof(CSREMOTE_PROC_PARAM));
3338 
3339 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
3340 			free(param);
3341 			return CS_FAIL;
3342 		}
3343 
3344 		if (NULL == cmd->input_params)
3345 			cmd->input_params = param;
3346 		else {
3347 			pparam = &cmd->input_params;
3348 			while ((*pparam)->next)
3349 				pparam = &(*pparam)->next;
3350 			(*pparam)->next = param;
3351 		}
3352 		tdsdump_log(TDS_DBG_INFO1, "ct_param() added input value\n");
3353 		return CS_SUCCEED;
3354 		break;
3355 
3356 	case CS_DYNAMIC_CMD:
3357 		if (cmd->dyn == NULL) {
3358 			tdsdump_log(TDS_DBG_INFO1, "cmd->dyn is NULL ct_param\n");
3359 			return CS_FAIL;
3360 		}
3361 
3362 		param = (CS_DYNAMIC_PARAM *) calloc(1, sizeof(CS_DYNAMIC_PARAM));
3363 		if (!param)
3364 			return CS_FAIL;
3365 
3366 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, &datalen, &indicator, 1)) {
3367 			tdsdump_log(TDS_DBG_INFO1, "ct_param() failed to add CS_DYNAMIC param\n");
3368 			free(param);
3369 			return CS_FAIL;
3370 		}
3371 
3372 		dyn = cmd->dyn;
3373 		pparam = &dyn->param_list;
3374 		while (*pparam) {
3375 			pparam = &(*pparam)->next;
3376 		}
3377 
3378 		*pparam = param;
3379 		return CS_SUCCEED;
3380 		break;
3381 	}
3382 	return CS_FAIL;
3383 }
3384 
3385 CS_RETCODE
ct_setparam(CS_COMMAND * cmd,CS_DATAFMT * datafmt,CS_VOID * data,CS_INT * datalen,CS_SMALLINT * indicator)3386 ct_setparam(CS_COMMAND * cmd, CS_DATAFMT * datafmt, CS_VOID * data, CS_INT * datalen, CS_SMALLINT * indicator)
3387 {
3388 	CSREMOTE_PROC *rpc;
3389 	CS_PARAM **pparam;
3390 	CS_PARAM *param;
3391 	CS_DYNAMIC *dyn;
3392 
3393 	tdsdump_log(TDS_DBG_FUNC, "ct_setparam(%p, %p, %p, %p, %p)\n", cmd, datafmt, data, datalen, indicator);
3394 
3395 	tdsdump_log(TDS_DBG_FUNC, "ct_setparam() command type = %d, data type = %d\n", cmd->command_type, datafmt->datatype);
3396 
3397 	/* Code changed for RPC functionality - SUHA */
3398 	/* RPC code changes starts here */
3399 
3400 	if (cmd == NULL)
3401 		return CS_FAIL;
3402 
3403 	switch (cmd->command_type) {
3404 
3405 	case CS_RPC_CMD:
3406 
3407 		if (cmd->rpc == NULL) {
3408             tdsdump_log(TDS_DBG_ERROR, "RPC is NULL in ct_setparam\n");
3409 			return CS_FAIL;
3410 		}
3411 
3412 		param = (CSREMOTE_PROC_PARAM *) calloc(1, sizeof(CSREMOTE_PROC_PARAM));
3413 
3414 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
3415 			tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add rpc param\n");
3416 			tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add input value\n");
3417 			free(param);
3418 			return CS_FAIL;
3419 		}
3420 
3421 		rpc = cmd->rpc;
3422 		pparam = &rpc->param_list;
3423 		tdsdump_log(TDS_DBG_INFO1, " ct_setparam() reached here\n");
3424 		if (*pparam != NULL) {
3425 			while ((*pparam)->next != NULL) {
3426 				pparam = &(*pparam)->next;
3427 			}
3428 
3429 			pparam = &(*pparam)->next;
3430 		}
3431 		*pparam = param;
3432 		param->next = NULL;
3433 		tdsdump_log(TDS_DBG_INFO1, " ct_setparam() added parameter %s \n", (*param).name);
3434 		return CS_SUCCEED;
3435 		break;
3436 
3437 	case CS_DYNAMIC_CMD :
3438 
3439 		if (cmd->dyn == NULL) {
3440             tdsdump_log(TDS_DBG_ERROR, "cmd->dyn is NULL in ct_setparam\n");
3441 			return CS_FAIL;
3442 		}
3443 
3444 		param = (CS_DYNAMIC_PARAM *) calloc(1, sizeof(CS_DYNAMIC_PARAM));
3445 
3446 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
3447 			tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add dynamic param\n");
3448 			free(param);
3449 			return CS_FAIL;
3450 		}
3451 
3452 		dyn = cmd->dyn;
3453 		pparam = &dyn->param_list;
3454 		if (*pparam != NULL) {
3455 			while ((*pparam)->next != NULL) {
3456 				pparam = &(*pparam)->next;
3457 			}
3458 
3459 			pparam = &(*pparam)->next;
3460 		}
3461 		*pparam = param;
3462 		param->next = NULL;
3463 		tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added dynamic parameter\n");
3464 		return CS_SUCCEED;
3465 		break;
3466 
3467 	case CS_LANG_CMD:
3468 
3469 		/* only accept CS_INPUTVALUE as the status */
3470 		if (CS_INPUTVALUE != datafmt->status) {
3471 			tdsdump_log(TDS_DBG_ERROR, "illegal datafmt->status(%d) passed to ct_setparam()\n", datafmt->status);
3472 			return CS_FAIL;
3473 		}
3474 
3475 		param = (CSREMOTE_PROC_PARAM *) calloc(1, sizeof(CSREMOTE_PROC_PARAM));
3476 
3477 		if (CS_SUCCEED != _ct_fill_param(cmd->command_type, param, datafmt, data, datalen, indicator, 0)) {
3478 			tdsdump_log(TDS_DBG_INFO1, "ct_setparam() failed to add language param\n");
3479 			free(param);
3480 			return CS_FAIL;
3481 		}
3482 
3483 		if (NULL == cmd->input_params)
3484 			cmd->input_params = param;
3485 		else {
3486 			pparam = &cmd->input_params;
3487 			while ((*pparam)->next)
3488 				pparam = &(*pparam)->next;
3489 			(*pparam)->next = param;
3490 		}
3491 		tdsdump_log(TDS_DBG_INFO1, "ct_setparam() added language parameter\n");
3492 		return CS_SUCCEED;
3493 		break;
3494 	}
3495 	return CS_FAIL;
3496 }
3497 
3498 CS_RETCODE
ct_options(CS_CONNECTION * con,CS_INT action,CS_INT option,CS_VOID * param,CS_INT paramlen,CS_INT * outlen)3499 ct_options(CS_CONNECTION * con, CS_INT action, CS_INT option, CS_VOID * param, CS_INT paramlen, CS_INT * outlen)
3500 {
3501 	TDS_OPTION_CMD tds_command = 0;
3502 	TDS_OPTION tds_option = 0;
3503 	TDS_OPTION_ARG tds_argument;
3504 	TDS_INT tds_argsize = 0;
3505 	TDSSOCKET *tds;
3506 
3507 	const char *action_string = NULL;
3508 	int i;
3509 
3510 	/* boolean options can all be treated the same way */
3511 	static const struct TDS_BOOL_OPTION_MAP
3512 	{
3513 		CS_INT option;
3514 		TDS_OPTION tds_option;
3515 	} tds_bool_option_map[] = {
3516 		  { CS_OPT_ANSINULL,       TDS_OPT_ANSINULL       }
3517 		, { CS_OPT_CHAINXACTS,     TDS_OPT_CHAINXACTS     }
3518 		, { CS_OPT_CURCLOSEONXACT, TDS_OPT_CURCLOSEONXACT }
3519 		, { CS_OPT_FIPSFLAG,       TDS_OPT_FIPSFLAG       }
3520 		, { CS_OPT_FORCEPLAN,      TDS_OPT_FORCEPLAN      }
3521 		, { CS_OPT_FORMATONLY,     TDS_OPT_FORMATONLY     }
3522 		, { CS_OPT_GETDATA,        TDS_OPT_GETDATA        }
3523 		, { CS_OPT_NOCOUNT,        TDS_OPT_NOCOUNT        }
3524 		, { CS_OPT_NOEXEC,         TDS_OPT_NOEXEC         }
3525 		, { CS_OPT_PARSEONLY,      TDS_OPT_PARSEONLY      }
3526 		, { CS_OPT_QUOTED_IDENT,   TDS_OPT_QUOTED_IDENT   }
3527 		, { CS_OPT_RESTREES,       TDS_OPT_RESTREES       }
3528 		, { CS_OPT_SHOWPLAN,       TDS_OPT_SHOWPLAN       }
3529 		, { CS_OPT_STATS_IO,       TDS_OPT_STAT_IO        }
3530 		, { CS_OPT_STATS_TIME,     TDS_OPT_STAT_TIME      }
3531 	};
3532 
3533 	tdsdump_log(TDS_DBG_FUNC, "ct_options(%p, %d, %d, %p, %d, %p)\n", con, action, option, param, paramlen, outlen);
3534 
3535 	if (param == NULL)
3536 		return CS_FAIL;
3537 
3538 	tds = con->tds_socket;
3539 
3540 	/*
3541 	 * Set the tds command
3542 	 */
3543 	switch (action) {
3544 	case CS_GET:
3545 		tds_command = TDS_OPT_LIST;	/* will be acknowledged by TDS_OPT_INFO */
3546 		action_string = "CS_GET";
3547 		tds_argsize = 0;
3548 		break;
3549 	case CS_SET:
3550 		tds_command = TDS_OPT_SET;
3551 		action_string = "CS_SET";
3552 		break;
3553 	case CS_CLEAR:
3554 		tds_command = TDS_OPT_DEFAULT;
3555 		action_string = "CS_CLEAR";
3556 		tds_argsize = 0;
3557 		break;
3558 	default:
3559 		tdsdump_log(TDS_DBG_FUNC, "ct_options: invalid action = %d\n", action);
3560 		return CS_FAIL;
3561 	}
3562 
3563 	assert(tds_command && action_string);
3564 
3565 	tdsdump_log(TDS_DBG_FUNC, "ct_options: %s, option = %d\n", action_string, option);
3566 
3567 	/*
3568 	 * Set the tds option
3569 	 *      The following TDS options apparently cannot be set with this function.
3570 	 *      TDS_OPT_CHARSET
3571 	 *      TDS_OPT_CURREAD
3572 	 *      TDS_OPT_IDENTITYOFF
3573 	 *      TDS_OPT_IDENTITYON
3574 	 *      TDS_OPT_CURWRITE
3575 	 *      TDS_OPT_NATLANG
3576 	 *      TDS_OPT_ROWCOUNT
3577 	 *      TDS_OPT_TEXTSIZE
3578 	 */
3579 
3580 	/*
3581 	 * First, take care of the easy cases, the booleans.
3582 	 */
3583 	for (i = 0; i < TDS_VECTOR_SIZE(tds_bool_option_map); i++) {
3584 		if (tds_bool_option_map[i].option == option) {
3585 			tds_option = tds_bool_option_map[i].tds_option;
3586 			break;
3587 		}
3588 	}
3589 
3590 	if (tds_option != 0) {	/* found a boolean */
3591 		if (action == CS_SET) {
3592 			switch (*(CS_BOOL *) param) {
3593 			case CS_TRUE:
3594 				tds_argument.ti = 1;
3595 				break;
3596 			case CS_FALSE:
3597 				tds_argument.ti = 0;
3598 				break;
3599 			default:
3600 				return CS_FAIL;
3601 			}
3602 			tds_argsize = 1;
3603 		}
3604 		if (action == CS_GET) {
3605 			tds_argsize = 0;
3606 		}
3607 		goto SEND_OPTION;
3608 	}
3609 
3610 	/*
3611 	 * Non-booleans are more complicated.
3612 	 */
3613 	switch (option) {
3614 	case CS_OPT_ANSIPERM:
3615 	case CS_OPT_STR_RTRUNC:
3616 		/* no documented tds option */
3617 		switch (*(CS_BOOL *) param) {
3618 		case CS_TRUE:
3619 		case CS_FALSE:
3620 			break;	/* end valid choices */
3621 		default:
3622 			if (action == CS_SET)
3623 				return CS_FAIL;
3624 		}
3625 		break;
3626 	case CS_OPT_ARITHABORT:
3627 		switch (*(CS_BOOL *) param) {
3628 		case CS_TRUE:
3629 			tds_option = TDS_OPT_ARITHABORTON;
3630 			break;
3631 		case CS_FALSE:
3632 			tds_option = TDS_OPT_ARITHABORTOFF;
3633 			break;
3634 		default:
3635 			if (action == CS_SET)
3636 				return CS_FAIL;
3637 			tds_option = TDS_OPT_ARITHABORTON;
3638 		}
3639 		tds_argument.ti = TDS_OPT_ARITHOVERFLOW | TDS_OPT_NUMERICTRUNC;
3640 		tds_argsize = (action == CS_SET) ? 1 : 0;
3641 		break;
3642 	case CS_OPT_ARITHIGNORE:
3643 		switch (*(CS_BOOL *) param) {
3644 		case CS_TRUE:
3645 			tds_option = TDS_OPT_ARITHIGNOREON;
3646 			break;
3647 		case CS_FALSE:
3648 			tds_option = TDS_OPT_ARITHIGNOREOFF;
3649 			break;
3650 		default:
3651 			if (action == CS_SET)
3652 				return CS_FAIL;
3653 		}
3654 		tds_argument.i = TDS_OPT_ARITHOVERFLOW | TDS_OPT_NUMERICTRUNC;
3655 		tds_argsize = (action == CS_SET) ? 4 : 0;
3656 		break;
3657 	case CS_OPT_AUTHOFF:
3658 		tds_option = TDS_OPT_AUTHOFF;
3659 		tds_argument.c = (TDS_CHAR *) param;
3660 		tds_argsize = (action == CS_SET) ? paramlen : 0;
3661 		break;
3662 	case CS_OPT_AUTHON:
3663 		tds_option = TDS_OPT_AUTHON;
3664 		tds_argument.c = (TDS_CHAR *) param;
3665 		tds_argsize = (action == CS_SET) ? paramlen : 0;
3666 		break;
3667 
3668 	case CS_OPT_DATEFIRST:
3669 		tds_option = TDS_OPT_DATEFIRST;
3670 		switch (*(CS_INT *) param) {
3671 		case CS_OPT_SUNDAY:
3672 			tds_argument.ti = TDS_OPT_SUNDAY;
3673 			break;
3674 		case CS_OPT_MONDAY:
3675 			tds_argument.ti = TDS_OPT_MONDAY;
3676 			break;
3677 		case CS_OPT_TUESDAY:
3678 			tds_argument.ti = TDS_OPT_TUESDAY;
3679 			break;
3680 		case CS_OPT_WEDNESDAY:
3681 			tds_argument.ti = TDS_OPT_WEDNESDAY;
3682 			break;
3683 		case CS_OPT_THURSDAY:
3684 			tds_argument.ti = TDS_OPT_THURSDAY;
3685 			break;
3686 		case CS_OPT_FRIDAY:
3687 			tds_argument.ti = TDS_OPT_FRIDAY;
3688 			break;
3689 		case CS_OPT_SATURDAY:
3690 			tds_argument.ti = TDS_OPT_SATURDAY;
3691 			break;
3692 		default:
3693 			if (action == CS_SET)
3694 				return CS_FAIL;
3695 		}
3696 		tds_argsize = (action == CS_SET) ? 1 : 0;
3697 		break;
3698 	case CS_OPT_DATEFORMAT:
3699 		tds_option = TDS_OPT_DATEFORMAT;
3700 		switch (*(CS_INT *) param) {
3701 		case CS_OPT_FMTMDY:
3702 			tds_argument.ti = TDS_OPT_FMTMDY;
3703 			break;
3704 		case CS_OPT_FMTDMY:
3705 			tds_argument.ti = TDS_OPT_FMTDMY;
3706 			break;
3707 		case CS_OPT_FMTYMD:
3708 			tds_argument.ti = TDS_OPT_FMTYMD;
3709 			break;
3710 		case CS_OPT_FMTYDM:
3711 			tds_argument.ti = TDS_OPT_FMTYDM;
3712 			break;
3713 		case CS_OPT_FMTMYD:
3714 			tds_argument.ti = TDS_OPT_FMTMYD;
3715 			break;
3716 		case CS_OPT_FMTDYM:
3717 			tds_argument.ti = TDS_OPT_FMTDYM;
3718 			break;
3719 		default:
3720 			if (action == CS_SET)
3721 				return CS_FAIL;
3722 		}
3723 		tds_argsize = (action == CS_SET) ? 1 : 0;
3724 		break;
3725 	case CS_OPT_ISOLATION:
3726 		tds_option = TDS_OPT_ISOLATION;
3727 		switch (*(char *) param) {
3728 		case CS_OPT_LEVEL0:	/* CS_OPT_LEVEL0 requires SQL Server version 11.0 or later or Adaptive Server. */
3729 			/* no documented value */
3730 			tds_option = 0;
3731 			tds_argument.ti = 0;
3732 			break;
3733 		case CS_OPT_LEVEL1:
3734 			tds_argument.ti = TDS_OPT_LEVEL1;
3735 		case CS_OPT_LEVEL3:
3736 			tds_argument.ti = TDS_OPT_LEVEL3;
3737 			break;
3738 		default:
3739 			if (action == CS_SET)
3740 				return CS_FAIL;
3741 		}
3742 		tds_argsize = (action == CS_SET) ? 1 : 0;
3743 		break;
3744 	case CS_OPT_TRUNCIGNORE:
3745 		tds_option = TDS_OPT_TRUNCABORT;	/* note inverted sense */
3746 		switch (*(CS_BOOL *) param) {
3747 		case CS_TRUE:
3748 		case CS_FALSE:
3749 			break;
3750 		default:
3751 			if (action == CS_SET)
3752 				return CS_FAIL;
3753 		}
3754 		tds_argument.ti = !*(char *) param;
3755 		tds_argsize = (action == CS_SET) ? 1 : 0;
3756 		break;
3757 	default:
3758 		return CS_FAIL;	/* invalid option */
3759 	}
3760 
3761 SEND_OPTION:
3762 
3763 	tdsdump_log(TDS_DBG_FUNC, "\ttds_submit_optioncmd will be action(%s) option(%d) arg(%x) arglen(%d)\n",
3764 				action_string, tds_option,
3765 				tds_argsize == 1 ? tds_argument.ti : (tds_argsize == 4 ? tds_argument.i : 0), tds_argsize);
3766 
3767 	if (TDS_FAILED(tds_submit_optioncmd(tds, tds_command, tds_option, &tds_argument, tds_argsize))) {
3768 		return CS_FAIL;
3769 	}
3770 
3771 	if (action == CS_GET) {
3772 		switch (option) {
3773 		case CS_OPT_ANSINULL :
3774 		case CS_OPT_CHAINXACTS :
3775 		case CS_OPT_CURCLOSEONXACT :
3776 		case CS_OPT_NOCOUNT :
3777 		case CS_OPT_QUOTED_IDENT :
3778 			*(CS_BOOL *)param = tds->option_value;
3779 			break;
3780 		case CS_OPT_DATEFIRST:
3781 			switch (tds->option_value) {
3782 			case TDS_OPT_SUNDAY: *(CS_INT *)param = CS_OPT_SUNDAY; break;
3783 			case TDS_OPT_MONDAY: *(CS_INT *)param = CS_OPT_MONDAY; break;
3784 			case TDS_OPT_TUESDAY: *(CS_INT *)param = CS_OPT_TUESDAY; break;
3785 			case TDS_OPT_WEDNESDAY: *(CS_INT *)param = CS_OPT_WEDNESDAY; break;
3786 			case TDS_OPT_THURSDAY: *(CS_INT *)param = CS_OPT_THURSDAY; break;
3787 			case TDS_OPT_FRIDAY: *(CS_INT *)param = CS_OPT_FRIDAY; break;
3788 			case TDS_OPT_SATURDAY: *(CS_INT *)param = CS_OPT_SATURDAY; break;
3789 			default: return CS_FAIL;
3790 			}
3791 			break;
3792 		case CS_OPT_DATEFORMAT:
3793 			switch (tds->option_value) {
3794 			case TDS_OPT_FMTDMY: *(CS_INT *)param = CS_OPT_FMTDMY; break;
3795 			case TDS_OPT_FMTDYM: *(CS_INT *)param = CS_OPT_FMTDYM; break;
3796 			case TDS_OPT_FMTMDY: *(CS_INT *)param = CS_OPT_FMTMDY; break;
3797 			case TDS_OPT_FMTMYD: *(CS_INT *)param = CS_OPT_FMTMYD; break;
3798 			case TDS_OPT_FMTYMD: *(CS_INT *)param = CS_OPT_FMTYMD; break;
3799 			case TDS_OPT_FMTYDM: *(CS_INT *)param = CS_OPT_FMTYDM; break;
3800 			default: return CS_FAIL;
3801 			}
3802 			break;
3803 		case CS_OPT_ARITHABORT :
3804 		case CS_OPT_ARITHIGNORE :
3805 			*(CS_BOOL *)param = tds->option_value;
3806 			break;
3807 		case CS_OPT_TRUNCIGNORE :
3808 			break;
3809 		}
3810 	}
3811 
3812 	return CS_SUCCEED;
3813 }				/* end ct_options() */
3814 
3815 CS_RETCODE
ct_poll(CS_CONTEXT * ctx,CS_CONNECTION * connection,CS_INT milliseconds,CS_CONNECTION ** compconn,CS_COMMAND ** compcmd,CS_INT * compid,CS_INT * compstatus)3816 ct_poll(CS_CONTEXT * ctx, CS_CONNECTION * connection, CS_INT milliseconds, CS_CONNECTION ** compconn, CS_COMMAND ** compcmd,
3817 	CS_INT * compid, CS_INT * compstatus)
3818 {
3819 	tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED ct_poll()\n");
3820 	tdsdump_log(TDS_DBG_FUNC, "ct_poll(%p, %p, %d, %p, %p, %p, %p)\n",
3821 				ctx, connection, milliseconds, compconn, compcmd, compid, compstatus);
3822 
3823 	return CS_FAIL;
3824 }
3825 
3826 static
str_icmp(char * s1,char * s2,int len)3827 int str_icmp(char* s1, char* s2, int len)
3828 {
3829     int i;
3830 
3831     for (i = 0; i < len; ++i) {
3832         char c1 = s1[i];
3833         char c2 = s2[i];
3834 
3835         if (c1 >= 'a' && c1 <= 'z') {
3836             c1 -= 'a'-'A';
3837         }
3838 
3839         if (c2 >= 'a' && c2 <= 'z') {
3840             c2 -= 'a'-'A';
3841         }
3842 
3843         if (c1 == c2) {
3844             if (c1 == '\0') {
3845                 return 0;
3846             }
3847         } else {
3848             if (c1 < c2) {
3849                 return -1;
3850             } else {
3851                 return 1;
3852             }
3853         }
3854     }
3855 
3856     return 0;
3857 }
3858 
3859 static
get_next_tok(char * str,char * delimiter,char ** ptrptr)3860 char* get_next_tok(char* str, char* delimiter, char **ptrptr)
3861 {
3862     char* result = NULL;
3863     *ptrptr = NULL;
3864 
3865     if (str && delimiter) {
3866         size_t str_len = strlen(str);
3867 
3868         size_t pos = strspn(str, delimiter);
3869 
3870         if (pos == 0) {
3871             *ptrptr = strpbrk(str, delimiter);
3872             return str;
3873         } else {
3874             if (pos != str_len) {
3875                 result = str + pos;
3876                 *ptrptr = strpbrk(result, delimiter);
3877             }
3878         }
3879     }
3880 
3881     return result;
3882 }
3883 
3884 CS_RETCODE
ct_cursor(CS_COMMAND * cmd,CS_INT type,CS_CHAR * name,CS_INT namelen,CS_CHAR * text,CS_INT tlen,CS_INT option)3885 ct_cursor(CS_COMMAND * cmd, CS_INT type, CS_CHAR * name, CS_INT namelen, CS_CHAR * text, CS_INT tlen, CS_INT option)
3886 {
3887 	TDSSOCKET *tds;
3888 	TDSCURSOR *cursor;
3889 
3890 	tdsdump_log(TDS_DBG_FUNC, "ct_cursor(%p, %d, %p, %d, %p, %d, %d)\n", cmd, type, name, namelen, text, tlen, option);
3891 
3892 	if (!cmd->con || !cmd->con->tds_socket)
3893 		return CS_FAIL;
3894 
3895 	tds = cmd->con->tds_socket;
3896 	cmd->command_type = CS_CUR_CMD;
3897 
3898 	tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : type = %d \n", type);
3899 
3900 	switch (type) {
3901 	case CS_CURSOR_DECLARE:
3902 
3903 		cursor = tds_alloc_cursor(tds, name, namelen == CS_NULLTERM ? strlen(name) : namelen,
3904 						text, tlen == CS_NULLTERM ? strlen(text) : tlen);
3905 		if (!cursor)
3906 			return CS_FAIL;
3907 
3908 		cursor->cursor_rows = 1;
3909 		cursor->options = option;
3910 		cursor->status.declare    = _CS_CURS_TYPE_REQUESTED;
3911 		cursor->status.cursor_row = _CS_CURS_TYPE_UNACTIONED;
3912 		cursor->status.open       = _CS_CURS_TYPE_UNACTIONED;
3913 		cursor->status.fetch      = _CS_CURS_TYPE_UNACTIONED;
3914 		cursor->status.close      = _CS_CURS_TYPE_UNACTIONED;
3915 		cursor->status.dealloc    = _CS_CURS_TYPE_UNACTIONED;
3916 
3917         if (option == CS_UNUSED || (option & CS_END) != 0) {
3918             /* Try to figure out type of the cursor. */
3919             char delimiter[] = "\n\t,.[]() ";
3920             int state = 0;
3921             char* savept = NULL;
3922             char* s = text;
3923 
3924             char* tok = get_next_tok(s, delimiter, &savept);
3925             while (tok != NULL) {
3926                 s = savept;
3927 
3928                 if (str_icmp(tok, "FOR", 3) == 0) {
3929                     state = 1;
3930                 } else if (str_icmp(tok, "UPDATE", 6) == 0) {
3931                     if (state == 1) {
3932                         state = 2;
3933                         break;
3934                     }
3935                 } else {
3936                     state = 0;
3937                 }
3938 
3939                 tok = get_next_tok(s, delimiter, &savept);
3940             }
3941 
3942             if (state == 2) {
3943                 /* FOR UPDATE */
3944                 cursor->type = 0x4; /* Forward-only cursor. */
3945             } else {
3946                 /* readonly */
3947                 cursor->type = 0x1; /* Keyset-driven cursor. Default value. */
3948             }
3949         } else if ((option & CS_FOR_UPDATE) != 0) {
3950             cursor->type = 0x4; /* Forward-only cursor. */
3951         } else {
3952             cursor->type = 0x1; /* Keyset-driven cursor. Default value. */
3953         }
3954 
3955         cursor->concurrency = 0x2004;
3956         /* Optimistic. Checks timestamps and, when not available, values. */
3957 
3958 		tds_release_cursor(&cmd->cursor);
3959 		cmd->cursor = cursor;
3960 		ct_set_command_state(cmd, _CS_COMMAND_READY);
3961 		return CS_SUCCEED;
3962 		break;
3963 
3964  	case CS_CURSOR_ROWS:
3965 
3966 		cursor = cmd->cursor;
3967 		if (!cursor) {
3968 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
3969 			return CS_FAIL;
3970 		}
3971 
3972 		if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
3973 			cursor->status.declare == _CS_CURS_TYPE_SENT) {
3974 
3975 			cursor->cursor_rows = option;
3976 			cursor->status.cursor_row = _CS_CURS_TYPE_REQUESTED;
3977 
3978 			ct_set_command_state(cmd, _CS_COMMAND_READY);
3979 			return CS_SUCCEED;
3980 		}
3981 		else {
3982 			cursor->status.cursor_row  = _CS_CURS_TYPE_UNACTIONED;
3983 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
3984 			return CS_FAIL;
3985 		}
3986 		break;
3987 
3988 	case CS_CURSOR_OPEN:
3989 
3990 		cursor = cmd->cursor;
3991 		if (!cursor) {
3992 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
3993 			return CS_FAIL;
3994 		}
3995 
3996 		if (cursor->status.declare == _CS_CURS_TYPE_REQUESTED ||
3997 			cursor->status.declare == _CS_CURS_TYPE_SENT ) {
3998 
3999 			cursor->status.open  = _CS_CURS_TYPE_REQUESTED;
4000 
4001 			return CS_SUCCEED;
4002 			ct_set_command_state(cmd, _CS_COMMAND_READY);
4003 		}
4004 		else {
4005 			cursor->status.open = _CS_CURS_TYPE_UNACTIONED;
4006 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not declared\n");
4007 			return CS_FAIL;
4008 		}
4009 
4010 		break;
4011 
4012 	case CS_CURSOR_CLOSE:
4013 
4014 		cursor = cmd->cursor;
4015 		if (!cursor) {
4016 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
4017 			return CS_FAIL;
4018 		}
4019 
4020 		cursor->status.cursor_row = _CS_CURS_TYPE_UNACTIONED;
4021 		cursor->status.open       = _CS_CURS_TYPE_UNACTIONED;
4022 		cursor->status.fetch      = _CS_CURS_TYPE_UNACTIONED;
4023 		cursor->status.close      = _CS_CURS_TYPE_REQUESTED;
4024 		if (option == CS_DEALLOC) {
4025 		 	cursor->status.dealloc   = _CS_CURS_TYPE_REQUESTED;
4026 		}
4027 		ct_set_command_state(cmd, _CS_COMMAND_READY);
4028 		return CS_SUCCEED;
4029 
4030 	case CS_CURSOR_DEALLOC:
4031 
4032 		cursor = cmd->cursor;
4033 		if (!cursor) {
4034 			tdsdump_log(TDS_DBG_FUNC, "ct_cursor() : cursor not present\n");
4035 			return CS_FAIL;
4036 		}
4037 		cursor->status.dealloc   = _CS_CURS_TYPE_REQUESTED;
4038 		ct_set_command_state(cmd, _CS_COMMAND_READY);
4039 		return CS_SUCCEED;
4040 
4041 	case CS_IMPLICIT_CURSOR:
4042 		tdsdump_log(TDS_DBG_INFO1, "CS_IMPLICIT_CURSOR: Option not implemented\n");
4043 		return CS_FAIL;
4044 	case CS_CURSOR_OPTION:
4045 		tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_OPTION: Option not implemented\n");
4046 		return CS_FAIL;
4047 	case CS_CURSOR_UPDATE:
4048 		tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_UPDATE: Option not implemented\n");
4049 		return CS_FAIL;
4050 	case CS_CURSOR_DELETE:
4051 		tdsdump_log(TDS_DBG_INFO1, "CS_CURSOR_DELETE: Option not implemented\n");
4052 		return CS_FAIL;
4053 
4054 	}
4055 
4056 	return CS_FAIL;
4057 }
4058 
4059 static int
_ct_fetchable_results(CS_COMMAND * cmd)4060 _ct_fetchable_results(CS_COMMAND * cmd)
4061 {
4062 	tdsdump_log(TDS_DBG_FUNC, "_ct_fetchable_results(%p)\n", cmd);
4063 
4064 	switch (cmd->curr_result_type) {
4065 	case CS_COMPUTE_RESULT:
4066 	case CS_CURSOR_RESULT:
4067 	case CS_PARAM_RESULT:
4068 	case CS_ROW_RESULT:
4069 	case CS_STATUS_RESULT:
4070 		return 1;
4071 	}
4072 	return 0;
4073 }
4074 
4075 static TDSRET
_ct_process_return_status(TDSSOCKET * tds)4076 _ct_process_return_status(TDSSOCKET * tds)
4077 {
4078 	TDSRESULTINFO *info;
4079 	TDSCOLUMN *curcol;
4080 	TDS_INT saved_status;
4081 	TDSRET rc;
4082 
4083 	enum { num_cols = 1 };
4084 
4085 	tdsdump_log(TDS_DBG_FUNC, "_ct_process_return_status(%p)\n", tds);
4086 
4087 	assert(tds);
4088 	saved_status = tds->ret_status;
4089 	tds_free_all_results(tds);
4090 
4091 	/* allocate the columns structure */
4092 	tds->res_info = tds_alloc_results(num_cols);
4093 	tds_set_current_results(tds, tds->res_info);
4094 
4095 	if (!tds->res_info)
4096 		return TDS_FAIL;
4097 
4098 	info = tds->res_info;
4099 
4100 	curcol = info->columns[0];
4101 
4102 	tds_set_column_type(tds->conn, curcol, SYBINT4);
4103 
4104 	tdsdump_log(TDS_DBG_INFO1, "generating return status row. type = %d(%s), varint_size %d\n",
4105 		    curcol->column_type, tds_prtype(curcol->column_type), curcol->column_varint_size);
4106 
4107 	rc = tds_alloc_row(info);
4108 	if (TDS_FAILED(rc))
4109 		return rc;
4110 
4111 	assert(curcol->column_data != NULL);
4112 
4113 	*(TDS_INT *) curcol->column_data = saved_status;
4114 
4115 	return TDS_SUCCESS;
4116 }
4117 
4118 /* Code added for RPC functionality  - SUHA */
4119 /* RPC code changes starts here */
4120 
4121 static const unsigned char *
paramrowalloc(TDSPARAMINFO * params,TDSCOLUMN * curcol,int param_num,void * value,int size)4122 paramrowalloc(TDSPARAMINFO * params, TDSCOLUMN * curcol, int param_num, void *value, int size)
4123 {
4124 	const void *row = tds_alloc_param_data(curcol);
4125 
4126 	tdsdump_log(TDS_DBG_INFO1, "paramrowalloc, size = %d, data = %p, row_size = %d\n",
4127 				size, curcol->column_data, params->row_size);
4128 	if (!row)
4129 		return NULL;
4130 
4131 	if (value) {
4132 		/* TODO check for BLOB and numeric */
4133 		if (size > curcol->column_size) {
4134 			tdsdump_log(TDS_DBG_FUNC, "paramrowalloc(): RESIZE %d to %d\n", size, curcol->column_size);
4135 			size = curcol->column_size;
4136 		}
4137 		/* TODO blobs */
4138 		if (!is_blob_col(curcol))
4139 			memcpy(curcol->column_data, value, size);
4140 		else {
4141 			TDSBLOB *blob = (TDSBLOB *) curcol->column_data;
4142             blob->textvalue = (TDS_CHAR*) malloc(size ? size : 1);
4143 			tdsdump_log(TDS_DBG_FUNC, "blob parameter supported, size %d textvalue pointer is %p\n",
4144 					size, blob->textvalue);
4145 			if (!blob->textvalue)
4146 				return NULL;
4147 			memcpy(blob->textvalue, value, size);
4148 		}
4149 		curcol->column_cur_size = size;
4150 	} else {
4151 		tdsdump_log(TDS_DBG_FUNC, "paramrowalloc(): setting parameter #%d to NULL\n", param_num);
4152 		curcol->column_cur_size = -1;
4153 	}
4154 
4155 	return (const unsigned char*) row;
4156 }
4157 
4158 /**
4159  * Allocate memory and copy the rpc information into a TDSPARAMINFO structure.
4160  */
4161 static TDSPARAMINFO *
paraminfoalloc(TDSSOCKET * tds,CS_PARAM * first_param)4162 paraminfoalloc(TDSSOCKET * tds, CS_PARAM * first_param)
4163 {
4164 	int i;
4165 	CS_PARAM *p;
4166 	TDSCOLUMN *pcol;
4167 	TDSPARAMINFO *params = NULL, *new_params;
4168 
4169     int temp_type;
4170     TDS_SERVER_TYPE tds_type;
4171 
4172 	tdsdump_log(TDS_DBG_FUNC, "paraminfoalloc(%p, %p)\n", tds, first_param);
4173 
4174 	/* sanity */
4175 	if (first_param == NULL)
4176 		return NULL;
4177 
4178 	for (i = 0, p = first_param; p != NULL; p = p->next, i++) {
4179 		const unsigned char *prow;
4180 		CS_BYTE *temp_value = NULL;
4181 		CS_INT temp_datalen = 0;
4182 
4183 		if (!(new_params = tds_alloc_param_result(params)))
4184 			goto memory_error;
4185 		params = new_params;
4186 
4187 		/*
4188 		 * The parameteter data has been passed by reference
4189 		 * i.e. using ct_setparam rather than ct_param
4190 		 */
4191 		temp_type = p->datatype;
4192 		tds_type = _ct_get_server_type(tds, p->datatype);
4193 		if (p->param_by_value == 0) {
4194 
4195 			/*
4196 			 * there are three ways to indicate null parameters
4197 			 * 1) *ind == -1
4198 			 * 2) *datalen == 0
4199 			 * 3) value, datalen and ind as NULL. Here value == NULL is
4200 			 *    sufficient
4201 			 */
4202 			if (*(p->ind) != -1 && p->value != NULL && *(p->datalen) != 0) {
4203 				/* datafmt.datalen is ignored for fixed length types */
4204 				if (is_fixed_type(tds_type)) {
4205 					temp_datalen = tds_get_size_by_type(tds_type);
4206 				} else {
4207 					temp_datalen = (*(p->datalen) == CS_UNUSED) ? 0 : *(p->datalen);
4208 				}
4209 
4210 				temp_value = p->value;
4211 			}
4212 		} else {
4213 			temp_value = p->value;
4214 			temp_datalen = *(p->datalen);
4215 		}
4216 
4217         if (temp_type == CS_VARCHAR_TYPE || temp_type == CS_NVARCHAR_TYPE ||
4218             temp_type == CS_VARBINARY_TYPE) {
4219 			CS_VARCHAR *vc = (CS_VARCHAR *) temp_value;
4220 
4221 			if (vc) {
4222 				temp_datalen = vc->len;
4223 				temp_value   = (CS_BYTE *) vc->str;
4224 			}
4225 		}
4226 
4227 		pcol = params->columns[i];
4228 
4229 		/* meta data */
4230 		if (p->name)
4231 			if (!tds_dstr_copy(&pcol->column_name, p->name))
4232 				goto memory_error;
4233 
4234 		tds_set_param_type(tds->conn, pcol, tds_type);
4235 
4236 		if (temp_datalen == CS_NULLTERM && temp_value)
4237 			temp_datalen = strlen((const char*) temp_value);
4238 
4239 		pcol->column_prec = p->precision;
4240 		pcol->column_scale = p->scale;
4241 		if (pcol->column_varint_size) {
4242             if ((pcol->column_varint_size == 2  &&  *(p->datalen) > 8000)
4243                 ||  (pcol->column_varint_size == 1  &&  *(p->datalen) > 255)) {
4244                 _csclient_msg(((CS_CONNECTION*)tds_get_parent(tds))->ctx,
4245                               "paraminfoalloc", 2, 1, 10, 25, "");
4246             }
4247 			if (p->maxlen < 0) {
4248 				tds_free_param_results(params);
4249 				return NULL;
4250             } else if (p->maxlen == 0  &&  is_unicode_type(tds_type)) {
4251                 /* Auto-detect; account for possible conversion to UCS-2. */
4252                 p->maxlen = temp_datalen * 2;
4253             }
4254 			pcol->on_server.column_size = pcol->column_size = p->maxlen;
4255 			pcol->column_cur_size = temp_value ? temp_datalen : -1;
4256 			if (temp_datalen > 0 && temp_datalen > p->maxlen)
4257 				pcol->on_server.column_size = pcol->column_size = temp_datalen;
4258 		} else {
4259 			pcol->column_cur_size = pcol->column_size;
4260 		}
4261 
4262 		if (p->status == CS_RETURN)
4263 			pcol->column_output = 1;
4264 		else
4265 			pcol->column_output = 0;
4266 
4267 		/* actual data */
4268 		tdsdump_log(TDS_DBG_FUNC, "paraminfoalloc: status = %d, maxlen %d \n", p->status, p->maxlen);
4269 		tdsdump_log(TDS_DBG_FUNC,
4270 			    "paraminfoalloc: name = %s, varint size %d "
4271 			    "column_type %d size %d, %d column_cur_size %d column_output = %d\n",
4272 			    tds_dstr_cstr(&pcol->column_name),
4273 			    pcol->column_varint_size, pcol->column_type,
4274 			    pcol->on_server.column_size, pcol->column_size,
4275 			    pcol->column_cur_size, pcol->column_output);
4276 		prow = paramrowalloc(params, pcol, i, temp_value, temp_datalen);
4277 		if (!prow)
4278 			goto memory_error;
4279 	}
4280 
4281 	return params;
4282 
4283 memory_error:
4284 	tds_free_param_results(params);
4285     _csclient_msg(((CS_CONNECTION*)tds_get_parent(tds))->ctx,
4286                   "paraminfoalloc", 2, 1, 17, 33, "");
4287 	return NULL;
4288 }
4289 
4290 static void
rpc_clear(CSREMOTE_PROC * rpc)4291 rpc_clear(CSREMOTE_PROC * rpc)
4292 {
4293 	tdsdump_log(TDS_DBG_FUNC, "rpc_clear(%p)\n", rpc);
4294 
4295 	if (rpc == NULL)
4296 		return;
4297 
4298 	param_clear(rpc->param_list);
4299 
4300 	free(rpc->name);
4301 	free(rpc);
4302 }
4303 
4304 /**
4305  * recursively erase the parameter list
4306  */
4307 static void
param_clear(CS_PARAM * pparam)4308 param_clear(CS_PARAM * pparam)
4309 {
4310 	tdsdump_log(TDS_DBG_FUNC, "param_clear(%p)\n", pparam);
4311 
4312 	if (pparam == NULL)
4313 		return;
4314 
4315 	if (pparam->next) {
4316 		param_clear(pparam->next);
4317 		pparam->next = NULL;
4318 	}
4319 
4320 	/* free self after clearing children */
4321 
4322 	free(pparam->name);
4323 	if (pparam->param_by_value)
4324 		free(pparam->value);
4325 
4326 	/*
4327 	 * DO NOT free datalen or ind, they are just pointer
4328 	 * to client data or private structure
4329 	 */
4330 
4331 	free(pparam);
4332 }
4333 
4334 /* RPC Code changes ends here */
4335 
4336 
4337 static int
_ct_fill_param(CS_INT cmd_type,CS_PARAM * param,CS_DATAFMT * datafmt,CS_VOID * data,CS_INT * datalen,CS_SMALLINT * indicator,CS_BYTE byvalue)4338 _ct_fill_param(CS_INT cmd_type, CS_PARAM *param, CS_DATAFMT *datafmt, CS_VOID *data, CS_INT *datalen,
4339 	       CS_SMALLINT *indicator, CS_BYTE byvalue)
4340 {
4341 	int desttype;
4342 
4343 	tdsdump_log(TDS_DBG_FUNC, "_ct_fill_param(%d, %p, %p, %p, %p, %p, %x)\n",
4344 				cmd_type, param, datafmt, data, datalen, indicator, byvalue);
4345 
4346 	if (cmd_type == CS_DYNAMIC_CMD) {
4347 		param->name = NULL;
4348 	} else {
4349 		if (datafmt->namelen == CS_NULLTERM) {
4350 			param->name = strdup(datafmt->name);
4351 			if (param->name == NULL)
4352 				return CS_FAIL;
4353 		} else if (datafmt->namelen > 0) {
4354 			param->name = (char*) calloc(1, datafmt->namelen + 1);
4355 			if (param->name == NULL)
4356 				return CS_FAIL;
4357 			strncpy(param->name, datafmt->name, datafmt->namelen);
4358 		} else {
4359 			param->name = NULL;
4360 		}
4361 	}
4362 
4363 	param->status = datafmt->status;
4364 	tdsdump_log(TDS_DBG_INFO1, " _ct_fill_param() status = %d \n", param->status);
4365 
4366 	/*
4367 	 * translate datafmt.datatype, e.g. CS_SMALLINT_TYPE
4368 	 * to Server type, e.g. SYBINT2
4369 	 */
4370 	desttype = _ct_get_server_type(NULL, datafmt->datatype);
4371 	param->datatype = datafmt->datatype;
4372 
4373 	if (is_numeric_type(desttype)) {
4374 		param->scale = datafmt->scale;
4375 		param->precision = datafmt->precision;
4376 		if (param->scale < 0 || param->precision < 0
4377 		    || param->precision > MAXPRECISION || param->scale > param->precision)
4378 			return CS_FAIL;
4379 	}
4380 
4381 	param->maxlen = datafmt->maxlength;
4382 
4383 	if (is_fixed_type(desttype)) {
4384 		param->maxlen = tds_get_size_by_type(desttype);
4385 	}
4386 
4387 	param->param_by_value = byvalue;
4388 
4389 	if (byvalue) {
4390 		param->datalen = &param->datalen_value;
4391 		*(param->datalen) = *datalen;
4392 
4393 		param->ind = &param->indicator_value;
4394 		*(param->ind) = *indicator;
4395 
4396 		/*
4397 		 * There are two ways to indicate a parameter with a null value:
4398 		 * - Pass indicator as -1. In this case, data and datalen are ignored.
4399 		 * - Pass data as NULL and datalen as 0 or CS_UNUSED
4400 		 */
4401 		if (*indicator == -1 || (data == NULL && (*datalen == 0 || *datalen == CS_UNUSED))) {
4402 			param->value = NULL;
4403 			*(param->datalen) = 0;
4404 		} else {
4405 			/* datafmt.datalen is ignored for fixed length types */
4406 
4407 			if (is_fixed_type(desttype)) {
4408 				*(param->datalen) = tds_get_size_by_type(desttype);
4409 			} else {
4410 				*(param->datalen) = (*datalen == CS_UNUSED) ? 0 : *datalen;
4411 			}
4412 
4413 			if (data) {
4414 				if (*(param->datalen) == CS_NULLTERM) {
4415 					tdsdump_log(TDS_DBG_INFO1,
4416 						    " _ct_fill_param() about to strdup string %u bytes long\n",
4417 						    (unsigned int) strlen((const char*) data));
4418 					*(param->datalen) = strlen((const char*) data);
4419 				} else if (*(param->datalen) < 0) {
4420 					return CS_FAIL;
4421 				}
4422 				param->value = (CS_BYTE*) malloc(*(param->datalen) ? *(param->datalen) : 1);
4423 				if (param->value == NULL)
4424 					return CS_FAIL;
4425 				memcpy(param->value, data, *(param->datalen));
4426 				param->param_by_value = 1;
4427 			} else {
4428 				param->value = NULL;
4429 				*(param->datalen) = 0;
4430 			}
4431 		}
4432 	} else {		/* not by value, i.e. by reference */
4433 		param->datalen = datalen;
4434 		param->ind = indicator;
4435 		param->value = (CS_BYTE*) data;
4436 	}
4437 	return CS_SUCCEED;
4438 }
4439 
4440 /* Code added for ct_diag implementation */
4441 /* Code changes start here - CT_DIAG - 02*/
4442 
4443 CS_RETCODE
ct_diag(CS_CONNECTION * conn,CS_INT operation,CS_INT type,CS_INT idx,CS_VOID * buffer)4444 ct_diag(CS_CONNECTION * conn, CS_INT operation, CS_INT type, CS_INT idx, CS_VOID * buffer)
4445 {
4446 	tdsdump_log(TDS_DBG_FUNC, "ct_diag(%p, %d, %d, %d, %p)\n", conn, operation, type, idx, buffer);
4447 
4448 	switch (operation) {
4449 	case CS_INIT:
4450 		if (conn->ctx->cs_errhandletype == _CS_ERRHAND_CB) {
4451 			/* contrary to the manual page you don't seem to */
4452 			/* be able to turn on inline message handling    */
4453 			/* using cs_diag, once a callback is installed!  */
4454 			return CS_FAIL;
4455 		}
4456 
4457 		conn->ctx->cs_errhandletype = _CS_ERRHAND_INLINE;
4458 
4459 		if (conn->ctx->cs_diag_msglimit_client == 0)
4460 			conn->ctx->cs_diag_msglimit_client = CS_NO_LIMIT;
4461 
4462 		if (conn->ctx->cs_diag_msglimit_server == 0)
4463 			conn->ctx->cs_diag_msglimit_server = CS_NO_LIMIT;
4464 
4465 		if (conn->ctx->cs_diag_msglimit_total == 0)
4466 			conn->ctx->cs_diag_msglimit_total = CS_NO_LIMIT;
4467 
4468 		conn->ctx->_clientmsg_cb = (CS_CLIENTMSG_FUNC) ct_diag_storeclientmsg;
4469 		conn->ctx->_servermsg_cb = (CS_SERVERMSG_FUNC) ct_diag_storeservermsg;
4470 
4471 		break;
4472 
4473 	case CS_MSGLIMIT:
4474 		if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
4475 			return CS_FAIL;
4476 
4477 		if (type == CS_CLIENTMSG_TYPE)
4478 			conn->ctx->cs_diag_msglimit_client = *(CS_INT *) buffer;
4479 
4480 		if (type == CS_SERVERMSG_TYPE)
4481 			conn->ctx->cs_diag_msglimit_server = *(CS_INT *) buffer;
4482 
4483 		if (type == CS_ALLMSG_TYPE)
4484 			conn->ctx->cs_diag_msglimit_total = *(CS_INT *) buffer;
4485 
4486 		break;
4487 
4488 	case CS_CLEAR:
4489 		if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
4490 			return CS_FAIL;
4491 		return _ct_diag_clearmsg(conn->ctx, type);
4492 		break;
4493 
4494 	case CS_GET:
4495 		if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
4496 			return CS_FAIL;
4497 
4498 		if (buffer == NULL)
4499 			return CS_FAIL;
4500 
4501 		if (type == CS_CLIENTMSG_TYPE) {
4502 			if (idx == 0
4503 			    || (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_client))
4504 				return CS_FAIL;
4505 
4506 			return (ct_diag_getclientmsg(conn->ctx, idx, (CS_CLIENTMSG *) buffer));
4507 		}
4508 
4509 		if (type == CS_SERVERMSG_TYPE) {
4510 			if (idx == 0
4511 			    || (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && idx > conn->ctx->cs_diag_msglimit_server))
4512 				return CS_FAIL;
4513 			return (ct_diag_getservermsg(conn->ctx, idx, (CS_SERVERMSG *) buffer));
4514 		}
4515 
4516 		break;
4517 
4518 	case CS_STATUS:
4519 		if (conn->ctx->cs_errhandletype != _CS_ERRHAND_INLINE)
4520 			return CS_FAIL;
4521 		if (buffer == NULL)
4522 			return CS_FAIL;
4523 
4524 		return (ct_diag_countmsg(conn->ctx, type, (CS_INT *) buffer));
4525 		break;
4526 	}
4527 	return CS_SUCCEED;
4528 }
4529 
4530 static CS_INT
ct_diag_storeclientmsg(CS_CONTEXT * context,CS_CONNECTION * conn,CS_CLIENTMSG * message)4531 ct_diag_storeclientmsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_CLIENTMSG * message)
4532 {
4533 	struct cs_diag_msg_client **curptr;
4534 	struct cs_diag_msg_svr **scurptr;
4535 
4536 	CS_INT msg_count = 0;
4537 
4538 	tdsdump_log(TDS_DBG_FUNC, "ct_diag_storeclientmsg(%p, %p, %p)\n", context, conn, message);
4539 
4540 	curptr = &(conn->ctx->clientstore);
4541 
4542 	scurptr = &(conn->ctx->svrstore);
4543 
4544 	/* if we already have a list of messages, go to the end of the list... */
4545 
4546 	while (*curptr != NULL) {
4547 		msg_count++;
4548 		curptr = &((*curptr)->next);
4549 	}
4550 
4551 	/* messages over and above the agreed limit */
4552 	/* are simply discarded...                  */
4553 
4554 	if (conn->ctx->cs_diag_msglimit_client != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_client) {
4555 		return CS_FAIL;
4556 	}
4557 
4558 	/* messages over and above the agreed TOTAL limit */
4559 	/* are simply discarded */
4560 
4561 	if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
4562 		while (*scurptr != NULL) {
4563 			msg_count++;
4564 			scurptr = &((*scurptr)->next);
4565 		}
4566 		if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
4567 			return CS_FAIL;
4568 		}
4569 	}
4570 
4571 	*curptr = (struct cs_diag_msg_client *) malloc(sizeof(struct cs_diag_msg_client));
4572 	if (*curptr == NULL) {
4573 		return CS_FAIL;
4574 	} else {
4575 		(*curptr)->next = NULL;
4576 		(*curptr)->clientmsg = (CS_CLIENTMSG*) malloc(sizeof(CS_CLIENTMSG));
4577 		if ((*curptr)->clientmsg == NULL) {
4578 			return CS_FAIL;
4579 		} else {
4580 			memcpy((*curptr)->clientmsg, message, sizeof(CS_CLIENTMSG));
4581 		}
4582 	}
4583 
4584 	return CS_SUCCEED;
4585 }
4586 
4587 static CS_INT
ct_diag_storeservermsg(CS_CONTEXT * context,CS_CONNECTION * conn,CS_SERVERMSG * message)4588 ct_diag_storeservermsg(CS_CONTEXT * context, CS_CONNECTION * conn, CS_SERVERMSG * message)
4589 {
4590 	struct cs_diag_msg_svr **curptr;
4591 	struct cs_diag_msg_client **ccurptr;
4592 
4593 	CS_INT msg_count = 0;
4594 
4595 	tdsdump_log(TDS_DBG_FUNC, "ct_diag_storeservermsg(%p, %p, %p)\n", context, conn, message);
4596 
4597 	curptr = &(conn->ctx->svrstore);
4598 	ccurptr = &(conn->ctx->clientstore);
4599 
4600 	/* if we already have a list of messages, go to the end of the list...  */
4601 
4602 	while (*curptr != NULL) {
4603 		msg_count++;
4604 		curptr = &((*curptr)->next);
4605 	}
4606 
4607 	/* messages over and above the agreed limit */
4608 	/* are simply discarded...                  */
4609 
4610 	if (conn->ctx->cs_diag_msglimit_server != CS_NO_LIMIT && msg_count >= conn->ctx->cs_diag_msglimit_server) {
4611 		return CS_FAIL;
4612 	}
4613 
4614 	/* messages over and above the agreed TOTAL limit */
4615 	/* are simply discarded...                  */
4616 
4617 	if (conn->ctx->cs_diag_msglimit_total != CS_NO_LIMIT) {
4618 		while (*ccurptr != NULL) {
4619 			msg_count++;
4620 			ccurptr = &((*ccurptr)->next);
4621 		}
4622 		if (msg_count >= conn->ctx->cs_diag_msglimit_total) {
4623 			return CS_FAIL;
4624 		}
4625 	}
4626 
4627 	*curptr = (struct cs_diag_msg_svr *) malloc(sizeof(struct cs_diag_msg_svr));
4628 	if (*curptr == NULL) {
4629 		return CS_FAIL;
4630 	} else {
4631 		(*curptr)->next = NULL;
4632 		(*curptr)->servermsg = (CS_SERVERMSG*) malloc(sizeof(CS_SERVERMSG));
4633 		if ((*curptr)->servermsg == NULL) {
4634 			return CS_FAIL;
4635 		} else {
4636 			memcpy((*curptr)->servermsg, message, sizeof(CS_SERVERMSG));
4637 		}
4638 	}
4639 
4640 	return CS_SUCCEED;
4641 }
4642 
4643 static CS_INT
ct_diag_getclientmsg(CS_CONTEXT * context,CS_INT idx,CS_CLIENTMSG * message)4644 ct_diag_getclientmsg(CS_CONTEXT * context, CS_INT idx, CS_CLIENTMSG * message)
4645 {
4646 	struct cs_diag_msg_client *curptr;
4647 	CS_INT msg_count = 0, msg_found = 0;
4648 
4649 	tdsdump_log(TDS_DBG_FUNC, "ct_diag_getclientmsg(%p, %d, %p)\n", context, idx, message);
4650 
4651 	curptr = context->clientstore;
4652 
4653 	/* if we already have a list of messages, go to the end of the list...  */
4654 
4655 	while (curptr != NULL) {
4656 		msg_count++;
4657 		if (msg_count == idx) {
4658 			msg_found++;
4659 			break;
4660 		}
4661 		curptr = curptr->next;
4662 	}
4663 
4664 	if (msg_found) {
4665 		memcpy(message, curptr->clientmsg, sizeof(CS_CLIENTMSG));
4666 		return CS_SUCCEED;
4667 	}
4668 	return CS_NOMSG;
4669 }
4670 
4671 static CS_INT
ct_diag_getservermsg(CS_CONTEXT * context,CS_INT idx,CS_SERVERMSG * message)4672 ct_diag_getservermsg(CS_CONTEXT * context, CS_INT idx, CS_SERVERMSG * message)
4673 {
4674 	struct cs_diag_msg_svr *curptr;
4675 	CS_INT msg_count = 0, msg_found = 0;
4676 
4677 	tdsdump_log(TDS_DBG_FUNC, "ct_diag_getservermsg(%p, %d, %p)\n", context, idx, message);
4678 
4679 	curptr = context->svrstore;
4680 
4681 	/* if we already have a list of messages, go to the end of the list...  */
4682 
4683 	while (curptr != NULL) {
4684 		msg_count++;
4685 		if (msg_count == idx) {
4686 			msg_found++;
4687 			break;
4688 		}
4689 		curptr = curptr->next;
4690 	}
4691 
4692 	if (msg_found) {
4693 		memcpy(message, curptr->servermsg, sizeof(CS_SERVERMSG));
4694 		return CS_SUCCEED;
4695 	} else {
4696 		return CS_NOMSG;
4697 	}
4698 }
4699 
4700 CS_INT
_ct_diag_clearmsg(CS_CONTEXT * context,CS_INT type)4701 _ct_diag_clearmsg(CS_CONTEXT * context, CS_INT type)
4702 {
4703 	struct cs_diag_msg_client *curptr, *freeptr;
4704 	struct cs_diag_msg_svr *scurptr, *sfreeptr;
4705 
4706 	tdsdump_log(TDS_DBG_FUNC, "_ct_diag_clearmsg(%p, %d)\n", context, type);
4707 
4708 	if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
4709 		curptr = context->clientstore;
4710 		context->clientstore = NULL;
4711 
4712 		while (curptr != NULL) {
4713 			freeptr = curptr;
4714 			curptr = freeptr->next;
4715 			free(freeptr->clientmsg);
4716 			free(freeptr);
4717 		}
4718 	}
4719 
4720 	if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
4721 		scurptr = context->svrstore;
4722 		context->svrstore = NULL;
4723 
4724 		while (scurptr != NULL) {
4725 			sfreeptr = scurptr;
4726 			scurptr = sfreeptr->next;
4727 			free(sfreeptr->servermsg);
4728 			free(sfreeptr);
4729 		}
4730 	}
4731 	return CS_SUCCEED;
4732 }
4733 
4734 static CS_INT
ct_diag_countmsg(CS_CONTEXT * context,CS_INT type,CS_INT * count)4735 ct_diag_countmsg(CS_CONTEXT * context, CS_INT type, CS_INT * count)
4736 {
4737 	struct cs_diag_msg_client *curptr;
4738 	struct cs_diag_msg_svr *scurptr;
4739 
4740 	CS_INT msg_count = 0;
4741 
4742 	tdsdump_log(TDS_DBG_FUNC, "ct_diag_countmsg(%p, %d, %p)\n", context, type, count);
4743 
4744 	if (type == CS_CLIENTMSG_TYPE || type == CS_ALLMSG_TYPE) {
4745 		curptr = context->clientstore;
4746 
4747 		while (curptr != NULL) {
4748 			msg_count++;
4749 			curptr = curptr->next;
4750 		}
4751 	}
4752 
4753 	if (type == CS_SERVERMSG_TYPE || type == CS_ALLMSG_TYPE) {
4754 		scurptr = context->svrstore;
4755 
4756 		while (scurptr != NULL) {
4757 			msg_count++;
4758 			scurptr = scurptr->next;
4759 		}
4760 	}
4761 	*count = msg_count;
4762 
4763 	return CS_SUCCEED;
4764 }
4765 
4766 /* Code changes ends here - CT_DIAG - 02*/
4767 
4768 static CS_DYNAMIC *
_ct_allocate_dynamic(CS_CONNECTION * con,char * id,int idlen)4769 _ct_allocate_dynamic(CS_CONNECTION * con, char *id, int idlen)
4770 {
4771 	CS_DYNAMIC *dyn;
4772 	CS_DYNAMIC **pdyn;
4773     size_t id_len;
4774 
4775 	tdsdump_log(TDS_DBG_FUNC, "_ct_allocate_dynamic(%p, %p, %d)\n", con, id, idlen);
4776 
4777 	dyn = (CS_DYNAMIC *) calloc(1, sizeof(CS_DYNAMIC));
4778 
4779 	if (idlen == CS_NULLTERM)
4780 		id_len = strlen(id);
4781 	else
4782 		id_len = idlen;
4783 
4784 	if (dyn != NULL) {
4785 		dyn->id = (char*) malloc(id_len + 1);
4786 		strncpy(dyn->id, id, id_len);
4787 		dyn->id[id_len] = '\0';
4788 
4789 		if (con->dynlist == NULL) {
4790 			tdsdump_log(TDS_DBG_INFO1, "_ct_allocate_dynamic() attaching dynamic command to head\n");
4791 			con->dynlist = dyn;
4792 		} else {
4793 			pdyn = &con->dynlist;
4794 			while (*pdyn) {
4795 				pdyn = &(*pdyn)->next;
4796 			}
4797 
4798 			*pdyn = dyn;
4799 		}
4800 	}
4801 	return (dyn);
4802 }
4803 
4804 static CS_DYNAMIC *
_ct_locate_dynamic(CS_CONNECTION * con,char * id,int idlen)4805 _ct_locate_dynamic(CS_CONNECTION * con, char *id, int idlen)
4806 {
4807 	CS_DYNAMIC *dyn;
4808     size_t id_len;
4809 
4810 	tdsdump_log(TDS_DBG_FUNC, "_ct_locate_dynamic(%p, %p, %d)\n", con, id, idlen);
4811 
4812 	if (idlen == CS_NULLTERM)
4813 		id_len = strlen(id);
4814 	else
4815 		id_len = idlen;
4816 
4817 	tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() looking for %s\n", (char *) id);
4818 
4819 	for (dyn = con->dynlist; dyn != NULL; dyn = dyn->next) {
4820 		tdsdump_log(TDS_DBG_INFO1, "_ct_locate_dynamic() matching with %s\n", (char *) dyn->id);
4821 		if (strncmp(dyn->id, id, id_len) == 0)
4822 			break;
4823 	}
4824 
4825 	return (dyn);
4826 }
4827 
4828 static CS_INT
_ct_deallocate_dynamic(CS_CONNECTION * con,CS_DYNAMIC * dyn)4829 _ct_deallocate_dynamic(CS_CONNECTION * con, CS_DYNAMIC *dyn)
4830 {
4831 	CS_DYNAMIC_LIST **pvictim;
4832 
4833 	tdsdump_log(TDS_DBG_FUNC, "_ct_deallocate_dynamic(%p, %p)\n", con, dyn);
4834 
4835 	if (!dyn)
4836 		return CS_SUCCEED;
4837 
4838 	pvictim = &con->dynlist;
4839 	for (; *pvictim != dyn;) {
4840 		if (*pvictim == NULL) {
4841 			tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : cannot find entry in list\n");
4842 			return CS_FAIL;
4843 		}
4844 		pvictim = &(*pvictim)->next;
4845 	}
4846 
4847 	/* detach node */
4848 	tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinking list\n");
4849 	*pvictim = dyn->next;
4850 	dyn->next = NULL;
4851 	tdsdump_log(TDS_DBG_FUNC, "ct_deallocate_dynamic() : relinked list\n");
4852 
4853 	/* free dynamic */
4854 	tds_release_dynamic(&dyn->tdsdyn);
4855 	free(dyn->id);
4856 	free(dyn->stmt);
4857 	param_clear(dyn->param_list);
4858 
4859 	free(dyn);
4860 
4861 	return CS_SUCCEED;
4862 }
4863 
4864