PageRenderTime 70ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/tds/query.c

https://gitlab.com/xk/FreeTDS
C | 3745 lines | 2565 code | 536 blank | 644 comment | 575 complexity | 6938f1b6db45218cd94b4bb8439074f7 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
  1. /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
  2. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
  3. * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Frediano Ziglio
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public
  16. * License along with this library; if not, write to the
  17. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. * Boston, MA 02111-1307, USA.
  19. */
  20. #include <config.h>
  21. #include <stdarg.h>
  22. #include <stdio.h>
  23. #if HAVE_STDLIB_H
  24. #include <stdlib.h>
  25. #endif /* HAVE_STDLIB_H */
  26. #if HAVE_STRING_H
  27. #include <string.h>
  28. #endif /* HAVE_STRING_H */
  29. #include <ctype.h>
  30. #include <freetds/tds.h>
  31. #include <freetds/enum_cap.h>
  32. #include <freetds/iconv.h>
  33. #include <freetds/convert.h>
  34. #include <freetds/string.h>
  35. #include "tds_checks.h"
  36. #include "replacements.h"
  37. #include <assert.h>
  38. TDS_RCSID(var, "$Id: query.c,v 1.269 2012-03-06 20:33:14 freddy77 Exp $");
  39. static void tds_put_params(TDSSOCKET * tds, TDSPARAMINFO * info, int flags);
  40. static void tds7_put_query_params(TDSSOCKET * tds, const char *query, size_t query_len);
  41. static void tds7_put_params_definition(TDSSOCKET * tds, const char *param_definition, size_t param_length);
  42. static TDSRET tds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags);
  43. static inline TDSRET tds_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol);
  44. static char *tds7_build_param_def_from_query(TDSSOCKET * tds, const char* converted_query, size_t converted_query_len, TDSPARAMINFO * params, size_t *out_len);
  45. static char *tds7_build_param_def_from_params(TDSSOCKET * tds, const char* query, size_t query_len, TDSPARAMINFO * params, size_t *out_len);
  46. static TDSRET tds_put_param_as_string(TDSSOCKET * tds, TDSPARAMINFO * params, int n);
  47. static TDSRET tds_send_emulated_execute(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params);
  48. static int tds_count_placeholders_ucs2le(const char *query, const char *query_end);
  49. #define TDS_PUT_DATA_USE_NAME 1
  50. #define TDS_PUT_DATA_PREFIX_NAME 2
  51. #undef MIN
  52. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  53. #undef MAX
  54. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  55. /* All manner of client to server submittal functions */
  56. /**
  57. * \ingroup libtds
  58. * \defgroup query Query
  59. * Function to handle query.
  60. */
  61. /**
  62. * \addtogroup query
  63. * @{
  64. */
  65. /**
  66. * Accept an ASCII string, convert it to UCS2-LE
  67. * The input is null-terminated, but the output excludes the null.
  68. * \param buffer buffer where to store output
  69. * \param buf string to write
  70. * \return bytes written
  71. */
  72. static size_t
  73. tds_ascii_to_ucs2(char *buffer, const char *buf)
  74. {
  75. char *s;
  76. assert(buffer && buf && *buf); /* This is an internal function. Call it correctly. */
  77. for (s = buffer; *buf != '\0'; ++buf) {
  78. *s++ = *buf;
  79. *s++ = '\0';
  80. }
  81. return s - buffer;
  82. }
  83. /**
  84. * Utility to convert a constant ascii string to ucs2 and send to server.
  85. * Used to send internal store procedure names to server.
  86. * \tds
  87. * \param s constanst string to send
  88. */
  89. #define TDS_PUT_N_AS_UCS2(tds, s) do { \
  90. char buffer[sizeof(s)*2-2]; \
  91. tds_put_smallint(tds, sizeof(buffer)/2); \
  92. tds_put_n(tds, buffer, tds_ascii_to_ucs2(buffer, s)); \
  93. } while(0)
  94. /**
  95. * Convert a string in an allocated buffer
  96. * \param tds state information for the socket and the TDS protocol
  97. * \param char_conv information about the encodings involved
  98. * \param s input string
  99. * \param len input string length (in bytes), -1 for null terminated
  100. * \param out_len returned output length (in bytes)
  101. * \return string allocated (or input pointer if no conversion required) or NULL if error
  102. */
  103. const char *
  104. tds_convert_string(TDSSOCKET * tds, TDSICONV * char_conv, const char *s, int len, size_t *out_len)
  105. {
  106. char *buf;
  107. const char *ib;
  108. char *ob;
  109. size_t il, ol;
  110. /* char_conv is only mostly const */
  111. TDS_ERRNO_MESSAGE_FLAGS *suppress = (TDS_ERRNO_MESSAGE_FLAGS*) &char_conv->suppress;
  112. CHECK_TDS_EXTRA(tds);
  113. il = len < 0 ? strlen(s) : (size_t) len;
  114. if (char_conv->flags == TDS_ENCODING_MEMCPY) {
  115. *out_len = il;
  116. return s;
  117. }
  118. /* allocate needed buffer (+1 is to exclude 0 case) */
  119. ol = il * char_conv->to.charset.max_bytes_per_char / char_conv->from.charset.min_bytes_per_char + 1;
  120. buf = (char *) malloc(ol);
  121. if (!buf)
  122. return NULL;
  123. ib = s;
  124. ob = buf;
  125. memset(suppress, 0, sizeof(char_conv->suppress));
  126. if (tds_iconv(tds, char_conv, to_server, &ib, &il, &ob, &ol) == (size_t)-1) {
  127. free(buf);
  128. return NULL;
  129. }
  130. *out_len = ob - buf;
  131. return buf;
  132. }
  133. #if ENABLE_EXTRA_CHECKS
  134. void
  135. tds_convert_string_free(const char *original, const char *converted)
  136. {
  137. if (original != converted)
  138. free((char *) converted);
  139. }
  140. #endif
  141. /**
  142. * Flush query packet.
  143. * Used at the end of packet write to really send packet to server.
  144. * \tds
  145. */
  146. static TDSRET
  147. tds_query_flush_packet(TDSSOCKET *tds)
  148. {
  149. /* TODO depend on result ?? */
  150. tds_set_state(tds, TDS_PENDING);
  151. return tds_flush_packet(tds);
  152. }
  153. /**
  154. * Set current dynamic.
  155. * \tds
  156. * \param dyn dynamic to set
  157. */
  158. void
  159. tds_set_cur_dyn(TDSSOCKET *tds, TDSDYNAMIC *dyn)
  160. {
  161. if (dyn)
  162. ++dyn->ref_count;
  163. tds_release_cur_dyn(tds);
  164. tds->cur_dyn = dyn;
  165. }
  166. /**
  167. * tds_submit_query() sends a language string to the database server for
  168. * processing. TDS 4.2 is a plain text message with a packet type of 0x01,
  169. * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a
  170. * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f.
  171. * \tds
  172. * \param query language query to submit
  173. * \return TDS_FAIL or TDS_SUCCESS
  174. */
  175. TDSRET
  176. tds_submit_query(TDSSOCKET * tds, const char *query)
  177. {
  178. return tds_submit_query_params(tds, query, NULL, NULL);
  179. }
  180. /**
  181. * Substitute ?-style placeholders with named (\@param) ones.
  182. * Sybase does not support ?-style placeholders so convert them.
  183. * Also the function replace parameters names.
  184. * \param query query string
  185. * \param[in,out] query_len pointer to query length.
  186. * On input length of input query, on output length
  187. * of output query
  188. * \param params parameters to send to server
  189. * \returns new query or NULL on error
  190. */
  191. static char *
  192. tds5_fix_dot_query(const char *query, size_t *query_len, TDSPARAMINFO * params)
  193. {
  194. int i;
  195. size_t len, pos;
  196. const char *e, *s;
  197. size_t size = *query_len + 30;
  198. char colname[32];
  199. char *out;
  200. out = (char *) malloc(size);
  201. if (!out)
  202. goto memory_error;
  203. pos = 0;
  204. s = query;
  205. for (i = 0;; ++i) {
  206. e = tds_next_placeholder(s);
  207. len = e ? e - s : strlen(s);
  208. if (pos + len + 12 >= size) {
  209. size = pos + len + 30;
  210. if (!TDS_RESIZE(out, size))
  211. goto memory_error;
  212. }
  213. memcpy(out + pos, s, len);
  214. pos += len;
  215. if (!e)
  216. break;
  217. pos += sprintf(out + pos, "@P%d", i + 1);
  218. if (i >= params->num_cols)
  219. goto memory_error;
  220. sprintf(colname, "@P%d", i + 1);
  221. if (!tds_dstr_copy(&params->columns[i]->column_name, colname))
  222. goto memory_error;
  223. s = e + 1;
  224. }
  225. out[pos] = 0;
  226. *query_len = pos;
  227. return out;
  228. memory_error:
  229. free(out);
  230. return NULL;
  231. }
  232. /**
  233. * Write data to wire
  234. * \tds
  235. * \param curcol column where store column information
  236. * \return TDS_FAIL on error or TDS_SUCCESS
  237. */
  238. static inline TDSRET
  239. tds_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol)
  240. {
  241. return curcol->funcs->put_data(tds, curcol, 0);
  242. }
  243. /**
  244. * Start query packet of a given type
  245. * \tds
  246. * \param packet_type packet type
  247. * \param head extra information to put in a TDS7 header
  248. */
  249. static TDSRET
  250. tds_start_query_head(TDSSOCKET *tds, unsigned char packet_type, TDSHEADERS * head)
  251. {
  252. tds->out_flag = packet_type;
  253. if (IS_TDS72_PLUS(tds->conn)) {
  254. int qn_len = 0;
  255. const char *converted_msgtext = NULL;
  256. const char *converted_options = NULL;
  257. size_t converted_msgtext_len = 0;
  258. size_t converted_options_len = 0;
  259. if (head && head->qn_msgtext && head->qn_options) {
  260. converted_msgtext = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], head->qn_msgtext, (int)strlen(head->qn_msgtext), &converted_msgtext_len);
  261. if (!converted_msgtext) {
  262. tds_set_state(tds, TDS_IDLE);
  263. return TDS_FAIL;
  264. }
  265. converted_options = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], head->qn_options, (int)strlen(head->qn_options), &converted_options_len);
  266. if (!converted_options) {
  267. tds_convert_string_free(head->qn_msgtext, converted_msgtext);
  268. tds_set_state(tds, TDS_IDLE);
  269. return TDS_FAIL;
  270. }
  271. qn_len = 6 + 2 + converted_msgtext_len + 2 + converted_options_len;
  272. if (head->qn_timeout != 0)
  273. qn_len += 4;
  274. }
  275. tds_put_int(tds, 4 + 18 + qn_len); /* total length */
  276. tds_put_int(tds, 18); /* length: transaction descriptor */
  277. tds_put_smallint(tds, 2); /* type: transaction descriptor */
  278. tds_put_n(tds, tds->conn->tds72_transaction, 8); /* transaction */
  279. tds_put_int(tds, 1); /* request count */
  280. if (qn_len != 0) {
  281. tds_put_int(tds, qn_len); /* length: query notification */
  282. tds_put_smallint(tds, 1); /* type: query notification */
  283. tds_put_smallint(tds, converted_msgtext_len); /* notifyid */
  284. tds_put_n(tds, converted_msgtext, converted_msgtext_len);
  285. tds_put_smallint(tds, converted_options_len); /* ssbdeployment */
  286. tds_put_n(tds, converted_options, converted_options_len);
  287. if (head->qn_timeout != 0)
  288. tds_put_int(tds, head->qn_timeout); /* timeout */
  289. tds_convert_string_free(head->qn_options, converted_options);
  290. tds_convert_string_free(head->qn_msgtext, converted_msgtext);
  291. }
  292. }
  293. return TDS_SUCCESS;
  294. }
  295. /**
  296. * Start query packet of a given type
  297. * \tds
  298. * \param packet_type packet type
  299. */
  300. static void
  301. tds_start_query(TDSSOCKET *tds, unsigned char packet_type)
  302. {
  303. /* no need to check return value here because tds_start_query_head() cannot
  304. fail when given a NULL head parameter */
  305. tds_start_query_head(tds, packet_type, NULL);
  306. }
  307. /**
  308. * tds_submit_query_params() sends a language string to the database server for
  309. * processing. TDS 4.2 is a plain text message with a packet type of 0x01,
  310. * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a
  311. * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f.
  312. * \tds
  313. * \param query language query to submit
  314. * \param params parameters of query
  315. * \return TDS_FAIL or TDS_SUCCESS
  316. */
  317. TDSRET
  318. tds_submit_query_params(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params, TDSHEADERS * head)
  319. {
  320. size_t query_len;
  321. int num_params = params ? params->num_cols : 0;
  322. CHECK_TDS_EXTRA(tds);
  323. if (params)
  324. CHECK_PARAMINFO_EXTRA(params);
  325. if (!query)
  326. return TDS_FAIL;
  327. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  328. return TDS_FAIL;
  329. query_len = strlen(query);
  330. if (IS_TDS50(tds->conn)) {
  331. char *new_query = NULL;
  332. /* are there '?' style parameters ? */
  333. if (tds_next_placeholder(query)) {
  334. if ((new_query = tds5_fix_dot_query(query, &query_len, params)) == NULL) {
  335. tds_set_state(tds, TDS_IDLE);
  336. return TDS_FAIL;
  337. }
  338. query = new_query;
  339. }
  340. tds->out_flag = TDS_NORMAL;
  341. tds_put_byte(tds, TDS_LANGUAGE_TOKEN);
  342. /* TODO ICONV use converted size, not input size and convert string */
  343. TDS_PUT_INT(tds, query_len + 1);
  344. tds_put_byte(tds, params ? 1 : 0); /* 1 if there are params, 0 otherwise */
  345. tds_put_n(tds, query, query_len);
  346. if (params) {
  347. /* add on parameters */
  348. tds_put_params(tds, params, tds_dstr_isempty(&params->columns[0]->column_name) ? 0 : TDS_PUT_DATA_USE_NAME);
  349. }
  350. free(new_query);
  351. } else if (!IS_TDS7_PLUS(tds->conn) || !params || !params->num_cols) {
  352. if (tds_start_query_head(tds, TDS_QUERY, head) != TDS_SUCCESS)
  353. return TDS_FAIL;
  354. tds_put_string(tds, query, (int)query_len);
  355. } else {
  356. TDSCOLUMN *param;
  357. size_t definition_len;
  358. int count, i;
  359. char *param_definition;
  360. size_t converted_query_len;
  361. const char *converted_query;
  362. converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, (int)query_len, &converted_query_len);
  363. if (!converted_query) {
  364. tds_set_state(tds, TDS_IDLE);
  365. return TDS_FAIL;
  366. }
  367. count = tds_count_placeholders_ucs2le(converted_query, converted_query + converted_query_len);
  368. if (!count) {
  369. param_definition = tds7_build_param_def_from_params(tds, converted_query, converted_query_len, params, &definition_len);
  370. if (!param_definition) {
  371. tds_convert_string_free(query, converted_query);
  372. tds_set_state(tds, TDS_IDLE);
  373. return TDS_FAIL;
  374. }
  375. } else {
  376. /*
  377. * TODO perhaps functions that calls tds7_build_param_def_from_query
  378. * should call also tds7_build_param_def_from_params ??
  379. */
  380. param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);
  381. if (!param_definition) {
  382. tds_convert_string_free(query, converted_query);
  383. tds_set_state(tds, TDS_IDLE);
  384. return TDS_FAIL;
  385. }
  386. }
  387. if (tds_start_query_head(tds, TDS_RPC, head) != TDS_SUCCESS) {
  388. tds_convert_string_free(query, converted_query);
  389. free(param_definition);
  390. return TDS_FAIL;
  391. }
  392. /* procedure name */
  393. if (IS_TDS71_PLUS(tds->conn)) {
  394. tds_put_smallint(tds, -1);
  395. tds_put_smallint(tds, TDS_SP_EXECUTESQL);
  396. } else {
  397. TDS_PUT_N_AS_UCS2(tds, "sp_executesql");
  398. }
  399. tds_put_smallint(tds, 0);
  400. /* string with sql statement */
  401. if (!count) {
  402. tds_put_byte(tds, 0);
  403. tds_put_byte(tds, 0);
  404. tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
  405. TDS_PUT_INT(tds, converted_query_len);
  406. if (IS_TDS71_PLUS(tds->conn))
  407. tds_put_n(tds, tds->conn->collation, 5);
  408. TDS_PUT_INT(tds, converted_query_len);
  409. tds_put_n(tds, converted_query, converted_query_len);
  410. } else {
  411. tds7_put_query_params(tds, converted_query, converted_query_len);
  412. }
  413. tds_convert_string_free(query, converted_query);
  414. tds7_put_params_definition(tds, param_definition, definition_len);
  415. free(param_definition);
  416. for (i = 0; i < num_params; i++) {
  417. param = params->columns[i];
  418. /* TODO check error */
  419. tds_put_data_info(tds, param, 0);
  420. if (tds_put_data(tds, param) != TDS_SUCCESS)
  421. return TDS_FAIL;
  422. }
  423. tds->current_op = TDS_OP_EXECUTESQL;
  424. }
  425. return tds_query_flush_packet(tds);
  426. }
  427. /**
  428. * Format and submit a query
  429. * \tds
  430. * \param queryf query format. printf like expansion is performed on
  431. * this query.
  432. */
  433. TDSRET
  434. tds_submit_queryf(TDSSOCKET * tds, const char *queryf, ...)
  435. {
  436. va_list ap;
  437. char *query = NULL;
  438. TDSRET rc = TDS_FAIL;
  439. CHECK_TDS_EXTRA(tds);
  440. va_start(ap, queryf);
  441. if (vasprintf(&query, queryf, ap) >= 0) {
  442. rc = tds_submit_query(tds, query);
  443. free(query);
  444. }
  445. va_end(ap);
  446. return rc;
  447. }
  448. /**
  449. * Skip a comment in a query
  450. * \param s start of the string (or part of it)
  451. * \returns pointer to end of comment
  452. */
  453. const char *
  454. tds_skip_comment(const char *s)
  455. {
  456. const char *p = s;
  457. if (*p == '-' && p[1] == '-') {
  458. for (;*++p != '\0';)
  459. if (*p == '\n')
  460. return p;
  461. } else if (*p == '/' && p[1] == '*') {
  462. ++p;
  463. for(;*++p != '\0';)
  464. if (*p == '*' && p[1] == '/')
  465. return p + 2;
  466. } else
  467. ++p;
  468. return p;
  469. }
  470. /**
  471. * Skip quoting string (like 'sfsf', "dflkdj" or [dfkjd])
  472. * \param s pointer to first quoting character. @verbatim Should be ', " or [. @endverbatim
  473. * \return character after quoting
  474. */
  475. const char *
  476. tds_skip_quoted(const char *s)
  477. {
  478. const char *p = s;
  479. char quote = (*s == '[') ? ']' : *s;
  480. for (; *++p;) {
  481. if (*p == quote) {
  482. if (*++p != quote)
  483. return p;
  484. }
  485. }
  486. return p;
  487. }
  488. /**
  489. * Get position of next placeholder
  490. * \param start pointer to part of query to search
  491. * \return next placeholder or NULL if not found
  492. */
  493. const char *
  494. tds_next_placeholder(const char *start)
  495. {
  496. const char *p = start;
  497. if (!p)
  498. return NULL;
  499. for (;;) {
  500. switch (*p) {
  501. case '\0':
  502. return NULL;
  503. case '\'':
  504. case '\"':
  505. case '[':
  506. p = tds_skip_quoted(p);
  507. break;
  508. case '-':
  509. case '/':
  510. p = tds_skip_comment(p);
  511. break;
  512. case '?':
  513. return p;
  514. default:
  515. ++p;
  516. break;
  517. }
  518. }
  519. }
  520. /**
  521. * Count the number of placeholders in query
  522. * \param query query string
  523. */
  524. int
  525. tds_count_placeholders(const char *query)
  526. {
  527. const char *p = query - 1;
  528. int count = 0;
  529. for (;; ++count) {
  530. if (!(p = tds_next_placeholder(p + 1)))
  531. return count;
  532. }
  533. }
  534. /**
  535. * Skip a comment in a query
  536. * \param s start of the string (or part of it). Encoded in ucs2
  537. * \param end end of string
  538. * \returns pointer to end of comment
  539. */
  540. static const char *
  541. tds_skip_comment_ucs2le(const char *s, const char *end)
  542. {
  543. const char *p = s;
  544. if (p+4 <= end && memcmp(p, "-\0-", 4) == 0) {
  545. for (;(p+=2) < end;)
  546. if (p[0] == '\n' && p[1] == 0)
  547. return p + 2;
  548. } else if (p+4 <= end && memcmp(p, "/\0*", 4) == 0) {
  549. p += 2;
  550. end -= 2;
  551. for(;(p+=2) < end;)
  552. if (memcmp(p, "*\0/", 4) == 0)
  553. return p + 4;
  554. } else
  555. p += 2;
  556. return p;
  557. }
  558. /**
  559. * Return pointer to end of a quoted string.
  560. * At the beginning pointer should point to delimiter.
  561. * \param s start of string to skip encoded in ucs2
  562. * \param end pointer to end of string
  563. */
  564. static const char *
  565. tds_skip_quoted_ucs2le(const char *s, const char *end)
  566. {
  567. const char *p = s;
  568. char quote = (*s == '[') ? ']' : *s;
  569. assert(s[1] == 0 && s < end && (end - s) % 2 == 0);
  570. for (; (p += 2) != end;) {
  571. if (p[0] == quote && !p[1]) {
  572. p += 2;
  573. if (p == end || p[0] != quote || p[1])
  574. return p;
  575. }
  576. }
  577. return p;
  578. }
  579. /**
  580. * Found the next placeholder (? or \@param) in a string.
  581. * String must be encoded in ucs2.
  582. * \param start start of the string (or part of it)
  583. * \param end end of string
  584. * \param named true if named parameters should be returned
  585. * \returns either start of next placeholder or end if not found
  586. */
  587. static const char *
  588. tds_next_placeholder_ucs2le(const char *start, const char *end, int named)
  589. {
  590. const char *p = start;
  591. char prev = ' ', c;
  592. assert(p && start <= end && (end - start) % 2 == 0);
  593. for (; p != end;) {
  594. if (p[1]) {
  595. prev = ' ';
  596. p += 2;
  597. continue;
  598. }
  599. c = p[0];
  600. switch (c) {
  601. case '\'':
  602. case '\"':
  603. case '[':
  604. p = tds_skip_quoted_ucs2le(p, end);
  605. break;
  606. case '-':
  607. case '/':
  608. p = tds_skip_comment_ucs2le(p, end);
  609. c = ' ';
  610. break;
  611. case '?':
  612. return p;
  613. case '@':
  614. if (named && !isalnum((unsigned char) prev))
  615. return p;
  616. default:
  617. p += 2;
  618. break;
  619. }
  620. prev = c;
  621. }
  622. return end;
  623. }
  624. /**
  625. * Count number of placeholders (?) in a query
  626. * \param query query encoded in ucs2
  627. * \param query_end end of query
  628. * \return number of placeholders found
  629. */
  630. static int
  631. tds_count_placeholders_ucs2le(const char *query, const char *query_end)
  632. {
  633. const char *p = query - 2;
  634. int count = 0;
  635. for (;; ++count) {
  636. if ((p = tds_next_placeholder_ucs2le(p + 2, query_end, 0)) == query_end)
  637. return count;
  638. }
  639. }
  640. /**
  641. * Return declaration for column (like "varchar(20)")
  642. * \tds
  643. * \param curcol column
  644. * \param out buffer to hold declaration
  645. * \return TDS_FAIL or TDS_SUCCESS
  646. */
  647. TDSRET
  648. tds_get_column_declaration(TDSSOCKET * tds, TDSCOLUMN * curcol, char *out)
  649. {
  650. const char *fmt = NULL;
  651. /* unsigned int is required by printf format, don't use size_t */
  652. unsigned int max_len = IS_TDS7_PLUS(tds->conn) ? 8000 : 255;
  653. unsigned int size;
  654. CHECK_TDS_EXTRA(tds);
  655. CHECK_COLUMN_EXTRA(curcol);
  656. size = tds_fix_column_size(tds, curcol);
  657. switch (tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size)) {
  658. case XSYBCHAR:
  659. case SYBCHAR:
  660. fmt = "CHAR(%u)";
  661. break;
  662. case SYBVARCHAR:
  663. case XSYBVARCHAR:
  664. if (curcol->column_varint_size == 8)
  665. fmt = "VARCHAR(MAX)";
  666. else
  667. fmt = "VARCHAR(%u)";
  668. break;
  669. case SYBINT1:
  670. fmt = "TINYINT";
  671. break;
  672. case SYBINT2:
  673. fmt = "SMALLINT";
  674. break;
  675. case SYBINT4:
  676. fmt = "INT";
  677. break;
  678. case SYBINT8:
  679. /* TODO even for Sybase ?? */
  680. fmt = "BIGINT";
  681. break;
  682. case SYBFLT8:
  683. fmt = "FLOAT";
  684. break;
  685. case SYBDATETIME:
  686. fmt = "DATETIME";
  687. break;
  688. case SYBBIT:
  689. fmt = "BIT";
  690. break;
  691. case SYBTEXT:
  692. fmt = "TEXT";
  693. break;
  694. case SYBLONGBINARY: /* TODO correct ?? */
  695. case SYBIMAGE:
  696. fmt = "IMAGE";
  697. break;
  698. case SYBMONEY4:
  699. fmt = "SMALLMONEY";
  700. break;
  701. case SYBMONEY:
  702. fmt = "MONEY";
  703. break;
  704. case SYBDATETIME4:
  705. fmt = "SMALLDATETIME";
  706. break;
  707. case SYBREAL:
  708. fmt = "REAL";
  709. break;
  710. case SYBBINARY:
  711. case XSYBBINARY:
  712. fmt = "BINARY(%u)";
  713. break;
  714. case SYBVARBINARY:
  715. case XSYBVARBINARY:
  716. if (curcol->column_varint_size == 8)
  717. fmt = "VARBINARY(MAX)";
  718. else
  719. fmt = "VARBINARY(%u)";
  720. break;
  721. case SYBNUMERIC:
  722. fmt = "NUMERIC(%d,%d)";
  723. goto numeric_decimal;
  724. case SYBDECIMAL:
  725. fmt = "DECIMAL(%d,%d)";
  726. numeric_decimal:
  727. sprintf(out, fmt, curcol->column_prec, curcol->column_scale);
  728. return TDS_SUCCESS;
  729. break;
  730. case SYBUNIQUE:
  731. if (IS_TDS7_PLUS(tds->conn))
  732. fmt = "UNIQUEIDENTIFIER";
  733. break;
  734. case SYBNTEXT:
  735. if (IS_TDS7_PLUS(tds->conn))
  736. fmt = "NTEXT";
  737. break;
  738. case SYBNVARCHAR:
  739. case XSYBNVARCHAR:
  740. if (curcol->column_varint_size == 8) {
  741. fmt = "NVARCHAR(MAX)";
  742. } else if (IS_TDS7_PLUS(tds->conn)) {
  743. fmt = "NVARCHAR(%u)";
  744. max_len = 4000;
  745. size /= 2u;
  746. }
  747. break;
  748. case XSYBNCHAR:
  749. if (IS_TDS7_PLUS(tds->conn)) {
  750. fmt = "NCHAR(%u)";
  751. max_len = 4000;
  752. size /= 2u;
  753. }
  754. break;
  755. case SYBVARIANT:
  756. if (IS_TDS7_PLUS(tds->conn))
  757. fmt = "SQL_VARIANT";
  758. break;
  759. /* TODO support scale !! */
  760. case SYBMSTIME:
  761. fmt = "TIME";
  762. break;
  763. case SYBMSDATE:
  764. fmt = "DATE";
  765. break;
  766. case SYBMSDATETIME2:
  767. fmt = "DATETIME2";
  768. break;
  769. case SYBMSDATETIMEOFFSET:
  770. fmt = "DATETIMEOFFSET";
  771. break;
  772. case SYBUINT2:
  773. fmt = "UNSIGNED SMALLINT";
  774. break;
  775. case SYBUINT4:
  776. fmt = "UNSIGNED INT";
  777. break;
  778. case SYBUINT8:
  779. fmt = "UNSIGNED BIGINT";
  780. break;
  781. /* nullable types should not occur here... */
  782. case SYBFLTN:
  783. case SYBMONEYN:
  784. case SYBDATETIMN:
  785. case SYBBITN:
  786. case SYBINTN:
  787. assert(0);
  788. /* TODO... */
  789. case SYBVOID:
  790. case SYBSINT1:
  791. default:
  792. tdsdump_log(TDS_DBG_ERROR, "Unknown type %d\n", tds_get_conversion_type(curcol->on_server.column_type, curcol->on_server.column_size));
  793. break;
  794. }
  795. if (fmt) {
  796. /* fill out */
  797. sprintf(out, fmt, size > 0 ? (size > max_len ? max_len : size) : 1u);
  798. return TDS_SUCCESS;
  799. }
  800. out[0] = 0;
  801. return TDS_FAIL;
  802. }
  803. /**
  804. * Return string with parameters definition, useful for TDS7+
  805. * \param tds state information for the socket and the TDS protocol
  806. * \param converted_query query to send to server in ucs2 encoding
  807. * \param converted_query_len query length in bytes
  808. * \param params parameters to build declaration
  809. * \param out_len length output buffer in bytes
  810. * \return allocated and filled string or NULL on failure (coded in ucs2le charset )
  811. */
  812. /* TODO find a better name for this function */
  813. static char *
  814. tds7_build_param_def_from_query(TDSSOCKET * tds, const char* converted_query, size_t converted_query_len, TDSPARAMINFO * params, size_t *out_len)
  815. {
  816. size_t len = 0, size = 512;
  817. char *param_str;
  818. char declaration[40];
  819. int i, count;
  820. assert(IS_TDS7_PLUS(tds->conn));
  821. assert(out_len);
  822. CHECK_TDS_EXTRA(tds);
  823. if (params)
  824. CHECK_PARAMINFO_EXTRA(params);
  825. count = tds_count_placeholders_ucs2le(converted_query, converted_query + converted_query_len);
  826. param_str = (char *) malloc(512);
  827. if (!param_str)
  828. return NULL;
  829. for (i = 0; i < count; ++i) {
  830. if (len > 0u) {
  831. param_str[len++] = ',';
  832. param_str[len++] = 0;
  833. }
  834. /* realloc on insufficient space */
  835. while ((len + (2u * 40u)) > size) {
  836. size += 512u;
  837. if (!TDS_RESIZE(param_str, size))
  838. goto Cleanup;
  839. }
  840. /* get this parameter declaration */
  841. sprintf(declaration, "@P%d ", i+1);
  842. if (params && i < params->num_cols) {
  843. if (TDS_FAILED(tds_get_column_declaration(tds, params->columns[i], declaration + strlen(declaration))))
  844. goto Cleanup;
  845. } else {
  846. strcat(declaration, "varchar(4000)");
  847. }
  848. /* convert it to ucs2 and append */
  849. len += tds_ascii_to_ucs2(param_str + len, declaration);
  850. }
  851. *out_len = len;
  852. return param_str;
  853. Cleanup:
  854. free(param_str);
  855. return NULL;
  856. }
  857. /**
  858. * Return string with parameters definition, useful for TDS7+
  859. * \param tds state information for the socket and the TDS protocol
  860. * \param query query to send to server encoded as ucs2
  861. * \param query_len query length in bytes
  862. * \param params parameters to build declaration
  863. * \param out_len length output buffer in bytes
  864. * \return allocated and filled string or NULL on failure (coded in ucs2le charset )
  865. */
  866. /* TODO find a better name for this function */
  867. static char *
  868. tds7_build_param_def_from_params(TDSSOCKET * tds, const char* query, size_t query_len, TDSPARAMINFO * params, size_t *out_len)
  869. {
  870. size_t size = 512;
  871. char *param_str;
  872. char declaration[40];
  873. size_t l = 0;
  874. int i;
  875. struct tds_ids {
  876. const char *p;
  877. size_t len;
  878. } *ids = NULL;
  879. assert(IS_TDS7_PLUS(tds->conn));
  880. assert(out_len);
  881. CHECK_TDS_EXTRA(tds);
  882. if (params)
  883. CHECK_PARAMINFO_EXTRA(params);
  884. param_str = (char *) malloc(512);
  885. if (!param_str)
  886. goto Cleanup;
  887. if (!params)
  888. goto no_params;
  889. /* try to detect missing names */
  890. if (params->num_cols) {
  891. ids = (struct tds_ids *) calloc(params->num_cols, sizeof(struct tds_ids));
  892. if (!ids)
  893. goto Cleanup;
  894. if (tds_dstr_isempty(&params->columns[0]->column_name)) {
  895. const char *s = query, *e, *id_end;
  896. const char *query_end = query + query_len;
  897. for (i = 0; i < params->num_cols; s = e + 2) {
  898. e = tds_next_placeholder_ucs2le(s, query_end, 1);
  899. if (e == query_end)
  900. break;
  901. if (e[0] != '@')
  902. continue;
  903. /* find end of param name */
  904. for (id_end = e + 2; id_end != query_end; id_end += 2)
  905. if (!id_end[1] && (id_end[0] != '_' && id_end[1] != '#' && !isalnum((unsigned char) id_end[0])))
  906. break;
  907. ids[i].p = e;
  908. ids[i].len = id_end - e;
  909. ++i;
  910. }
  911. }
  912. }
  913. for (i = 0; i < params->num_cols; ++i) {
  914. const char *ib;
  915. char *ob;
  916. size_t il, ol;
  917. if (l > 0u) {
  918. param_str[l++] = ',';
  919. param_str[l++] = 0;
  920. }
  921. /* realloc on insufficient space */
  922. il = ids[i].p ? ids[i].len : 2 * tds_dstr_len(&params->columns[i]->column_name);
  923. while ((l + (2u * 40u) + il) > size) {
  924. size += 512u;
  925. if (!TDS_RESIZE(param_str, size))
  926. goto Cleanup;
  927. }
  928. /* this part of buffer can be not-ascii compatible, use all ucs2... */
  929. if (ids[i].p) {
  930. memcpy(param_str + l, ids[i].p, ids[i].len);
  931. l += ids[i].len;
  932. } else {
  933. ib = tds_dstr_cstr(&params->columns[i]->column_name);
  934. il = tds_dstr_len(&params->columns[i]->column_name);
  935. ob = param_str + l;
  936. ol = size - l;
  937. memset(&tds->conn->char_convs[iso2server_metadata]->suppress, 0, sizeof(tds->conn->char_convs[iso2server_metadata]->suppress));
  938. if (tds_iconv(tds, tds->conn->char_convs[iso2server_metadata], to_server, &ib, &il, &ob, &ol) == (size_t) - 1)
  939. goto Cleanup;
  940. l = size - ol;
  941. }
  942. param_str[l++] = ' ';
  943. param_str[l++] = 0;
  944. /* get this parameter declaration */
  945. tds_get_column_declaration(tds, params->columns[i], declaration);
  946. if (!declaration[0])
  947. goto Cleanup;
  948. /* convert it to ucs2 and append */
  949. l += tds_ascii_to_ucs2(param_str + l, declaration);
  950. }
  951. free(ids);
  952. no_params:
  953. *out_len = l;
  954. return param_str;
  955. Cleanup:
  956. free(ids);
  957. free(param_str);
  958. return NULL;
  959. }
  960. /**
  961. * Output params types and query (required by sp_prepare/sp_executesql/sp_prepexec)
  962. * \param tds state information for the socket and the TDS protocol
  963. * \param query query (in ucs2le codings)
  964. * \param query_len query length in bytes
  965. */
  966. static void
  967. tds7_put_query_params(TDSSOCKET * tds, const char *query, size_t query_len)
  968. {
  969. size_t len;
  970. int i, num_placeholders;
  971. const char *s, *e;
  972. char buf[24];
  973. const char *const query_end = query + query_len;
  974. CHECK_TDS_EXTRA(tds);
  975. assert(IS_TDS7_PLUS(tds->conn));
  976. /* we use all "@PX" for parameters */
  977. num_placeholders = tds_count_placeholders_ucs2le(query, query_end);
  978. len = num_placeholders * 2;
  979. /* adjust for the length of X */
  980. for (i = 10; i <= num_placeholders; i *= 10) {
  981. len += num_placeholders - i + 1;
  982. }
  983. /* string with sql statement */
  984. /* replace placeholders with dummy parametes */
  985. tds_put_byte(tds, 0);
  986. tds_put_byte(tds, 0);
  987. tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
  988. len = 2u * len + query_len;
  989. TDS_PUT_INT(tds, len);
  990. if (IS_TDS71_PLUS(tds->conn))
  991. tds_put_n(tds, tds->conn->collation, 5);
  992. TDS_PUT_INT(tds, len);
  993. s = query;
  994. /* TODO do a test with "...?" and "...?)" */
  995. for (i = 1;; ++i) {
  996. e = tds_next_placeholder_ucs2le(s, query_end, 0);
  997. assert(e && query <= e && e <= query_end);
  998. tds_put_n(tds, s, e - s);
  999. if (e == query_end)
  1000. break;
  1001. sprintf(buf, "@P%d", i);
  1002. tds_put_string(tds, buf, -1);
  1003. s = e + 2;
  1004. }
  1005. }
  1006. /**
  1007. * Send parameter definition to server
  1008. * \tds
  1009. * \param param_definition parameter definition string. Encoded in ucs2
  1010. * \param param_length parameter definition string length in bytes
  1011. */
  1012. static void
  1013. tds7_put_params_definition(TDSSOCKET * tds, const char *param_definition, size_t param_length)
  1014. {
  1015. CHECK_TDS_EXTRA(tds);
  1016. /* string with parameters types */
  1017. tds_put_byte(tds, 0);
  1018. tds_put_byte(tds, 0);
  1019. tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
  1020. /* put parameters definitions */
  1021. TDS_PUT_INT(tds, param_length);
  1022. if (IS_TDS71_PLUS(tds->conn))
  1023. tds_put_n(tds, tds->conn->collation, 5);
  1024. TDS_PUT_INT(tds, param_length ? param_length : -1);
  1025. tds_put_n(tds, param_definition, param_length);
  1026. }
  1027. /**
  1028. * tds_submit_prepare() creates a temporary stored procedure in the server.
  1029. * Under TDS 4.2 dynamic statements are emulated building sql command
  1030. * \param tds state information for the socket and the TDS protocol
  1031. * \param query language query with given placeholders (?)
  1032. * \param id string to identify the dynamic query. Pass NULL for automatic generation.
  1033. * \param dyn_out will receive allocated TDSDYNAMIC*. Any older allocated dynamic won't be freed, Can be NULL.
  1034. * \param params parameters to use. It can be NULL even if parameters are present. Used only for TDS7+
  1035. * \return TDS_FAIL or TDS_SUCCESS
  1036. */
  1037. /* TODO parse all results ?? */
  1038. TDSRET
  1039. tds_submit_prepare(TDSSOCKET * tds, const char *query, const char *id, TDSDYNAMIC ** dyn_out, TDSPARAMINFO * params)
  1040. {
  1041. int id_len, query_len;
  1042. TDSRET rc = TDS_FAIL;
  1043. TDSDYNAMIC *dyn;
  1044. CHECK_TDS_EXTRA(tds);
  1045. if (params)
  1046. CHECK_PARAMINFO_EXTRA(params);
  1047. if (!query || !dyn_out)
  1048. return TDS_FAIL;
  1049. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1050. return TDS_FAIL;
  1051. /* allocate a structure for this thing */
  1052. dyn = tds_alloc_dynamic(tds->conn, id);
  1053. if (!dyn)
  1054. return TDS_FAIL;
  1055. tds_release_dynamic(dyn_out);
  1056. *dyn_out = dyn;
  1057. tds_release_cur_dyn(tds);
  1058. /* TDS5 sometimes cannot accept prepare so we need to store query */
  1059. if (!IS_TDS7_PLUS(tds->conn)) {
  1060. dyn->query = strdup(query);
  1061. if (!dyn->query)
  1062. goto failure;
  1063. }
  1064. if (!IS_TDS50(tds->conn) && !IS_TDS7_PLUS(tds->conn)) {
  1065. dyn->emulated = 1;
  1066. tds_dynamic_deallocated(tds->conn, dyn);
  1067. tds_set_state(tds, TDS_IDLE);
  1068. return TDS_SUCCESS;
  1069. }
  1070. query_len = (int)strlen(query);
  1071. tds_set_cur_dyn(tds, dyn);
  1072. if (IS_TDS7_PLUS(tds->conn)) {
  1073. size_t definition_len = 0;
  1074. char *param_definition = NULL;
  1075. size_t converted_query_len;
  1076. const char *converted_query;
  1077. converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, query_len, &converted_query_len);
  1078. if (!converted_query)
  1079. goto failure;
  1080. param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);
  1081. if (!param_definition) {
  1082. tds_convert_string_free(query, converted_query);
  1083. goto failure;
  1084. }
  1085. tds_start_query(tds, TDS_RPC);
  1086. /* procedure name */
  1087. if (IS_TDS71_PLUS(tds->conn)) {
  1088. tds_put_smallint(tds, -1);
  1089. tds_put_smallint(tds, TDS_SP_PREPARE);
  1090. } else {
  1091. TDS_PUT_N_AS_UCS2(tds, "sp_prepare");
  1092. }
  1093. tds_put_smallint(tds, 0);
  1094. /* return param handle (int) */
  1095. tds_put_byte(tds, 0);
  1096. tds_put_byte(tds, 1); /* result */
  1097. tds_put_byte(tds, SYBINTN);
  1098. tds_put_byte(tds, 4);
  1099. tds_put_byte(tds, 0);
  1100. tds7_put_params_definition(tds, param_definition, definition_len);
  1101. tds7_put_query_params(tds, converted_query, converted_query_len);
  1102. tds_convert_string_free(query, converted_query);
  1103. free(param_definition);
  1104. /* 1 param ?? why ? flags ?? */
  1105. tds_put_byte(tds, 0);
  1106. tds_put_byte(tds, 0);
  1107. tds_put_byte(tds, SYBINTN);
  1108. tds_put_byte(tds, 4);
  1109. tds_put_byte(tds, 4);
  1110. tds_put_int(tds, 1);
  1111. tds->current_op = TDS_OP_PREPARE;
  1112. } else {
  1113. int dynproc_capability =
  1114. tds_capability_has_req(tds->conn, TDS_REQ_PROTO_DYNPROC);
  1115. unsigned toklen;
  1116. tds->out_flag = TDS_NORMAL;
  1117. id_len = (int)strlen(dyn->id);
  1118. tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);
  1119. toklen = 5 + id_len + query_len;
  1120. if (dynproc_capability) toklen += id_len + 16;
  1121. tds_put_smallint(tds, toklen);
  1122. tds_put_byte(tds, TDS_DYN_PREPARE);
  1123. tds_put_byte(tds, 0x00);
  1124. tds_put_byte(tds, id_len);
  1125. tds_put_n(tds, dyn->id, id_len);
  1126. /* TODO ICONV convert string, do not put with tds_put_n */
  1127. /* TODO how to pass parameters type? like store procedures ? */
  1128. if (dynproc_capability) {
  1129. tds_put_smallint(tds, query_len + id_len + 16);
  1130. tds_put_n(tds, "create proc ", 12);
  1131. tds_put_n(tds, dyn->id, id_len);
  1132. tds_put_n(tds, " as ", 4);
  1133. } else {
  1134. tds_put_smallint(tds, query_len);
  1135. }
  1136. tds_put_n(tds, query, query_len);
  1137. }
  1138. rc = tds_query_flush_packet(tds);
  1139. if (TDS_SUCCEED(rc))
  1140. return rc;
  1141. failure:
  1142. /* TODO correct if writing fail ?? */
  1143. tds_set_state(tds, TDS_IDLE);
  1144. tds_release_dynamic(dyn_out);
  1145. tds_dynamic_deallocated(tds->conn, dyn);
  1146. return rc;
  1147. }
  1148. /**
  1149. * Submit a prepared query with parameters
  1150. * \param tds state information for the socket and the TDS protocol
  1151. * \param query language query with given placeholders (?)
  1152. * \param params parameters to send
  1153. * \return TDS_FAIL or TDS_SUCCESS
  1154. */
  1155. TDSRET
  1156. tds_submit_execdirect(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params, TDSHEADERS * head)
  1157. {
  1158. size_t query_len;
  1159. TDSCOLUMN *param;
  1160. TDSDYNAMIC *dyn;
  1161. size_t id_len;
  1162. CHECK_TDS_EXTRA(tds);
  1163. CHECK_PARAMINFO_EXTRA(params);
  1164. if (!query)
  1165. return TDS_FAIL;
  1166. query_len = strlen(query);
  1167. if (IS_TDS7_PLUS(tds->conn)) {
  1168. size_t definition_len = 0;
  1169. int i;
  1170. char *param_definition = NULL;
  1171. size_t converted_query_len;
  1172. const char *converted_query;
  1173. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1174. return TDS_FAIL;
  1175. converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, (int)query_len, &converted_query_len);
  1176. if (!converted_query) {
  1177. tds_set_state(tds, TDS_IDLE);
  1178. return TDS_FAIL;
  1179. }
  1180. param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);
  1181. if (!param_definition) {
  1182. tds_convert_string_free(query, converted_query);
  1183. tds_set_state(tds, TDS_IDLE);
  1184. return TDS_FAIL;
  1185. }
  1186. if (tds_start_query_head(tds, TDS_RPC, head) != TDS_SUCCESS) {
  1187. tds_convert_string_free(query, converted_query);
  1188. free(param_definition);
  1189. return TDS_FAIL;
  1190. }
  1191. /* procedure name */
  1192. if (IS_TDS71_PLUS(tds->conn)) {
  1193. tds_put_smallint(tds, -1);
  1194. tds_put_smallint(tds, TDS_SP_EXECUTESQL);
  1195. } else {
  1196. TDS_PUT_N_AS_UCS2(tds, "sp_executesql");
  1197. }
  1198. tds_put_smallint(tds, 0);
  1199. tds7_put_query_params(tds, converted_query, converted_query_len);
  1200. tds7_put_params_definition(tds, param_definition, definition_len);
  1201. tds_convert_string_free(query, converted_query);
  1202. free(param_definition);
  1203. for (i = 0; i < params->num_cols; i++) {
  1204. TDSRET ret;
  1205. param = params->columns[i];
  1206. /* TODO check error */
  1207. tds_put_data_info(tds, param, 0);
  1208. ret = tds_put_data(tds, param);
  1209. if (TDS_FAILED(ret))
  1210. return ret;
  1211. }
  1212. tds->current_op = TDS_OP_EXECUTESQL;
  1213. return tds_query_flush_packet(tds);
  1214. }
  1215. /* allocate a structure for this thing */
  1216. dyn = tds_alloc_dynamic(tds->conn, NULL);
  1217. if (!dyn)
  1218. return TDS_FAIL;
  1219. /* check is no parameters */
  1220. if (params && !params->num_cols)
  1221. params = NULL;
  1222. /* TDS 4.2, emulate prepared statements */
  1223. /*
  1224. * TODO Sybase seems to not support parameters in prepared execdirect
  1225. * so use language or prepare and then exec
  1226. */
  1227. if (!IS_TDS50(tds->conn) || params) {
  1228. TDSRET ret = TDS_SUCCESS;
  1229. dyn->emulated = 1;
  1230. dyn->params = params;
  1231. dyn->query = strdup(query);
  1232. if (!dyn->query)
  1233. ret = TDS_FAIL;
  1234. if (TDS_SUCCEED(ret))
  1235. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1236. ret = TDS_FAIL;
  1237. if (TDS_SUCCEED(ret)) {
  1238. ret = tds_send_emulated_execute(tds, dyn->query, dyn->params);
  1239. if (TDS_SUCCEED(ret))
  1240. ret = tds_query_flush_packet(tds);
  1241. }
  1242. /* do not free our parameters */
  1243. dyn->params = NULL;
  1244. tds_dynamic_deallocated(tds->conn, dyn);
  1245. tds_release_dynamic(&dyn);
  1246. return ret;
  1247. }
  1248. tds_release_cur_dyn(tds);
  1249. tds->cur_dyn = dyn;
  1250. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1251. return TDS_FAIL;
  1252. tds->out_flag = TDS_NORMAL;
  1253. id_len = strlen(dyn->id);
  1254. tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);
  1255. TDS_PUT_SMALLINT(tds, query_len + id_len * 2 + 21);
  1256. tds_put_byte(tds, TDS_DYN_EXEC_IMMED);
  1257. tds_put_byte(tds, params ? 0x01 : 0);
  1258. TDS_PUT_BYTE(tds, id_len);
  1259. tds_put_n(tds, dyn->id, id_len);
  1260. /* TODO ICONV convert string, do not put with tds_put_n */
  1261. /* TODO how to pass parameters type? like store procedures ? */
  1262. TDS_PUT_SMALLINT(tds, query_len + id_len + 16);
  1263. tds_put_n(tds, "create proc ", 12);
  1264. tds_put_n(tds, dyn->id, (int)id_len);
  1265. tds_put_n(tds, " as ", 4);
  1266. tds_put_n(tds, query, (int)query_len);
  1267. if (params)
  1268. tds_put_params(tds, params, 0);
  1269. return tds_flush_packet(tds);
  1270. }
  1271. /**
  1272. * tds71_submit_prepexec() creates a temporary stored procedure in the server.
  1273. * \param tds state information for the socket and the TDS protocol
  1274. * \param query language query with given placeholders (?)
  1275. * \param id string to identify the dynamic query. Pass NULL for automatic generation.
  1276. * \param dyn_out will receive allocated TDSDYNAMIC*. Any older allocated dynamic won't be freed, Can be NULL.
  1277. * \param params parameters to use. It can be NULL even if parameters are present. Used only for TDS7+
  1278. * \return TDS_FAIL or TDS_SUCCESS
  1279. */
  1280. TDSRET
  1281. tds71_submit_prepexec(TDSSOCKET * tds, const char *query, const char *id, TDSDYNAMIC ** dyn_out, TDSPARAMINFO * params)
  1282. {
  1283. int query_len;
  1284. TDSRET rc = TDS_FAIL;
  1285. TDSDYNAMIC *dyn;
  1286. size_t definition_len = 0;
  1287. char *param_definition = NULL;
  1288. size_t converted_query_len;
  1289. const char *converted_query;
  1290. CHECK_TDS_EXTRA(tds);
  1291. if (params)
  1292. CHECK_PARAMINFO_EXTRA(params);
  1293. if (!query || !dyn_out || !IS_TDS7_PLUS(tds->conn))
  1294. return TDS_FAIL;
  1295. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1296. return TDS_FAIL;
  1297. /* allocate a structure for this thing */
  1298. dyn = tds_alloc_dynamic(tds->conn, id);
  1299. if (!dyn)
  1300. return TDS_FAIL;
  1301. tds_release_dynamic(dyn_out);
  1302. *dyn_out = dyn;
  1303. tds_set_cur_dyn(tds, dyn);
  1304. query_len = (int)strlen(query);
  1305. converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], query, query_len, &converted_query_len);
  1306. if (!converted_query)
  1307. goto failure;
  1308. param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);
  1309. if (!param_definition) {
  1310. tds_convert_string_free(query, converted_query);
  1311. goto failure;
  1312. }
  1313. tds_start_query(tds, TDS_RPC);
  1314. /* procedure name */
  1315. if (IS_TDS71_PLUS(tds->conn)) {
  1316. tds_put_smallint(tds, -1);
  1317. tds_put_smallint(tds, TDS_SP_PREPEXEC);
  1318. } else {
  1319. TDS_PUT_N_AS_UCS2(tds, "sp_prepexec");
  1320. }
  1321. tds_put_smallint(tds, 0);
  1322. /* return param handle (int) */
  1323. tds_put_byte(tds, 0);
  1324. tds_put_byte(tds, 1); /* result */
  1325. tds_put_byte(tds, SYBINTN);
  1326. tds_put_byte(tds, 4);
  1327. tds_put_byte(tds, 0);
  1328. tds7_put_params_definition(tds, param_definition, definition_len);
  1329. tds7_put_query_params(tds, converted_query, converted_query_len);
  1330. tds_convert_string_free(query, converted_query);
  1331. free(param_definition);
  1332. if (params) {
  1333. int i;
  1334. for (i = 0; i < params->num_cols; i++) {
  1335. TDSCOLUMN *param = params->columns[i];
  1336. /* TODO check error */
  1337. tds_put_data_info(tds, param, 0);
  1338. rc = tds_put_data(tds, param);
  1339. if (TDS_FAILED(rc))
  1340. return rc;
  1341. }
  1342. }
  1343. tds->current_op = TDS_OP_PREPEXEC;
  1344. rc = tds_query_flush_packet(tds);
  1345. if (TDS_SUCCEED(rc))
  1346. return rc;
  1347. failure:
  1348. /* TODO correct if writing fail ?? */
  1349. tds_set_state(tds, TDS_IDLE);
  1350. tds_release_dynamic(dyn_out);
  1351. tds_dynamic_deallocated(tds->conn, dyn);
  1352. return rc;
  1353. }
  1354. /**
  1355. * Get column size for wire
  1356. */
  1357. size_t
  1358. tds_fix_column_size(TDSSOCKET * tds, TDSCOLUMN * curcol)
  1359. {
  1360. size_t size = curcol->on_server.column_size, min;
  1361. if (!size) {
  1362. size = curcol->column_size;
  1363. if (is_unicode_type(curcol->on_server.column_type))
  1364. size *= 2u;
  1365. }
  1366. switch (curcol->column_varint_size) {
  1367. case 1:
  1368. size = MAX(MIN(size, 255), 1);
  1369. break;
  1370. case 2:
  1371. /* note that varchar(max)/varbinary(max) have a varint of 8 */
  1372. if (curcol->on_server.column_type == XSYBNVARCHAR || curcol->on_server.column_type == XSYBNCHAR)
  1373. min = 2;
  1374. else
  1375. min = 1;
  1376. size = MAX(MIN(size, 8000u), min);
  1377. break;
  1378. case 4:
  1379. if (curcol->on_server.column_type == SYBNTEXT)
  1380. size = MAX(MIN(size, 0x7ffffffeu), 2u);
  1381. else
  1382. size = MAX(MIN(size, 0x7fffffffu), 1u);
  1383. break;
  1384. default:
  1385. break;
  1386. }
  1387. return size;
  1388. }
  1389. /**
  1390. * Put data information to wire
  1391. * \param tds state information for the socket and the TDS protocol
  1392. * \param curcol column where to store information
  1393. * \param flags bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information)
  1394. * \return TDS_SUCCESS or TDS_FAIL
  1395. */
  1396. static TDSRET
  1397. tds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags)
  1398. {
  1399. int len;
  1400. CHECK_TDS_EXTRA(tds);
  1401. CHECK_COLUMN_EXTRA(curcol);
  1402. if (flags & TDS_PUT_DATA_USE_NAME) {
  1403. len = tds_dstr_len(&curcol->column_name);
  1404. tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting param_name \n");
  1405. if (IS_TDS7_PLUS(tds->conn)) {
  1406. size_t converted_param_len;
  1407. const char *converted_param;
  1408. /* TODO use a fixed buffer to avoid error ? */
  1409. converted_param =
  1410. tds_convert_string(tds, tds->conn->char_convs[client2ucs2], tds_dstr_cstr(&curcol->column_name), len,
  1411. &converted_param_len);
  1412. if (!converted_param)
  1413. return TDS_FAIL;
  1414. if (!(flags & TDS_PUT_DATA_PREFIX_NAME)) {
  1415. TDS_PUT_BYTE(tds, converted_param_len / 2);
  1416. } else {
  1417. TDS_PUT_BYTE(tds, converted_param_len / 2 + 1);
  1418. tds_put_n(tds, "@", 2);
  1419. }
  1420. tds_put_n(tds, converted_param, converted_param_len);
  1421. tds_convert_string_free(tds_dstr_cstr(&curcol->column_name), converted_param);
  1422. } else {
  1423. /* TODO ICONV convert */
  1424. tds_put_byte(tds, len); /* param name len */
  1425. tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), len);
  1426. }
  1427. } else {
  1428. tds_put_byte(tds, 0x00); /* param name len */
  1429. }
  1430. /*
  1431. * TODO support other flags (use defaul null/no metadata)
  1432. * bit 1 (2 as flag) in TDS7+ is "default value" bit
  1433. * (what's the meaning of "default value" ?)
  1434. */
  1435. tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting status \n");
  1436. tds_put_byte(tds, curcol->column_output); /* status (input) */
  1437. if (!IS_TDS7_PLUS(tds->conn))
  1438. tds_put_int(tds, curcol->column_usertype); /* usertype */
  1439. /* FIXME: column_type is wider than one byte. Do something sensible, not just lop off the high byte. */
  1440. tds_put_byte(tds, curcol->on_server.column_type);
  1441. if (curcol->funcs->put_info(tds, curcol) != TDS_SUCCESS)
  1442. return TDS_FAIL;
  1443. /* TODO needed in TDS4.2 ?? now is called only is TDS >= 5 */
  1444. if (!IS_TDS7_PLUS(tds->conn))
  1445. tds_put_byte(tds, 0x00); /* locale info length */
  1446. return TDS_SUCCESS;
  1447. }
  1448. /**
  1449. * Calc information length in bytes (useful for calculating full packet length)
  1450. * \param tds state information for the socket and the TDS protocol
  1451. * \param curcol column where to store information
  1452. * \param flags bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information)
  1453. * \return data info length
  1454. */
  1455. static int
  1456. tds_put_data_info_length(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags)
  1457. {
  1458. int len = 8;
  1459. CHECK_TDS_EXTRA(tds);
  1460. CHECK_COLUMN_EXTRA(curcol);
  1461. #if ENABLE_EXTRA_CHECKS
  1462. if (IS_TDS7_PLUS(tds->conn))
  1463. tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info_length called with TDS7+\n");
  1464. #endif
  1465. /* TODO ICONV convert string if needed (see also tds_put_data_info) */
  1466. if (flags & TDS_PUT_DATA_USE_NAME)
  1467. len += tds_dstr_len(&curcol->column_name);
  1468. if (is_numeric_type(curcol->on_server.column_type))
  1469. len += 2;
  1470. if (curcol->column_varint_size == 5)
  1471. return len + 4;
  1472. return len + curcol->column_varint_size;
  1473. }
  1474. /**
  1475. * Send dynamic request on TDS 7+ to be executed
  1476. * \tds
  1477. * \param dyn dynamic query to execute
  1478. */
  1479. static void
  1480. tds7_send_execute(TDSSOCKET * tds, TDSDYNAMIC * dyn)
  1481. {
  1482. TDSCOLUMN *param;
  1483. TDSPARAMINFO *info;
  1484. int i;
  1485. /* procedure name */
  1486. /* NOTE do not call this procedure using integer name (TDS_SP_EXECUTE) on mssql2k, it doesn't work! */
  1487. TDS_PUT_N_AS_UCS2(tds, "sp_execute");
  1488. tds_put_smallint(tds, 0); /* flags */
  1489. /* id of prepared statement */
  1490. tds_put_byte(tds, 0);
  1491. tds_put_byte(tds, 0);
  1492. tds_put_byte(tds, SYBINTN);
  1493. tds_put_byte(tds, 4);
  1494. tds_put_byte(tds, 4);
  1495. tds_put_int(tds, dyn->num_id);
  1496. info = dyn->params;
  1497. if (info)
  1498. for (i = 0; i < info->num_cols; i++) {
  1499. param = info->columns[i];
  1500. /* TODO check error */
  1501. tds_put_data_info(tds, param, 0);
  1502. /* FIXME handle error */
  1503. tds_put_data(tds, param);
  1504. }
  1505. tds->current_op = TDS_OP_EXECUTE;
  1506. }
  1507. /**
  1508. * tds_submit_execute() sends a previously prepared dynamic statement to the
  1509. * server.
  1510. * \param tds state information for the socket and the TDS protocol
  1511. * \param dyn dynamic proc to execute. Must build from same tds.
  1512. */
  1513. TDSRET
  1514. tds_submit_execute(TDSSOCKET * tds, TDSDYNAMIC * dyn)
  1515. {
  1516. int id_len;
  1517. CHECK_TDS_EXTRA(tds);
  1518. /* TODO this dynamic should be in tds */
  1519. CHECK_DYNAMIC_EXTRA(dyn);
  1520. tdsdump_log(TDS_DBG_FUNC, "tds_submit_execute()\n");
  1521. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1522. return TDS_FAIL;
  1523. tds_set_cur_dyn(tds, dyn);
  1524. if (IS_TDS7_PLUS(tds->conn)) {
  1525. /* check proper id */
  1526. if (dyn->num_id == 0) {
  1527. tds_set_state(tds, TDS_IDLE);
  1528. return TDS_FAIL;
  1529. }
  1530. /* RPC on sp_execute */
  1531. tds_start_query(tds, TDS_RPC);
  1532. tds7_send_execute(tds, dyn);
  1533. return tds_query_flush_packet(tds);
  1534. }
  1535. if (dyn->emulated) {
  1536. TDSRET rc = tds_send_emulated_execute(tds, dyn->query, dyn->params);
  1537. if (TDS_FAILED(rc))
  1538. return rc;
  1539. return tds_query_flush_packet(tds);
  1540. }
  1541. /* query has been prepared successfully, discard original query */
  1542. if (dyn->query)
  1543. TDS_ZERO_FREE(dyn->query);
  1544. tds->out_flag = TDS_NORMAL;
  1545. /* dynamic id */
  1546. id_len = (int)strlen(dyn->id);
  1547. tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);
  1548. tds_put_smallint(tds, id_len + 5);
  1549. tds_put_byte(tds, 0x02);
  1550. tds_put_byte(tds, dyn->params ? 0x01 : 0);
  1551. tds_put_byte(tds, id_len);
  1552. tds_put_n(tds, dyn->id, id_len);
  1553. tds_put_smallint(tds, 0);
  1554. if (dyn->params)
  1555. tds_put_params(tds, dyn->params, 0);
  1556. /* send it */
  1557. return tds_query_flush_packet(tds);
  1558. }
  1559. /**
  1560. * Send parameters to server.
  1561. * \tds
  1562. * \param info parameters to send
  1563. * \param flags 0 or TDS_PUT_DATA_USE_NAME
  1564. */
  1565. static void
  1566. tds_put_params(TDSSOCKET * tds, TDSPARAMINFO * info, int flags)
  1567. {
  1568. int i, len;
  1569. CHECK_TDS_EXTRA(tds);
  1570. CHECK_PARAMINFO_EXTRA(info);
  1571. /* column descriptions */
  1572. tds_put_byte(tds, TDS5_PARAMFMT_TOKEN);
  1573. /* size */
  1574. len = 2;
  1575. for (i = 0; i < info->num_cols; i++)
  1576. len += tds_put_data_info_length(tds, info->columns[i], flags);
  1577. tds_put_smallint(tds, len);
  1578. /* number of parameters */
  1579. tds_put_smallint(tds, info->num_cols);
  1580. /* column detail for each parameter */
  1581. for (i = 0; i < info->num_cols; i++) {
  1582. /* FIXME add error handling */
  1583. tds_put_data_info(tds, info->columns[i], flags);
  1584. }
  1585. /* row data */
  1586. tds_put_byte(tds, TDS5_PARAMS_TOKEN);
  1587. for (i = 0; i < info->num_cols; i++) {
  1588. /* FIXME handle error */
  1589. tds_put_data(tds, info->columns[i]);
  1590. }
  1591. }
  1592. /**
  1593. * Check if dynamic request must be unprepared.
  1594. * Depending on status and protocol version request should be unprepared
  1595. * or not.
  1596. * \tds
  1597. * \param dyn dynamic request to check
  1598. */
  1599. int
  1600. tds_needs_unprepare(TDSSOCKET * tds, TDSDYNAMIC * dyn)
  1601. {
  1602. CHECK_TDS_EXTRA(tds);
  1603. CHECK_DYNAMIC_EXTRA(dyn);
  1604. /* check if statement is prepared */
  1605. if (IS_TDS7_PLUS(tds->conn) && !dyn->num_id)
  1606. return 0;
  1607. if (dyn->emulated || !dyn->id[0])
  1608. return 0;
  1609. return 1;
  1610. }
  1611. /**
  1612. * Send a unprepare request for a prepared query
  1613. * \param tds state information for the socket and the TDS protocol
  1614. * \param dyn dynamic query
  1615. * \result TDS_SUCCESS or TDS_FAIL
  1616. */
  1617. TDSRET
  1618. tds_submit_unprepare(TDSSOCKET * tds, TDSDYNAMIC * dyn)
  1619. {
  1620. int id_len;
  1621. CHECK_TDS_EXTRA(tds);
  1622. /* TODO test dyn in tds */
  1623. CHECK_DYNAMIC_EXTRA(dyn);
  1624. if (!dyn)
  1625. return TDS_FAIL;
  1626. tdsdump_log(TDS_DBG_FUNC, "tds_submit_unprepare() %s\n", dyn->id);
  1627. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1628. return TDS_FAIL;
  1629. tds_set_cur_dyn(tds, dyn);
  1630. if (IS_TDS7_PLUS(tds->conn)) {
  1631. /* RPC on sp_execute */
  1632. tds_start_query(tds, TDS_RPC);
  1633. /* procedure name */
  1634. if (IS_TDS71_PLUS(tds->conn)) {
  1635. /* save some byte for mssql2k */
  1636. tds_put_smallint(tds, -1);
  1637. tds_put_smallint(tds, TDS_SP_UNPREPARE);
  1638. } else {
  1639. TDS_PUT_N_AS_UCS2(tds, "sp_unprepare");
  1640. }
  1641. tds_put_smallint(tds, 0); /* flags */
  1642. /* id of prepared statement */
  1643. tds_put_byte(tds, 0);
  1644. tds_put_byte(tds, 0);
  1645. tds_put_byte(tds, SYBINTN);
  1646. tds_put_byte(tds, 4);
  1647. tds_put_byte(tds, 4);
  1648. tds_put_int(tds, dyn->num_id);
  1649. tds->current_op = TDS_OP_UNPREPARE;
  1650. return tds_query_flush_packet(tds);
  1651. }
  1652. if (dyn->emulated) {
  1653. tds_start_query(tds, TDS_QUERY);
  1654. /* just a dummy select to return some data */
  1655. tds_put_string(tds, "select 1 where 0=1", -1);
  1656. return tds_query_flush_packet(tds);
  1657. }
  1658. tds->out_flag = TDS_NORMAL;
  1659. /* dynamic id */
  1660. id_len = (int)strlen(dyn->id);
  1661. tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);
  1662. tds_put_smallint(tds, id_len + 5);
  1663. tds_put_byte(tds, TDS_DYN_DEALLOC);
  1664. tds_put_byte(tds, 0x00);
  1665. tds_put_byte(tds, id_len);
  1666. tds_put_n(tds, dyn->id, id_len);
  1667. tds_put_smallint(tds, 0);
  1668. /* send it */
  1669. tds->current_op = TDS_OP_DYN_DEALLOC;
  1670. return tds_query_flush_packet(tds);
  1671. }
  1672. /**
  1673. * Send RPC as string query.
  1674. * This function is used on old protocol which does not support RPC queries.
  1675. * \tds
  1676. * \param rpc_name name of RPC to invoke
  1677. * \param params parameters to send to server
  1678. * \returns TDS_FAIL or TDS_SUCCESS
  1679. */
  1680. static TDSRET
  1681. tds_send_emulated_rpc(TDSSOCKET * tds, const char *rpc_name, TDSPARAMINFO * params)
  1682. {
  1683. TDSCOLUMN *param;
  1684. int i, n;
  1685. int num_params = params ? params->num_cols : 0;
  1686. const char *sep = " ";
  1687. char buf[80];
  1688. /* create params and set */
  1689. for (i = 0, n = 0; i < num_params; ++i) {
  1690. param = params->columns[i];
  1691. /* declare and set output parameters */
  1692. if (!param->column_output)
  1693. continue;
  1694. ++n;
  1695. sprintf(buf, " DECLARE @P%d ", n);
  1696. tds_get_column_declaration(tds, param, buf + strlen(buf));
  1697. sprintf(buf + strlen(buf), " SET @P%d=", n);
  1698. tds_put_string(tds, buf, -1);
  1699. tds_put_param_as_string(tds, params, i);
  1700. }
  1701. /* put exec statement */
  1702. tds_put_string(tds, " EXEC ", 6);
  1703. tds_put_string(tds, rpc_name, -1);
  1704. /* put arguments */
  1705. for (i = 0, n = 0; i < num_params; ++i) {
  1706. param = params->columns[i];
  1707. tds_put_string(tds, sep, -1);
  1708. if (!tds_dstr_isempty(&param->column_name)) {
  1709. tds_put_string(tds, tds_dstr_cstr(&param->column_name), tds_dstr_len(&param->column_name));
  1710. tds_put_string(tds, "=", 1);
  1711. }
  1712. if (param->column_output) {
  1713. ++n;
  1714. sprintf(buf, "@P%d OUTPUT", n);
  1715. tds_put_string(tds, buf, -1);
  1716. } else {
  1717. tds_put_param_as_string(tds, params, i);
  1718. }
  1719. sep = ",";
  1720. }
  1721. return tds_query_flush_packet(tds);
  1722. }
  1723. /**
  1724. * tds_submit_rpc() call a RPC from server. Output parameters will be stored in tds->param_info
  1725. * \param tds state information for the socket and the TDS protocol
  1726. * \param rpc_name name of RPC
  1727. * \param params parameters informations. NULL for no parameters
  1728. */
  1729. TDSRET
  1730. tds_submit_rpc(TDSSOCKET * tds, const char *rpc_name, TDSPARAMINFO * params, TDSHEADERS * head)
  1731. {
  1732. TDSCOLUMN *param;
  1733. int rpc_name_len, i;
  1734. int num_params = params ? params->num_cols : 0;
  1735. CHECK_TDS_EXTRA(tds);
  1736. if (params)
  1737. CHECK_PARAMINFO_EXTRA(params);
  1738. assert(tds);
  1739. assert(rpc_name);
  1740. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  1741. return TDS_FAIL;
  1742. /* distinguish from dynamic query */
  1743. tds_release_cur_dyn(tds);
  1744. rpc_name_len = (int)strlen(rpc_name);
  1745. if (IS_TDS7_PLUS(tds->conn)) {
  1746. const char *converted_name;
  1747. size_t converted_name_len;
  1748. /* procedure name */
  1749. converted_name = tds_convert_string(tds, tds->conn->char_convs[client2ucs2], rpc_name, rpc_name_len, &converted_name_len);
  1750. if (!converted_name) {
  1751. tds_set_state(tds, TDS_IDLE);
  1752. return TDS_FAIL;
  1753. }
  1754. if (tds_start_query_head(tds, TDS_RPC, head) != TDS_SUCCESS) {
  1755. tds_convert_string_free(rpc_name, converted_name);
  1756. return TDS_FAIL;
  1757. }
  1758. TDS_PUT_SMALLINT(tds, converted_name_len / 2);
  1759. tds_put_n(tds, converted_name, (int)converted_name_len);
  1760. tds_convert_string_free(rpc_name, converted_name);
  1761. /*
  1762. * TODO support flags
  1763. * bit 0 (1 as flag) in TDS7/TDS5 is "recompile"
  1764. * bit 1 (2 as flag) in TDS7+ is "no metadata" bit
  1765. * (I don't know meaning of "no metadata")
  1766. */
  1767. tds_put_smallint(tds, 0);
  1768. for (i = 0; i < num_params; i++) {
  1769. param = params->columns[i];
  1770. /* TODO check error */
  1771. tds_put_data_info(tds, param, TDS_PUT_DATA_USE_NAME);
  1772. /* FIXME handle error */
  1773. tds_put_data(tds, param);
  1774. }
  1775. return tds_query_flush_packet(tds);
  1776. }
  1777. if (IS_TDS50(tds->conn)) {
  1778. tds->out_flag = TDS_NORMAL;
  1779. /* DBRPC */
  1780. tds_put_byte(tds, TDS_DBRPC_TOKEN);
  1781. /* TODO ICONV convert rpc name */
  1782. tds_put_smallint(tds, rpc_name_len + 3);
  1783. tds_put_byte(tds, rpc_name_len);
  1784. tds_put_n(tds, rpc_name, rpc_name_len);
  1785. /* TODO flags */
  1786. tds_put_smallint(tds, num_params ? 2 : 0);
  1787. if (num_params)
  1788. tds_put_params(tds, params, TDS_PUT_DATA_USE_NAME);
  1789. /* send it */
  1790. return tds_query_flush_packet(tds);
  1791. }
  1792. /* emulate it for TDS4.x, send RPC for mssql */
  1793. if (tds->conn->tds_version < 0x500)
  1794. return tds_send_emulated_rpc(tds, rpc_name, params);
  1795. /* TODO continue, support for TDS4?? */
  1796. tds_set_state(tds, TDS_IDLE);
  1797. return TDS_FAIL;
  1798. }
  1799. /**
  1800. * tds_send_cancel() sends an empty packet (8 byte header only)
  1801. * tds_process_cancel should be called directly after this.
  1802. * \param tds state information for the socket and the TDS protocol
  1803. * \remarks
  1804. * tcp will either deliver the packet or time out.
  1805. * (TIME_WAIT determines how long it waits between retries.)
  1806. *
  1807. * On sending the cancel, we may get EAGAIN. We then select(2) until we know
  1808. * either 1) it succeeded or 2) it didn't. On failure, close the socket,
  1809. * tell the app, and fail the function.
  1810. *
  1811. * On success, we read(2) and wait for a reply with select(2). If we get
  1812. * one, great. If the client's timeout expires, we tell him, but all we can
  1813. * do is wait some more or give up and close the connection. If he tells us
  1814. * to cancel again, we wait some more.
  1815. */
  1816. TDSRET
  1817. tds_send_cancel(TDSSOCKET * tds)
  1818. {
  1819. #if ENABLE_ODBC_MARS
  1820. static const char one = 1;
  1821. CHECK_TDS_EXTRA(tds);
  1822. tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: %sin_cancel and %sidle\n",
  1823. (tds->in_cancel? "":"not "), (tds->state == TDS_IDLE? "":"not "));
  1824. /* one cancel is sufficient */
  1825. if (tds->in_cancel || tds->state == TDS_IDLE) {
  1826. return TDS_SUCCESS;
  1827. }
  1828. tds->in_cancel = 1;
  1829. if (tds_mutex_trylock(&tds->conn->list_mtx)) {
  1830. /* TODO check */
  1831. /* signal other socket */
  1832. send(tds->conn->s_signal, (const void*) &one, sizeof(one), 0);
  1833. return TDS_SUCCESS;
  1834. }
  1835. if (tds->conn->in_net_tds) {
  1836. tds_mutex_unlock(&tds->conn->list_mtx);
  1837. /* TODO check */
  1838. /* signal other socket */
  1839. send(tds->conn->s_signal, (const void*) &one, sizeof(one), 0);
  1840. return TDS_SUCCESS;
  1841. }
  1842. tds_mutex_unlock(&tds->conn->list_mtx);
  1843. /*
  1844. problem: if we are in in_net and we got a signal ??
  1845. on timeout we and a cancel, directly in in_net
  1846. if we hold the lock and we get a signal lock create a death lock
  1847. if we use a recursive mutex and we can get the lock there are 2 cases
  1848. - same thread, we could add a packet and signal, no try ok
  1849. - first thread locking, we could add a packet but are we sure it get processed ??, no try ok
  1850. if recursive mutex and we can't get another thread, wait
  1851. if mutex is not recursive and we get the lock (try)
  1852. - nobody locked, if in_net it could be same or another
  1853. if mutex is not recursive and we can't get the lock
  1854. - another thread is locking, sending signal require not exiting and global list (not protected by list_mtx)
  1855. - same thread have lock, we can't wait nothing without deathlock, setting a flag in tds and signaling could help
  1856. if a tds is waiting for data or is waiting for a condition or for a signal in poll
  1857. pass cancel request on socket ??
  1858. */
  1859. tds->out_flag = TDS_CANCEL;
  1860. tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: sending cancel packet\n");
  1861. return tds_flush_packet(tds);
  1862. #else
  1863. TDSRET rc;
  1864. /*
  1865. * if we are not able to get the lock signal other thread
  1866. * this means that either:
  1867. * - another thread is processing data
  1868. * - we got called from a signal inside processing thread
  1869. */
  1870. if (tds_mutex_trylock(&tds->wire_mtx)) {
  1871. static const char one = '1';
  1872. /* TODO check */
  1873. /* signal other socket */
  1874. send(tds->conn->s_signal, (const void*) &one, sizeof(one), 0);
  1875. return TDS_SUCCESS;
  1876. }
  1877. CHECK_TDS_EXTRA(tds);
  1878. tdsdump_log(TDS_DBG_FUNC, "tds_send_cancel: %sin_cancel and %sidle\n",
  1879. (tds->in_cancel? "":"not "), (tds->state == TDS_IDLE? "":"not "));
  1880. /* one cancel is sufficient */
  1881. if (tds->in_cancel || tds->state == TDS_IDLE) {
  1882. tds_mutex_unlock(&tds->wire_mtx);
  1883. return TDS_SUCCESS;
  1884. }
  1885. rc = tds_put_cancel(tds);
  1886. tds_mutex_unlock(&tds->wire_mtx);
  1887. return rc;
  1888. #endif
  1889. }
  1890. /**
  1891. * Quote a string properly. Output string is always NUL-terminated
  1892. * \tds
  1893. * \param buffer output buffer. If NULL function will just return
  1894. * required bytes
  1895. * \param quoting quote character
  1896. * \param id string to quote
  1897. * \param len length of string to quote
  1898. * \returns size of output string
  1899. */
  1900. static size_t
  1901. tds_quote(TDSSOCKET * tds, char *buffer, char quoting, const char *id, size_t len)
  1902. {
  1903. size_t size;
  1904. const char *src, *pend;
  1905. char *dst;
  1906. CHECK_TDS_EXTRA(tds);
  1907. pend = id + len;
  1908. /* quote */
  1909. src = id;
  1910. if (!buffer) {
  1911. size = 2u + len;
  1912. for (; src != pend; ++src)
  1913. if (*src == quoting)
  1914. ++size;
  1915. return size;
  1916. }
  1917. dst = buffer;
  1918. *dst++ = (quoting == ']') ? '[' : quoting;
  1919. for (; src != pend; ++src) {
  1920. if (*src == quoting)
  1921. *dst++ = quoting;
  1922. *dst++ = *src;
  1923. }
  1924. *dst++ = quoting;
  1925. *dst = 0;
  1926. return dst - buffer;
  1927. }
  1928. /**
  1929. * Quote an id
  1930. * \param tds state information for the socket and the TDS protocol
  1931. * \param buffer buffer to store quoted id. If NULL do not write anything
  1932. * (useful to compute quote length)
  1933. * \param id id to quote
  1934. * \param idlen id length
  1935. * \result written chars (not including needed terminator)
  1936. */
  1937. size_t
  1938. tds_quote_id(TDSSOCKET * tds, char *buffer, const char *id, int idlen)
  1939. {
  1940. size_t i, len;
  1941. CHECK_TDS_EXTRA(tds);
  1942. len = idlen < 0 ? strlen(id) : (size_t) idlen;
  1943. /* quote always for mssql */
  1944. if (TDS_IS_MSSQL(tds) || tds->conn->product_version >= TDS_SYB_VER(12, 5, 1))
  1945. return tds_quote(tds, buffer, ']', id, len);
  1946. /* need quote ?? */
  1947. for (i = 0; i < len; ++i) {
  1948. char c = id[i];
  1949. if (c >= 'a' && c <= 'z')
  1950. continue;
  1951. if (c >= 'A' && c <= 'Z')
  1952. continue;
  1953. if (i > 0 && c >= '0' && c <= '9')
  1954. continue;
  1955. if (c == '_')
  1956. continue;
  1957. return tds_quote(tds, buffer, '\"', id, len);
  1958. }
  1959. if (buffer) {
  1960. memcpy(buffer, id, len);
  1961. buffer[len] = '\0';
  1962. }
  1963. return len;
  1964. }
  1965. /**
  1966. * Quote a string
  1967. * \param tds state information for the socket and the TDS protocol
  1968. * \param buffer buffer to store quoted id. If NULL do not write anything
  1969. * (useful to compute quote length)
  1970. * \param str string to quote (not necessary null-terminated)
  1971. * \param len length of string (-1 for null terminated)
  1972. * \result written chars (not including needed terminator)
  1973. */
  1974. size_t
  1975. tds_quote_string(TDSSOCKET * tds, char *buffer, const char *str, int len)
  1976. {
  1977. return tds_quote(tds, buffer, '\'', str, len < 0 ? strlen(str) : (size_t) len);
  1978. }
  1979. /**
  1980. * Set current cursor.
  1981. * Current cursor is the one will receive output from server.
  1982. * \tds
  1983. * \param cursor cursor to set as current
  1984. */
  1985. static inline void
  1986. tds_set_cur_cursor(TDSSOCKET *tds, TDSCURSOR *cursor)
  1987. {
  1988. ++cursor->ref_count;
  1989. if (tds->cur_cursor)
  1990. tds_release_cursor(&tds->cur_cursor);
  1991. tds->cur_cursor = cursor;
  1992. }
  1993. TDSRET
  1994. tds_cursor_declare(TDSSOCKET * tds, TDSCURSOR * cursor, TDSPARAMINFO *params, int *something_to_send)
  1995. {
  1996. CHECK_TDS_EXTRA(tds);
  1997. if (!cursor)
  1998. return TDS_FAIL;
  1999. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_declare() cursor id = %d\n", cursor->cursor_id);
  2000. if (IS_TDS7_PLUS(tds->conn)) {
  2001. cursor->srv_status |= TDS_CUR_ISTAT_DECLARED;
  2002. cursor->srv_status |= TDS_CUR_ISTAT_CLOSED;
  2003. cursor->srv_status |= TDS_CUR_ISTAT_RDONLY;
  2004. }
  2005. if (IS_TDS50(tds->conn)) {
  2006. if (!*something_to_send) {
  2007. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2008. return TDS_FAIL;
  2009. tds->out_flag = TDS_NORMAL;
  2010. }
  2011. if (tds->state != TDS_QUERYING || tds->out_flag != TDS_NORMAL)
  2012. return TDS_FAIL;
  2013. tds_put_byte(tds, TDS_CURDECLARE_TOKEN);
  2014. /* length of the data stream that follows */
  2015. TDS_PUT_SMALLINT(tds, (6 + strlen(cursor->cursor_name) + strlen(cursor->query)));
  2016. tdsdump_log(TDS_DBG_ERROR, "size = %u\n", (unsigned int) (6u + strlen(cursor->cursor_name) + strlen(cursor->query)));
  2017. TDS_PUT_BYTE(tds, strlen(cursor->cursor_name));
  2018. tds_put_n(tds, cursor->cursor_name, (int)strlen(cursor->cursor_name));
  2019. tds_put_byte(tds, 1); /* cursor option is read only=1, unused=0 */
  2020. tds_put_byte(tds, 0); /* status unused=0 */
  2021. /* TODO iconv */
  2022. TDS_PUT_SMALLINT(tds, strlen(cursor->query));
  2023. tds_put_n(tds, cursor->query, (int)strlen(cursor->query));
  2024. tds_put_tinyint(tds, 0); /* number of columns = 0 , valid value applicable only for updatable cursor */
  2025. *something_to_send = 1;
  2026. }
  2027. return TDS_SUCCESS;
  2028. }
  2029. TDSRET
  2030. tds_cursor_open(TDSSOCKET * tds, TDSCURSOR * cursor, TDSPARAMINFO *params, int *something_to_send)
  2031. {
  2032. CHECK_TDS_EXTRA(tds);
  2033. if (!cursor)
  2034. return TDS_FAIL;
  2035. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_open() cursor id = %d\n", cursor->cursor_id);
  2036. if (!*something_to_send) {
  2037. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2038. return TDS_FAIL;
  2039. }
  2040. if (tds->state != TDS_QUERYING)
  2041. return TDS_FAIL;
  2042. tds_set_cur_cursor(tds, cursor);
  2043. if (IS_TDS50(tds->conn)) {
  2044. tds->out_flag = TDS_NORMAL;
  2045. tds_put_byte(tds, TDS_CUROPEN_TOKEN);
  2046. TDS_PUT_SMALLINT(tds, 6 + strlen(cursor->cursor_name)); /* length of the data stream that follows */
  2047. /*tds_put_int(tds, cursor->cursor_id); *//* Only if cursor id is passed as zero, the cursor name need to be sent */
  2048. tds_put_int(tds, 0);
  2049. TDS_PUT_BYTE(tds, strlen(cursor->cursor_name));
  2050. tds_put_n(tds, cursor->cursor_name, (int)strlen(cursor->cursor_name));
  2051. tds_put_byte(tds, 0); /* Cursor status : 0 for no arguments */
  2052. *something_to_send = 1;
  2053. }
  2054. if (IS_TDS7_PLUS(tds->conn)) {
  2055. const char *converted_query;
  2056. size_t definition_len = 0, converted_query_len;
  2057. char *param_definition = NULL;
  2058. int num_params = params ? params->num_cols : 0;
  2059. /* cursor statement */
  2060. converted_query = tds_convert_string(tds, tds->conn->char_convs[client2ucs2],
  2061. cursor->query, (int)strlen(cursor->query), &converted_query_len);
  2062. if (!converted_query) {
  2063. if (!*something_to_send)
  2064. tds_set_state(tds, TDS_IDLE);
  2065. return TDS_FAIL;
  2066. }
  2067. if (num_params) {
  2068. param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);
  2069. if (!param_definition) {
  2070. tds_convert_string_free(cursor->query, converted_query);
  2071. if (!*something_to_send)
  2072. tds_set_state(tds, TDS_IDLE);
  2073. return TDS_FAIL;
  2074. }
  2075. }
  2076. /* RPC call to sp_cursoropen */
  2077. tds_start_query(tds, TDS_RPC);
  2078. /* procedure identifier by number */
  2079. if (IS_TDS71_PLUS(tds->conn)) {
  2080. tds_put_smallint(tds, -1);
  2081. tds_put_smallint(tds, TDS_SP_CURSOROPEN);
  2082. } else {
  2083. TDS_PUT_N_AS_UCS2(tds, "sp_cursoropen");
  2084. }
  2085. tds_put_smallint(tds, 0); /* flags */
  2086. /* return cursor handle (int) */
  2087. tds_put_byte(tds, 0); /* no parameter name */
  2088. tds_put_byte(tds, 1); /* output parameter */
  2089. tds_put_byte(tds, SYBINTN);
  2090. tds_put_byte(tds, 4);
  2091. tds_put_byte(tds, 0);
  2092. if (definition_len) {
  2093. tds7_put_query_params(tds, converted_query, converted_query_len);
  2094. } else {
  2095. tds_put_byte(tds, 0);
  2096. tds_put_byte(tds, 0);
  2097. tds_put_byte(tds, SYBNTEXT); /* must be Ntype */
  2098. TDS_PUT_INT(tds, converted_query_len);
  2099. if (IS_TDS71_PLUS(tds->conn))
  2100. tds_put_n(tds, tds->conn->collation, 5);
  2101. TDS_PUT_INT(tds, converted_query_len);
  2102. tds_put_n(tds, converted_query, (int)converted_query_len);
  2103. }
  2104. tds_convert_string_free(cursor->query, converted_query);
  2105. /* type */
  2106. tds_put_byte(tds, 0); /* no parameter name */
  2107. tds_put_byte(tds, 1); /* output parameter */
  2108. tds_put_byte(tds, SYBINTN);
  2109. tds_put_byte(tds, 4);
  2110. tds_put_byte(tds, 4);
  2111. tds_put_int(tds, definition_len ? cursor->type | 0x1000 : cursor->type);
  2112. /* concurrency */
  2113. tds_put_byte(tds, 0); /* no parameter name */
  2114. tds_put_byte(tds, 1); /* output parameter */
  2115. tds_put_byte(tds, SYBINTN);
  2116. tds_put_byte(tds, 4);
  2117. tds_put_byte(tds, 4);
  2118. tds_put_int(tds, cursor->concurrency);
  2119. /* row count */
  2120. tds_put_byte(tds, 0);
  2121. tds_put_byte(tds, 1); /* output parameter */
  2122. tds_put_byte(tds, SYBINTN);
  2123. tds_put_byte(tds, 4);
  2124. tds_put_byte(tds, 4);
  2125. tds_put_int(tds, 0);
  2126. if (definition_len) {
  2127. int i;
  2128. tds7_put_params_definition(tds, param_definition, definition_len);
  2129. for (i = 0; i < num_params; i++) {
  2130. TDSCOLUMN *param = params->columns[i];
  2131. /* TODO check error */
  2132. tds_put_data_info(tds, param, 0);
  2133. /* FIXME handle error */
  2134. tds_put_data(tds, param);
  2135. }
  2136. }
  2137. free(param_definition);
  2138. *something_to_send = 1;
  2139. tds->current_op = TDS_OP_CURSOROPEN;
  2140. tdsdump_log(TDS_DBG_ERROR, "tds_cursor_open (): RPC call set up \n");
  2141. }
  2142. tdsdump_log(TDS_DBG_ERROR, "tds_cursor_open (): cursor open completed\n");
  2143. return TDS_SUCCESS;
  2144. }
  2145. TDSRET
  2146. tds_cursor_setrows(TDSSOCKET * tds, TDSCURSOR * cursor, int *something_to_send)
  2147. {
  2148. CHECK_TDS_EXTRA(tds);
  2149. if (!cursor)
  2150. return TDS_FAIL;
  2151. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_setrows() cursor id = %d\n", cursor->cursor_id);
  2152. if (IS_TDS7_PLUS(tds->conn)) {
  2153. cursor->srv_status &= ~TDS_CUR_ISTAT_DECLARED;
  2154. cursor->srv_status |= TDS_CUR_ISTAT_CLOSED;
  2155. cursor->srv_status |= TDS_CUR_ISTAT_ROWCNT;
  2156. }
  2157. if (IS_TDS50(tds->conn)) {
  2158. if (!*something_to_send) {
  2159. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2160. return TDS_FAIL;
  2161. tds->out_flag = TDS_NORMAL;
  2162. }
  2163. if (tds->state != TDS_QUERYING || tds->out_flag != TDS_NORMAL)
  2164. return TDS_FAIL;
  2165. tds_set_cur_cursor(tds, cursor);
  2166. tds_put_byte(tds, TDS_CURINFO_TOKEN);
  2167. TDS_PUT_SMALLINT(tds, 12 + strlen(cursor->cursor_name));
  2168. /* length of data stream that follows */
  2169. /* tds_put_int(tds, tds->cursor->cursor_id); */ /* Cursor id */
  2170. tds_put_int(tds, 0);
  2171. TDS_PUT_BYTE(tds, strlen(cursor->cursor_name));
  2172. tds_put_n(tds, cursor->cursor_name, (int)strlen(cursor->cursor_name));
  2173. tds_put_byte(tds, 1); /* Command TDS_CUR_CMD_SETCURROWS */
  2174. tds_put_byte(tds, 0x00); /* Status - TDS_CUR_ISTAT_ROWCNT 0x0020 */
  2175. tds_put_byte(tds, 0x20); /* Status - TDS_CUR_ISTAT_ROWCNT 0x0020 */
  2176. tds_put_int(tds, cursor->cursor_rows); /* row count to set */
  2177. *something_to_send = 1;
  2178. }
  2179. return TDS_SUCCESS;
  2180. }
  2181. static void
  2182. tds7_put_cursor_fetch(TDSSOCKET * tds, TDS_INT cursor_id, TDS_TINYINT fetch_type, TDS_INT i_row, TDS_INT num_rows)
  2183. {
  2184. if (IS_TDS71_PLUS(tds->conn)) {
  2185. tds_put_smallint(tds, -1);
  2186. tds_put_smallint(tds, TDS_SP_CURSORFETCH);
  2187. } else {
  2188. TDS_PUT_N_AS_UCS2(tds, "sp_cursorfetch");
  2189. }
  2190. /* This flag tells the SP only to */
  2191. /* output a dummy metadata token */
  2192. tds_put_smallint(tds, 2);
  2193. /* input cursor handle (int) */
  2194. tds_put_byte(tds, 0); /* no parameter name */
  2195. tds_put_byte(tds, 0); /* input parameter */
  2196. tds_put_byte(tds, SYBINTN);
  2197. tds_put_byte(tds, 4);
  2198. tds_put_byte(tds, 4);
  2199. tds_put_int(tds, cursor_id);
  2200. /* fetch type - 2 = NEXT */
  2201. tds_put_byte(tds, 0); /* no parameter name */
  2202. tds_put_byte(tds, 0); /* input parameter */
  2203. tds_put_byte(tds, SYBINTN);
  2204. tds_put_byte(tds, 4);
  2205. tds_put_byte(tds, 4);
  2206. tds_put_int(tds, fetch_type);
  2207. /* row number */
  2208. tds_put_byte(tds, 0); /* no parameter name */
  2209. tds_put_byte(tds, 0); /* input parameter */
  2210. tds_put_byte(tds, SYBINTN);
  2211. tds_put_byte(tds, 4);
  2212. if ((fetch_type & 0x30) != 0) {
  2213. tds_put_byte(tds, 4);
  2214. tds_put_int(tds, i_row);
  2215. } else {
  2216. tds_put_byte(tds, 0);
  2217. }
  2218. /* number of rows to fetch */
  2219. tds_put_byte(tds, 0); /* no parameter name */
  2220. tds_put_byte(tds, 0); /* input parameter */
  2221. tds_put_byte(tds, SYBINTN);
  2222. tds_put_byte(tds, 4);
  2223. tds_put_byte(tds, 4);
  2224. tds_put_int(tds, num_rows);
  2225. }
  2226. TDSRET
  2227. tds_cursor_fetch(TDSSOCKET * tds, TDSCURSOR * cursor, TDS_CURSOR_FETCH fetch_type, TDS_INT i_row)
  2228. {
  2229. CHECK_TDS_EXTRA(tds);
  2230. if (!cursor)
  2231. return TDS_FAIL;
  2232. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_fetch() cursor id = %d\n", cursor->cursor_id);
  2233. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2234. return TDS_FAIL;
  2235. tds_set_cur_cursor(tds, cursor);
  2236. if (IS_TDS50(tds->conn)) {
  2237. size_t len = strlen(cursor->cursor_name);
  2238. size_t row_len = 0;
  2239. tds->out_flag = TDS_NORMAL;
  2240. tds_put_byte(tds, TDS_CURFETCH_TOKEN);
  2241. if (len > (255-10))
  2242. len = (255-10);
  2243. if (fetch_type == TDS_CURSOR_FETCH_ABSOLUTE || fetch_type == TDS_CURSOR_FETCH_RELATIVE)
  2244. row_len = 4;
  2245. /*tds_put_smallint(tds, 8); */
  2246. TDS_PUT_SMALLINT(tds, 6 + len + row_len); /* length of the data stream that follows */
  2247. /*tds_put_int(tds, cursor->cursor_id); *//* cursor id returned by the server */
  2248. tds_put_int(tds, 0);
  2249. TDS_PUT_BYTE(tds, len);
  2250. tds_put_n(tds, cursor->cursor_name, len);
  2251. tds_put_tinyint(tds, fetch_type);
  2252. /* optional argument to fetch row at absolute/relative position */
  2253. if (row_len)
  2254. tds_put_int(tds, i_row);
  2255. return tds_query_flush_packet(tds);
  2256. }
  2257. if (IS_TDS7_PLUS(tds->conn)) {
  2258. /* RPC call to sp_cursorfetch */
  2259. static const unsigned char mssql_fetch[7] = {
  2260. 0,
  2261. 2, /* TDS_CURSOR_FETCH_NEXT */
  2262. 4, /* TDS_CURSOR_FETCH_PREV */
  2263. 1, /* TDS_CURSOR_FETCH_FIRST */
  2264. 8, /* TDS_CURSOR_FETCH_LAST */
  2265. 0x10, /* TDS_CURSOR_FETCH_ABSOLUTE */
  2266. 0x20 /* TDS_CURSOR_FETCH_RELATIVE */
  2267. };
  2268. tds_start_query(tds, TDS_RPC);
  2269. /* TODO enum for 2 ... */
  2270. if (cursor->type == 2 && fetch_type == TDS_CURSOR_FETCH_ABSOLUTE) {
  2271. /* strangely dynamic cursor do not support absolute so emulate it with first + relative */
  2272. tds7_put_cursor_fetch(tds, cursor->cursor_id, 1, 0, 0);
  2273. /* TODO define constant */
  2274. tds_put_byte(tds, IS_TDS72_PLUS(tds->conn) ? 0xff : 0x80);
  2275. tds7_put_cursor_fetch(tds, cursor->cursor_id, 0x20, i_row, cursor->cursor_rows);
  2276. } else {
  2277. /* TODO check fetch_type ?? */
  2278. tds7_put_cursor_fetch(tds, cursor->cursor_id, mssql_fetch[fetch_type], i_row, cursor->cursor_rows);
  2279. }
  2280. tds->current_op = TDS_OP_CURSORFETCH;
  2281. return tds_query_flush_packet(tds);
  2282. }
  2283. tds_set_state(tds, TDS_IDLE);
  2284. return TDS_SUCCESS;
  2285. }
  2286. TDSRET
  2287. tds_cursor_get_cursor_info(TDSSOCKET *tds, TDSCURSOR *cursor, TDS_UINT *prow_number, TDS_UINT *prow_count)
  2288. {
  2289. int done_flags;
  2290. TDSRET retcode;
  2291. TDS_INT result_type;
  2292. CHECK_TDS_EXTRA(tds);
  2293. if (!cursor)
  2294. return TDS_FAIL;
  2295. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_get_cursor_info() cursor id = %d\n", cursor->cursor_id);
  2296. /* Assume not known */
  2297. assert(prow_number && prow_count);
  2298. *prow_number = 0;
  2299. *prow_count = 0;
  2300. if (IS_TDS7_PLUS(tds->conn)) {
  2301. /* Change state to querying */
  2302. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2303. return TDS_FAIL;
  2304. /* Remember the server has been sent a command for this cursor */
  2305. tds_set_cur_cursor(tds, cursor);
  2306. /* General initialization of server command */
  2307. tds_start_query(tds, TDS_RPC);
  2308. /* Create and send query to server */
  2309. if (IS_TDS71_PLUS(tds->conn)) {
  2310. tds_put_smallint(tds, -1);
  2311. tds_put_smallint(tds, TDS_SP_CURSORFETCH);
  2312. } else {
  2313. TDS_PUT_N_AS_UCS2(tds, "sp_cursorfetch");
  2314. }
  2315. /* This flag tells the SP only to */
  2316. /* output a dummy metadata token */
  2317. tds_put_smallint(tds, 2);
  2318. /* input cursor handle (int) */
  2319. tds_put_byte(tds, 0); /* no parameter name */
  2320. tds_put_byte(tds, 0); /* input parameter */
  2321. tds_put_byte(tds, SYBINTN);
  2322. tds_put_byte(tds, 4);
  2323. tds_put_byte(tds, 4);
  2324. tds_put_int(tds, cursor->cursor_id);
  2325. tds_put_byte(tds, 0); /* no parameter name */
  2326. tds_put_byte(tds, 0); /* input parameter */
  2327. tds_put_byte(tds, SYBINTN);
  2328. tds_put_byte(tds, 4);
  2329. tds_put_byte(tds, 4);
  2330. tds_put_int(tds, 0x100); /* FETCH_INFO */
  2331. /* row number */
  2332. tds_put_byte(tds, 0); /* no parameter name */
  2333. tds_put_byte(tds, 1); /* output parameter */
  2334. tds_put_byte(tds, SYBINTN);
  2335. tds_put_byte(tds, 4);
  2336. tds_put_byte(tds, 0);
  2337. /* number of rows fetched */
  2338. tds_put_byte(tds, 0); /* no parameter name */
  2339. tds_put_byte(tds, 1); /* output parameter */
  2340. tds_put_byte(tds, SYBINTN);
  2341. tds_put_byte(tds, 4);
  2342. tds_put_byte(tds, 0);
  2343. /* Adjust current state */
  2344. tds->current_op = TDS_OP_NONE;
  2345. if (TDS_FAILED(retcode=tds_query_flush_packet(tds)))
  2346. return retcode;
  2347. /* Process answer from server */
  2348. for (;;) {
  2349. retcode = tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_PROC);
  2350. tdsdump_log(TDS_DBG_FUNC, "tds_cursor_get_cursor_info: tds_process_tokens returned %d\n", retcode);
  2351. tdsdump_log(TDS_DBG_FUNC, " result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
  2352. result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
  2353. switch (retcode) {
  2354. case TDS_NO_MORE_RESULTS:
  2355. return TDS_SUCCESS;
  2356. case TDS_SUCCESS:
  2357. if (result_type==TDS_PARAM_RESULT) {
  2358. /* Status is updated when TDS_STATUS_RESULT token arrives, before the params are processed */
  2359. if (tds->has_status && tds->ret_status==0) {
  2360. TDSPARAMINFO *pinfo = tds->current_results;
  2361. /* Make sure the params retuned have the correct type and size */
  2362. if (pinfo && pinfo->num_cols==2
  2363. && pinfo->columns[0]->column_type==SYBINTN
  2364. && pinfo->columns[1]->column_type==SYBINTN
  2365. && pinfo->columns[0]->column_size==4
  2366. && pinfo->columns[1]->column_size==4) {
  2367. /* Take the values */
  2368. *prow_number = (TDS_UINT)(*(TDS_INT *) pinfo->columns[0]->column_data);
  2369. *prow_count = (TDS_UINT)(*(TDS_INT *) pinfo->columns[1]->column_data);
  2370. tdsdump_log(TDS_DBG_FUNC, "----------------> prow_number=%u, prow_count=%u\n",
  2371. *prow_count, *prow_number);
  2372. }
  2373. }
  2374. }
  2375. break;
  2376. default:
  2377. return retcode;
  2378. }
  2379. }
  2380. }
  2381. return TDS_SUCCESS;
  2382. }
  2383. TDSRET
  2384. tds_cursor_close(TDSSOCKET * tds, TDSCURSOR * cursor)
  2385. {
  2386. CHECK_TDS_EXTRA(tds);
  2387. if (!cursor)
  2388. return TDS_FAIL;
  2389. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_close() cursor id = %d\n", cursor->cursor_id);
  2390. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2391. return TDS_FAIL;
  2392. tds_set_cur_cursor(tds, cursor);
  2393. if (IS_TDS50(tds->conn)) {
  2394. tds->out_flag = TDS_NORMAL;
  2395. tds_put_byte(tds, TDS_CURCLOSE_TOKEN);
  2396. tds_put_smallint(tds, 5); /* length of the data stream that follows */
  2397. tds_put_int(tds, cursor->cursor_id); /* cursor id returned by the server is available now */
  2398. if (cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
  2399. tds_put_byte(tds, 0x01); /* Close option: TDS_CUR_COPT_DEALLOC */
  2400. cursor->status.dealloc = TDS_CURSOR_STATE_SENT;
  2401. }
  2402. else
  2403. tds_put_byte(tds, 0x00); /* Close option: TDS_CUR_COPT_UNUSED */
  2404. }
  2405. if (IS_TDS7_PLUS(tds->conn)) {
  2406. /* RPC call to sp_cursorclose */
  2407. tds_start_query(tds, TDS_RPC);
  2408. if (IS_TDS71_PLUS(tds->conn)) {
  2409. tds_put_smallint(tds, -1);
  2410. tds_put_smallint(tds, TDS_SP_CURSORCLOSE);
  2411. } else {
  2412. TDS_PUT_N_AS_UCS2(tds, "sp_cursorclose");
  2413. }
  2414. /* This flag tells the SP to output only a dummy metadata token */
  2415. tds_put_smallint(tds, 2);
  2416. /* input cursor handle (int) */
  2417. tds_put_byte(tds, 0); /* no parameter name */
  2418. tds_put_byte(tds, 0); /* input parameter */
  2419. tds_put_byte(tds, SYBINTN);
  2420. tds_put_byte(tds, 4);
  2421. tds_put_byte(tds, 4);
  2422. tds_put_int(tds, cursor->cursor_id);
  2423. tds->current_op = TDS_OP_CURSORCLOSE;
  2424. }
  2425. return tds_query_flush_packet(tds);
  2426. }
  2427. TDSRET
  2428. tds_cursor_setname(TDSSOCKET * tds, TDSCURSOR * cursor)
  2429. {
  2430. int len;
  2431. CHECK_TDS_EXTRA(tds);
  2432. if (!cursor)
  2433. return TDS_FAIL;
  2434. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_setname() cursor id = %d\n", cursor->cursor_id);
  2435. if (!IS_TDS7_PLUS(tds->conn))
  2436. return TDS_SUCCESS;
  2437. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2438. return TDS_FAIL;
  2439. tds_set_cur_cursor(tds, cursor);
  2440. /* RPC call to sp_cursoroption */
  2441. tds_start_query(tds, TDS_RPC);
  2442. if (IS_TDS71_PLUS(tds->conn)) {
  2443. tds_put_smallint(tds, -1);
  2444. tds_put_smallint(tds, TDS_SP_CURSOROPTION);
  2445. } else {
  2446. TDS_PUT_N_AS_UCS2(tds, "sp_cursoroption");
  2447. }
  2448. tds_put_smallint(tds, 0);
  2449. /* input cursor handle (int) */
  2450. tds_put_byte(tds, 0); /* no parameter name */
  2451. tds_put_byte(tds, 0); /* input parameter */
  2452. tds_put_byte(tds, SYBINTN);
  2453. tds_put_byte(tds, 4);
  2454. tds_put_byte(tds, 4);
  2455. tds_put_int(tds, cursor->cursor_id);
  2456. /* code, 2 == set cursor name */
  2457. tds_put_byte(tds, 0); /* no parameter name */
  2458. tds_put_byte(tds, 0); /* input parameter */
  2459. tds_put_byte(tds, SYBINTN);
  2460. tds_put_byte(tds, 4);
  2461. tds_put_byte(tds, 4);
  2462. tds_put_int(tds, 2);
  2463. /* cursor name */
  2464. tds_put_byte(tds, 0);
  2465. tds_put_byte(tds, 0);
  2466. /* TODO convert ?? */
  2467. tds_put_byte(tds, XSYBVARCHAR);
  2468. len = (int)strlen(cursor->cursor_name);
  2469. tds_put_smallint(tds, len);
  2470. if (IS_TDS71_PLUS(tds->conn))
  2471. tds_put_n(tds, tds->conn->collation, 5);
  2472. tds_put_smallint(tds, len);
  2473. tds_put_n(tds, cursor->cursor_name, len);
  2474. tds->current_op = TDS_OP_CURSOROPTION;
  2475. return tds_query_flush_packet(tds);
  2476. }
  2477. TDSRET
  2478. tds_cursor_update(TDSSOCKET * tds, TDSCURSOR * cursor, TDS_CURSOR_OPERATION op, TDS_INT i_row, TDSPARAMINFO *params)
  2479. {
  2480. CHECK_TDS_EXTRA(tds);
  2481. if (!cursor)
  2482. return TDS_FAIL;
  2483. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_update() cursor id = %d\n", cursor->cursor_id);
  2484. /* client must provide parameters for update */
  2485. if (op == TDS_CURSOR_UPDATE && (!params || params->num_cols <= 0))
  2486. return TDS_FAIL;
  2487. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2488. return TDS_FAIL;
  2489. tds_set_cur_cursor(tds, cursor);
  2490. if (IS_TDS50(tds->conn)) {
  2491. tds->out_flag = TDS_NORMAL;
  2492. /* FIXME finish*/
  2493. tds_set_state(tds, TDS_IDLE);
  2494. return TDS_FAIL;
  2495. }
  2496. if (IS_TDS7_PLUS(tds->conn)) {
  2497. /* RPC call to sp_cursorclose */
  2498. tds_start_query(tds, TDS_RPC);
  2499. if (IS_TDS71_PLUS(tds->conn)) {
  2500. tds_put_smallint(tds, -1);
  2501. tds_put_smallint(tds, TDS_SP_CURSOR);
  2502. } else {
  2503. TDS_PUT_N_AS_UCS2(tds, "sp_cursor");
  2504. }
  2505. tds_put_smallint(tds, 0);
  2506. /* input cursor handle (int) */
  2507. tds_put_byte(tds, 0); /* no parameter name */
  2508. tds_put_byte(tds, 0); /* input parameter */
  2509. tds_put_byte(tds, SYBINTN);
  2510. tds_put_byte(tds, 4);
  2511. tds_put_byte(tds, 4);
  2512. tds_put_int(tds, cursor->cursor_id);
  2513. /* cursor operation */
  2514. tds_put_byte(tds, 0); /* no parameter name */
  2515. tds_put_byte(tds, 0); /* input parameter */
  2516. tds_put_byte(tds, SYBINTN);
  2517. tds_put_byte(tds, 4);
  2518. tds_put_byte(tds, 4);
  2519. tds_put_int(tds, 32 | op);
  2520. /* row number */
  2521. tds_put_byte(tds, 0); /* no parameter name */
  2522. tds_put_byte(tds, 0); /* input parameter */
  2523. tds_put_byte(tds, SYBINTN);
  2524. tds_put_byte(tds, 4);
  2525. tds_put_byte(tds, 4);
  2526. tds_put_int(tds, i_row);
  2527. /* update require table name */
  2528. if (op == TDS_CURSOR_UPDATE) {
  2529. TDSCOLUMN *param;
  2530. unsigned int n, num_params;
  2531. const char *table_name = NULL;
  2532. size_t converted_table_len = 0;
  2533. const char *converted_table = NULL;
  2534. /* empty table name */
  2535. tds_put_byte(tds, 0);
  2536. tds_put_byte(tds, 0);
  2537. tds_put_byte(tds, XSYBNVARCHAR);
  2538. num_params = params->num_cols;
  2539. for (n = 0; n < num_params; ++n) {
  2540. param = params->columns[n];
  2541. if (!tds_dstr_isempty(&param->table_name)) {
  2542. table_name = tds_dstr_cstr(&param->table_name);
  2543. break;
  2544. }
  2545. }
  2546. if (table_name) {
  2547. converted_table =
  2548. tds_convert_string(tds, tds->conn->char_convs[client2ucs2],
  2549. table_name, (int)strlen(table_name), &converted_table_len);
  2550. if (!converted_table) {
  2551. /* FIXME not here, in the middle of a packet */
  2552. tds_set_state(tds, TDS_IDLE);
  2553. return TDS_FAIL;
  2554. }
  2555. }
  2556. TDS_PUT_SMALLINT(tds, converted_table_len);
  2557. if (IS_TDS71_PLUS(tds->conn))
  2558. tds_put_n(tds, tds->conn->collation, 5);
  2559. TDS_PUT_SMALLINT(tds, converted_table_len);
  2560. tds_put_n(tds, converted_table, converted_table_len);
  2561. tds_convert_string_free(table_name, converted_table);
  2562. /* output columns to update */
  2563. for (n = 0; n < num_params; ++n) {
  2564. param = params->columns[n];
  2565. /* TODO check error */
  2566. tds_put_data_info(tds, param, TDS_PUT_DATA_USE_NAME|TDS_PUT_DATA_PREFIX_NAME);
  2567. /* FIXME handle error */
  2568. tds_put_data(tds, param);
  2569. }
  2570. }
  2571. tds->current_op = TDS_OP_CURSOR;
  2572. }
  2573. return tds_query_flush_packet(tds);
  2574. }
  2575. /**
  2576. * Send a deallocation request to server
  2577. */
  2578. TDSRET
  2579. tds_cursor_dealloc(TDSSOCKET * tds, TDSCURSOR * cursor)
  2580. {
  2581. TDSRET res = TDS_SUCCESS;
  2582. CHECK_TDS_EXTRA(tds);
  2583. if (!cursor)
  2584. return TDS_FAIL;
  2585. if (cursor->srv_status == TDS_CUR_ISTAT_UNUSED || (cursor->srv_status & TDS_CUR_ISTAT_DEALLOC) != 0
  2586. || (IS_TDS7_PLUS(tds->conn) && (cursor->srv_status & TDS_CUR_ISTAT_CLOSED) != 0)) {
  2587. tds_cursor_deallocated(tds->conn, cursor);
  2588. return TDS_SUCCESS;
  2589. }
  2590. tdsdump_log(TDS_DBG_INFO1, "tds_cursor_dealloc() cursor id = %d\n", cursor->cursor_id);
  2591. if (IS_TDS50(tds->conn)) {
  2592. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2593. return TDS_FAIL;
  2594. tds_set_cur_cursor(tds, cursor);
  2595. tds->out_flag = TDS_NORMAL;
  2596. tds_put_byte(tds, TDS_CURCLOSE_TOKEN);
  2597. tds_put_smallint(tds, 5); /* length of the data stream that follows */
  2598. tds_put_int(tds, cursor->cursor_id); /* cursor id returned by the server is available now */
  2599. tds_put_byte(tds, 0x01); /* Close option: TDS_CUR_COPT_DEALLOC */
  2600. res = tds_query_flush_packet(tds);
  2601. }
  2602. /*
  2603. * in TDS 5 the cursor deallocate function involves
  2604. * a server interaction. The cursor will be freed
  2605. * when we receive acknowledgement of the cursor
  2606. * deallocate from the server. for TDS 7 we do it
  2607. * here...
  2608. */
  2609. if (IS_TDS7_PLUS(tds->conn)) {
  2610. if (cursor->status.dealloc == TDS_CURSOR_STATE_SENT ||
  2611. cursor->status.dealloc == TDS_CURSOR_STATE_REQUESTED) {
  2612. tdsdump_log(TDS_DBG_ERROR, "tds_cursor_dealloc(): freeing cursor \n");
  2613. }
  2614. }
  2615. return res;
  2616. }
  2617. /**
  2618. * Send a string to server while quoting it.
  2619. * \tds
  2620. * \param s string start
  2621. * \param end string end
  2622. */
  2623. static void
  2624. tds_quote_and_put(TDSSOCKET * tds, const char *s, const char *end)
  2625. {
  2626. char buf[256];
  2627. int i;
  2628. CHECK_TDS_EXTRA(tds);
  2629. for (i = 0; s != end; ++s) {
  2630. buf[i++] = *s;
  2631. if (*s == '\'')
  2632. buf[i++] = '\'';
  2633. if (i >= 254) {
  2634. tds_put_string(tds, buf, i);
  2635. i = 0;
  2636. }
  2637. }
  2638. tds_put_string(tds, buf, i);
  2639. }
  2640. /**
  2641. * Send a parameter to server.
  2642. * Parameters are converted to string and sent to server.
  2643. * \tds
  2644. * \param params parameters structure
  2645. * \param n number of parameter to send
  2646. * \returns TDS_FAIL or TDS_SUCCESS
  2647. */
  2648. static TDSRET
  2649. tds_put_param_as_string(TDSSOCKET * tds, TDSPARAMINFO * params, int n)
  2650. {
  2651. TDSCOLUMN *curcol = params->columns[n];
  2652. CONV_RESULT cr;
  2653. TDS_INT res;
  2654. TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
  2655. int src_len = curcol->column_cur_size;
  2656. int i;
  2657. char buf[256];
  2658. int quote = 0;
  2659. TDS_CHAR *save_src;
  2660. int converted = 0;
  2661. CHECK_TDS_EXTRA(tds);
  2662. CHECK_PARAMINFO_EXTRA(params);
  2663. if (src_len < 0) {
  2664. /* on TDS 4 and 5 TEXT/IMAGE cannot be NULL, use empty */
  2665. if (!IS_TDS7_PLUS(tds->conn) && (curcol->column_type == SYBIMAGE || curcol->column_type == SYBTEXT))
  2666. tds_put_string(tds, "''", 2);
  2667. else
  2668. tds_put_string(tds, "NULL", 4);
  2669. return TDS_SUCCESS;
  2670. }
  2671. if (is_blob_col(curcol))
  2672. src = ((TDSBLOB *)src)->textvalue;
  2673. save_src = src;
  2674. /* TODO I don't like copy&paste too much, see above -- freddy77 */
  2675. /* convert string if needed */
  2676. if (curcol->char_conv && curcol->char_conv->flags != TDS_ENCODING_MEMCPY) {
  2677. size_t output_size;
  2678. #if 0
  2679. /* TODO this case should be optimized */
  2680. /* we know converted bytes */
  2681. if (curcol->char_conv->client_charset.min_bytes_per_char == curcol->char_conv->client_charset.max_bytes_per_char
  2682. && curcol->char_conv->server_charset.min_bytes_per_char == curcol->char_conv->server_charset.max_bytes_per_char) {
  2683. converted_size = colsize * curcol->char_conv->server_charset.min_bytes_per_char / curcol->char_conv->client_charset.min_bytes_per_char;
  2684. } else {
  2685. #endif
  2686. /* we need to convert data before */
  2687. /* TODO this can be a waste of memory... */
  2688. converted = 1;
  2689. src = (TDS_CHAR*) tds_convert_string(tds, curcol->char_conv, src, src_len, &output_size);
  2690. src_len = (int) output_size;
  2691. if (!src)
  2692. /* conversion error, exit with an error */
  2693. return TDS_FAIL;
  2694. }
  2695. /* we could try to use only tds_convert but is not good in all cases */
  2696. switch (curcol->column_type) {
  2697. /* binary/char, do conversion in line */
  2698. case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY:
  2699. tds_put_n(tds, "0x", 2);
  2700. for (i=0; src_len; ++src, --src_len) {
  2701. buf[i++] = tds_hex_digits[*src >> 4 & 0xF];
  2702. buf[i++] = tds_hex_digits[*src & 0xF];
  2703. if (i == 256) {
  2704. tds_put_string(tds, buf, i);
  2705. i = 0;
  2706. }
  2707. }
  2708. tds_put_string(tds, buf, i);
  2709. break;
  2710. /* char, quote as necessary */
  2711. case SYBNVARCHAR: case SYBNTEXT: case XSYBNCHAR: case XSYBNVARCHAR:
  2712. tds_put_string(tds, "N", 1);
  2713. case SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: case XSYBVARCHAR:
  2714. tds_put_string(tds, "\'", 1);
  2715. tds_quote_and_put(tds, src, src + src_len);
  2716. tds_put_string(tds, "\'", 1);
  2717. break;
  2718. /* TODO date, use iso format */
  2719. case SYBDATETIME:
  2720. case SYBDATETIME4:
  2721. case SYBDATETIMN:
  2722. case SYBMSTIME:
  2723. case SYBMSDATE:
  2724. case SYBMSDATETIME2:
  2725. case SYBMSDATETIMEOFFSET:
  2726. /* TODO use an ISO context */
  2727. case SYBUNIQUE:
  2728. quote = 1;
  2729. default:
  2730. res = tds_convert(tds_get_ctx(tds), tds_get_conversion_type(curcol->column_type, curcol->column_size), src, src_len, SYBCHAR, &cr);
  2731. if (res < 0)
  2732. return TDS_FAIL;
  2733. if (quote)
  2734. tds_put_string(tds, "\'", 1);
  2735. tds_quote_and_put(tds, cr.c, cr.c + res);
  2736. if (quote)
  2737. tds_put_string(tds, "\'", 1);
  2738. free(cr.c);
  2739. }
  2740. if (converted)
  2741. tds_convert_string_free(save_src, src);
  2742. return TDS_SUCCESS;
  2743. }
  2744. /**
  2745. * Emulate prepared execute traslating to a normal language
  2746. */
  2747. static TDSRET
  2748. tds_send_emulated_execute(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params)
  2749. {
  2750. int num_placeholders, i;
  2751. const char *s, *e;
  2752. CHECK_TDS_EXTRA(tds);
  2753. assert(query);
  2754. num_placeholders = tds_count_placeholders(query);
  2755. if (num_placeholders && num_placeholders > params->num_cols)
  2756. return TDS_FAIL;
  2757. /*
  2758. * NOTE: even for TDS5 we use this packet so to avoid computing
  2759. * entire sql command
  2760. */
  2761. tds_start_query(tds, TDS_QUERY);
  2762. if (!num_placeholders) {
  2763. tds_put_string(tds, query, -1);
  2764. return TDS_SUCCESS;
  2765. }
  2766. s = query;
  2767. for (i = 0;; ++i) {
  2768. e = tds_next_placeholder(s);
  2769. tds_put_string(tds, s, (int)(e ? e - s : -1));
  2770. if (!e)
  2771. break;
  2772. /* now translate parameter in string */
  2773. tds_put_param_as_string(tds, params, i);
  2774. s = e + 1;
  2775. }
  2776. return TDS_SUCCESS;
  2777. }
  2778. enum { MUL_STARTED = 1 };
  2779. TDSRET
  2780. tds_multiple_init(TDSSOCKET *tds, TDSMULTIPLE *multiple, TDS_MULTIPLE_TYPE type, TDSHEADERS * head)
  2781. {
  2782. unsigned char packet_type;
  2783. multiple->type = type;
  2784. multiple->flags = 0;
  2785. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2786. return TDS_FAIL;
  2787. packet_type = TDS_QUERY;
  2788. switch (type) {
  2789. case TDS_MULTIPLE_QUERY:
  2790. break;
  2791. case TDS_MULTIPLE_EXECUTE:
  2792. case TDS_MULTIPLE_RPC:
  2793. if (IS_TDS7_PLUS(tds->conn))
  2794. packet_type = TDS_RPC;
  2795. break;
  2796. }
  2797. if (tds_start_query_head(tds, packet_type, head) != TDS_SUCCESS)
  2798. return TDS_FAIL;
  2799. return TDS_SUCCESS;
  2800. }
  2801. TDSRET
  2802. tds_multiple_done(TDSSOCKET *tds, TDSMULTIPLE *multiple)
  2803. {
  2804. assert(tds && multiple);
  2805. return tds_query_flush_packet(tds);
  2806. }
  2807. TDSRET
  2808. tds_multiple_query(TDSSOCKET *tds, TDSMULTIPLE *multiple, const char *query, TDSPARAMINFO * params)
  2809. {
  2810. assert(multiple->type == TDS_MULTIPLE_QUERY);
  2811. if (multiple->flags & MUL_STARTED)
  2812. tds_put_string(tds, " ", 1);
  2813. multiple->flags |= MUL_STARTED;
  2814. return tds_send_emulated_execute(tds, query, params);
  2815. }
  2816. TDSRET
  2817. tds_multiple_execute(TDSSOCKET *tds, TDSMULTIPLE *multiple, TDSDYNAMIC * dyn)
  2818. {
  2819. assert(multiple->type == TDS_MULTIPLE_EXECUTE);
  2820. if (IS_TDS7_PLUS(tds->conn)) {
  2821. if (multiple->flags & MUL_STARTED) {
  2822. /* TODO define constant */
  2823. tds_put_byte(tds, IS_TDS72_PLUS(tds->conn) ? 0xff : 0x80);
  2824. }
  2825. multiple->flags |= MUL_STARTED;
  2826. tds7_send_execute(tds, dyn);
  2827. return TDS_SUCCESS;
  2828. }
  2829. if (multiple->flags & MUL_STARTED)
  2830. tds_put_string(tds, " ", 1);
  2831. multiple->flags |= MUL_STARTED;
  2832. return tds_send_emulated_execute(tds, dyn->query, dyn->params);
  2833. }
  2834. /**
  2835. * Send option commands to server.
  2836. * Option commands are used to change server options.
  2837. * \tds
  2838. * \param command command type.
  2839. * \param option option to set/get.
  2840. * \param param parameter value
  2841. * \param param_size length of parameter value in bytes
  2842. */
  2843. TDSRET
  2844. tds_submit_optioncmd(TDSSOCKET * tds, TDS_OPTION_CMD command, TDS_OPTION option, TDS_OPTION_ARG *param, TDS_INT param_size)
  2845. {
  2846. char cmd[128];
  2847. char datefmt[4];
  2848. TDS_INT resulttype;
  2849. TDSCOLUMN *col;
  2850. CONV_RESULT dres;
  2851. int ctype;
  2852. unsigned char*src;
  2853. int srclen;
  2854. CHECK_TDS_EXTRA(tds);
  2855. tdsdump_log(TDS_DBG_FUNC, "tds_submit_optioncmd() \n");
  2856. if (IS_TDS50(tds->conn)) {
  2857. TDSRET rc;
  2858. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  2859. return TDS_FAIL;
  2860. tds->out_flag = TDS_NORMAL;
  2861. tds_put_byte(tds, TDS_OPTIONCMD_TOKEN);
  2862. tds_put_smallint(tds, 3 + param_size);
  2863. tds_put_byte(tds, command);
  2864. tds_put_byte(tds, option);
  2865. tds_put_byte(tds, param_size);
  2866. if (param_size)
  2867. tds_put_n(tds, param, param_size);
  2868. tds_query_flush_packet(tds);
  2869. rc = tds_process_simple_query(tds);
  2870. if (TDS_FAILED(rc))
  2871. return rc;
  2872. }
  2873. if (IS_TDS7_PLUS(tds->conn)) {
  2874. if (command == TDS_OPT_SET) {
  2875. TDSRET rc;
  2876. switch (option) {
  2877. case TDS_OPT_ANSINULL :
  2878. sprintf(cmd, "SET ANSI_NULLS %s", param->ti ? "ON" : "OFF");
  2879. break;
  2880. case TDS_OPT_ARITHABORTON :
  2881. strcpy(cmd, "SET ARITHABORT ON");
  2882. break;
  2883. case TDS_OPT_ARITHABORTOFF :
  2884. strcpy(cmd, "SET ARITHABORT OFF");
  2885. break;
  2886. case TDS_OPT_ARITHIGNOREON :
  2887. strcpy(cmd, "SET ARITHIGNORE ON");
  2888. break;
  2889. case TDS_OPT_ARITHIGNOREOFF :
  2890. strcpy(cmd, "SET ARITHIGNORE OFF");
  2891. break;
  2892. case TDS_OPT_CHAINXACTS :
  2893. sprintf(cmd, "SET IMPLICIT_TRANSACTIONS %s", param->ti ? "ON" : "OFF");
  2894. break;
  2895. case TDS_OPT_CURCLOSEONXACT :
  2896. sprintf(cmd, "SET CURSOR_CLOSE_ON_COMMIT %s", param->ti ? "ON" : "OFF");
  2897. break;
  2898. case TDS_OPT_NOCOUNT :
  2899. sprintf(cmd, "SET NOCOUNT %s", param->ti ? "ON" : "OFF");
  2900. break;
  2901. case TDS_OPT_QUOTED_IDENT :
  2902. sprintf(cmd, "SET QUOTED_IDENTIFIER %s", param->ti ? "ON" : "OFF");
  2903. break;
  2904. case TDS_OPT_TRUNCABORT :
  2905. sprintf(cmd, "SET ANSI_WARNINGS %s", param->ti ? "OFF" : "ON");
  2906. break;
  2907. case TDS_OPT_DATEFIRST :
  2908. sprintf(cmd, "SET DATEFIRST %d", param->ti);
  2909. break;
  2910. case TDS_OPT_DATEFORMAT :
  2911. switch (param->ti) {
  2912. case TDS_OPT_FMTDMY: strcpy(datefmt,"dmy"); break;
  2913. case TDS_OPT_FMTDYM: strcpy(datefmt,"dym"); break;
  2914. case TDS_OPT_FMTMDY: strcpy(datefmt,"mdy"); break;
  2915. case TDS_OPT_FMTMYD: strcpy(datefmt,"myd"); break;
  2916. case TDS_OPT_FMTYDM: strcpy(datefmt,"ydm"); break;
  2917. case TDS_OPT_FMTYMD: strcpy(datefmt,"ymd"); break;
  2918. }
  2919. sprintf(cmd, "SET DATEFORMAT %s", datefmt);
  2920. break;
  2921. case TDS_OPT_TEXTSIZE:
  2922. sprintf(cmd, "SET TEXTSIZE %d", (int) param->i);
  2923. break;
  2924. /* TODO */
  2925. case TDS_OPT_STAT_TIME:
  2926. case TDS_OPT_STAT_IO:
  2927. case TDS_OPT_ROWCOUNT:
  2928. case TDS_OPT_NATLANG:
  2929. case TDS_OPT_ISOLATION:
  2930. case TDS_OPT_AUTHON:
  2931. case TDS_OPT_CHARSET:
  2932. case TDS_OPT_SHOWPLAN:
  2933. case TDS_OPT_NOEXEC:
  2934. case TDS_OPT_PARSEONLY:
  2935. case TDS_OPT_GETDATA:
  2936. case TDS_OPT_FORCEPLAN:
  2937. case TDS_OPT_FORMATONLY:
  2938. case TDS_OPT_FIPSFLAG:
  2939. case TDS_OPT_RESTREES:
  2940. case TDS_OPT_IDENTITYON:
  2941. case TDS_OPT_CURREAD:
  2942. case TDS_OPT_CURWRITE:
  2943. case TDS_OPT_IDENTITYOFF:
  2944. case TDS_OPT_AUTHOFF:
  2945. break;
  2946. }
  2947. tds_submit_query(tds, cmd);
  2948. rc = tds_process_simple_query(tds);
  2949. if (TDS_FAILED(rc))
  2950. return rc;
  2951. }
  2952. if (command == TDS_OPT_LIST) {
  2953. int optionval = 0;
  2954. switch (option) {
  2955. case TDS_OPT_ANSINULL :
  2956. case TDS_OPT_ARITHABORTON :
  2957. case TDS_OPT_ARITHABORTOFF :
  2958. case TDS_OPT_ARITHIGNOREON :
  2959. case TDS_OPT_ARITHIGNOREOFF :
  2960. case TDS_OPT_CHAINXACTS :
  2961. case TDS_OPT_CURCLOSEONXACT :
  2962. case TDS_OPT_NOCOUNT :
  2963. case TDS_OPT_QUOTED_IDENT :
  2964. case TDS_OPT_TRUNCABORT :
  2965. tdsdump_log(TDS_DBG_FUNC, "SELECT @@options\n");
  2966. strcpy(cmd, "SELECT @@options");
  2967. break;
  2968. case TDS_OPT_DATEFIRST :
  2969. strcpy(cmd, "SELECT @@datefirst");
  2970. break;
  2971. case TDS_OPT_DATEFORMAT :
  2972. strcpy(cmd, "SELECT DATEPART(dy,'01/02/03')");
  2973. break;
  2974. case TDS_OPT_TEXTSIZE:
  2975. strcpy(cmd, "SELECT @@textsize");
  2976. break;
  2977. /* TODO */
  2978. case TDS_OPT_STAT_TIME:
  2979. case TDS_OPT_STAT_IO:
  2980. case TDS_OPT_ROWCOUNT:
  2981. case TDS_OPT_NATLANG:
  2982. case TDS_OPT_ISOLATION:
  2983. case TDS_OPT_AUTHON:
  2984. case TDS_OPT_CHARSET:
  2985. case TDS_OPT_SHOWPLAN:
  2986. case TDS_OPT_NOEXEC:
  2987. case TDS_OPT_PARSEONLY:
  2988. case TDS_OPT_GETDATA:
  2989. case TDS_OPT_FORCEPLAN:
  2990. case TDS_OPT_FORMATONLY:
  2991. case TDS_OPT_FIPSFLAG:
  2992. case TDS_OPT_RESTREES:
  2993. case TDS_OPT_IDENTITYON:
  2994. case TDS_OPT_CURREAD:
  2995. case TDS_OPT_CURWRITE:
  2996. case TDS_OPT_IDENTITYOFF:
  2997. case TDS_OPT_AUTHOFF:
  2998. default:
  2999. tdsdump_log(TDS_DBG_FUNC, "what!\n");
  3000. }
  3001. tds_submit_query(tds, cmd);
  3002. while (tds_process_tokens(tds, &resulttype, NULL, TDS_TOKEN_RESULTS) == TDS_SUCCESS) {
  3003. switch (resulttype) {
  3004. case TDS_ROWFMT_RESULT:
  3005. break;
  3006. case TDS_ROW_RESULT:
  3007. while (tds_process_tokens(tds, &resulttype, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW) == TDS_SUCCESS) {
  3008. if (resulttype != TDS_ROW_RESULT)
  3009. break;
  3010. if (!tds->current_results)
  3011. continue;
  3012. col = tds->current_results->columns[0];
  3013. ctype = tds_get_conversion_type(col->column_type, col->column_size);
  3014. src = col->column_data;
  3015. srclen = col->column_cur_size;
  3016. tds_convert(tds_get_ctx(tds), ctype, (TDS_CHAR *) src, srclen, SYBINT4, &dres);
  3017. optionval = dres.i;
  3018. }
  3019. break;
  3020. default:
  3021. break;
  3022. }
  3023. }
  3024. tdsdump_log(TDS_DBG_FUNC, "optionval = %d\n", optionval);
  3025. switch (option) {
  3026. case TDS_OPT_CHAINXACTS :
  3027. tds->option_value = (optionval & 0x02) > 0;
  3028. break;
  3029. case TDS_OPT_CURCLOSEONXACT :
  3030. tds->option_value = (optionval & 0x04) > 0;
  3031. break;
  3032. case TDS_OPT_TRUNCABORT :
  3033. tds->option_value = (optionval & 0x08) > 0;
  3034. break;
  3035. case TDS_OPT_ANSINULL :
  3036. tds->option_value = (optionval & 0x20) > 0;
  3037. break;
  3038. case TDS_OPT_ARITHABORTON :
  3039. tds->option_value = (optionval & 0x40) > 0;
  3040. break;
  3041. case TDS_OPT_ARITHABORTOFF :
  3042. tds->option_value = (optionval & 0x40) > 0;
  3043. break;
  3044. case TDS_OPT_ARITHIGNOREON :
  3045. tds->option_value = (optionval & 0x80) > 0;
  3046. break;
  3047. case TDS_OPT_ARITHIGNOREOFF :
  3048. tds->option_value = (optionval & 0x80) > 0;
  3049. break;
  3050. case TDS_OPT_QUOTED_IDENT :
  3051. tds->option_value = (optionval & 0x0100) > 0;
  3052. break;
  3053. case TDS_OPT_NOCOUNT :
  3054. tds->option_value = (optionval & 0x0200) > 0;
  3055. break;
  3056. case TDS_OPT_TEXTSIZE:
  3057. case TDS_OPT_DATEFIRST :
  3058. tds->option_value = optionval;
  3059. break;
  3060. case TDS_OPT_DATEFORMAT :
  3061. switch (optionval) {
  3062. case 61: tds->option_value = TDS_OPT_FMTYDM; break;
  3063. case 34: tds->option_value = TDS_OPT_FMTYMD; break;
  3064. case 32: tds->option_value = TDS_OPT_FMTDMY; break;
  3065. case 60: tds->option_value = TDS_OPT_FMTYDM; break;
  3066. case 2: tds->option_value = TDS_OPT_FMTMDY; break;
  3067. case 3: tds->option_value = TDS_OPT_FMTMYD; break;
  3068. }
  3069. break;
  3070. /* TODO */
  3071. case TDS_OPT_STAT_TIME:
  3072. case TDS_OPT_STAT_IO:
  3073. case TDS_OPT_ROWCOUNT:
  3074. case TDS_OPT_NATLANG:
  3075. case TDS_OPT_ISOLATION:
  3076. case TDS_OPT_AUTHON:
  3077. case TDS_OPT_CHARSET:
  3078. case TDS_OPT_SHOWPLAN:
  3079. case TDS_OPT_NOEXEC:
  3080. case TDS_OPT_PARSEONLY:
  3081. case TDS_OPT_GETDATA:
  3082. case TDS_OPT_FORCEPLAN:
  3083. case TDS_OPT_FORMATONLY:
  3084. case TDS_OPT_FIPSFLAG:
  3085. case TDS_OPT_RESTREES:
  3086. case TDS_OPT_IDENTITYON:
  3087. case TDS_OPT_CURREAD:
  3088. case TDS_OPT_CURWRITE:
  3089. case TDS_OPT_IDENTITYOFF:
  3090. case TDS_OPT_AUTHOFF:
  3091. break;
  3092. }
  3093. tdsdump_log(TDS_DBG_FUNC, "tds_submit_optioncmd: returned option_value = %d\n", tds->option_value);
  3094. }
  3095. }
  3096. return TDS_SUCCESS;
  3097. }
  3098. /**
  3099. * Send a rollback request.
  3100. * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
  3101. * \tds
  3102. * \sa tds_submit_commit, tds_submit_rollback
  3103. */
  3104. TDSRET
  3105. tds_submit_begin_tran(TDSSOCKET *tds)
  3106. {
  3107. CHECK_TDS_EXTRA(tds);
  3108. if (!IS_TDS72_PLUS(tds->conn))
  3109. return tds_submit_query(tds, "BEGIN TRANSACTION");
  3110. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  3111. return TDS_FAIL;
  3112. tds_start_query(tds, TDS7_TRANS);
  3113. /* begin transaction */
  3114. tds_put_smallint(tds, 5);
  3115. tds_put_byte(tds, 0); /* new transaction level TODO */
  3116. tds_put_byte(tds, 0); /* new transaction name */
  3117. return tds_query_flush_packet(tds);
  3118. }
  3119. /**
  3120. * Send a rollback request.
  3121. * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
  3122. * \tds
  3123. * \param cont true to start a new transaction
  3124. * \sa tds_submit_begin_tran, tds_submit_commit
  3125. */
  3126. TDSRET
  3127. tds_submit_rollback(TDSSOCKET *tds, int cont)
  3128. {
  3129. CHECK_TDS_EXTRA(tds);
  3130. if (!IS_TDS72_PLUS(tds->conn))
  3131. return tds_submit_query(tds, cont ? "IF @@TRANCOUNT > 0 ROLLBACK BEGIN TRANSACTION" : "IF @@TRANCOUNT > 0 ROLLBACK");
  3132. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  3133. return TDS_FAIL;
  3134. tds_start_query(tds, TDS7_TRANS);
  3135. tds_put_smallint(tds, 8); /* rollback */
  3136. tds_put_byte(tds, 0); /* name */
  3137. if (cont) {
  3138. tds_put_byte(tds, 1);
  3139. tds_put_byte(tds, 0); /* new transaction level TODO */
  3140. tds_put_byte(tds, 0); /* new transaction name */
  3141. } else {
  3142. tds_put_byte(tds, 0); /* do not continue */
  3143. }
  3144. return tds_query_flush_packet(tds);
  3145. }
  3146. /**
  3147. * Send a commit request.
  3148. * TDS 7.2+ need this in order to handle transactions correctly if MARS is used.
  3149. * \tds
  3150. * \param cont true to start a new transaction
  3151. * \sa tds_submit_rollback, tds_submit_begin_tran
  3152. */
  3153. TDSRET
  3154. tds_submit_commit(TDSSOCKET *tds, int cont)
  3155. {
  3156. CHECK_TDS_EXTRA(tds);
  3157. if (!IS_TDS72_PLUS(tds->conn))
  3158. return tds_submit_query(tds, cont ? "IF @@TRANCOUNT > 0 COMMIT BEGIN TRANSACTION" : "IF @@TRANCOUNT > 0 COMMIT");
  3159. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)
  3160. return TDS_FAIL;
  3161. tds_start_query(tds, TDS7_TRANS);
  3162. tds_put_smallint(tds, 7); /* commit */
  3163. tds_put_byte(tds, 0); /* name */
  3164. if (cont) {
  3165. tds_put_byte(tds, 1);
  3166. tds_put_byte(tds, 0); /* new transaction level TODO */
  3167. tds_put_byte(tds, 0); /* new transaction name */
  3168. } else {
  3169. tds_put_byte(tds, 0); /* do not continue */
  3170. }
  3171. return tds_query_flush_packet(tds);
  3172. }
  3173. static const TDSCONTEXT empty_ctx;
  3174. TDSRET
  3175. tds_disconnect(TDSSOCKET * tds)
  3176. {
  3177. TDS_INT old_timeout;
  3178. const TDSCONTEXT *old_ctx;
  3179. CHECK_TDS_EXTRA(tds);
  3180. tdsdump_log(TDS_DBG_FUNC, "tds_disconnect() \n");
  3181. if (!IS_TDS50(tds->conn))
  3182. return TDS_SUCCESS;
  3183. old_timeout = tds->query_timeout;
  3184. old_ctx = tds_get_ctx(tds);
  3185. /* avoid to stall forever */
  3186. tds->query_timeout = 5;
  3187. /* do not report errors to upper libraries */
  3188. tds_set_ctx(tds, &empty_ctx);
  3189. if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING) {
  3190. tds->query_timeout = old_timeout;
  3191. tds_set_ctx(tds, old_ctx);
  3192. return TDS_FAIL;
  3193. }
  3194. tds->out_flag = TDS_NORMAL;
  3195. tds_put_byte(tds, TDS_LOGOUT_TOKEN);
  3196. tds_put_byte(tds, 0);
  3197. tds_query_flush_packet(tds);
  3198. return tds_process_simple_query(tds);
  3199. }
  3200. /*
  3201. * TODO add function to return type suitable for param
  3202. * ie:
  3203. * sybvarchar -> sybvarchar / xsybvarchar
  3204. * sybint4 -> sybintn
  3205. */
  3206. /** @} */