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