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