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 = ¶m->datalen_value;
4391 *(param->datalen) = *datalen;
4392
4393 param->ind = ¶m->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