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