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