PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/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

Large files files are truncated, but you can click here to view the full file

  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_DE

Large files files are truncated, but you can click here to view the full file