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