PageRenderTime 92ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/dblib/dblib.c

https://gitlab.com/xk/FreeTDS
C | 8050 lines | 5049 code | 893 blank | 2108 comment | 840 complexity | 613ab4e5b267f6016141cd88ff0f7bbc 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-2015 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 <freetds/time.h>
  23. #include <assert.h>
  24. #include <stdio.h>
  25. #if HAVE_STDLIB_H
  26. #include <stdlib.h>
  27. #endif /* HAVE_STDLIB_H */
  28. #if HAVE_STRING_H
  29. #include <string.h>
  30. #endif /* HAVE_STRING_H */
  31. #if HAVE_UNISTD_H
  32. #include <unistd.h>
  33. #endif /* HAVE_UNISTD_H */
  34. #if HAVE_ERRNO_H
  35. # include <errno.h>
  36. #endif /* HAVE_ERRNO_H */
  37. /**
  38. * \ingroup dblib_core
  39. * \remarks Either SYBDBLIB or MSDBLIB (not both) must be defined.
  40. * This affects how certain application-addressable
  41. * strucures are defined.
  42. */
  43. #include <freetds/tds.h>
  44. #include <freetds/thread.h>
  45. #include <freetds/convert.h>
  46. #include <freetds/string.h>
  47. #include <freetds/data.h>
  48. #include <replacements.h>
  49. #include <sybfront.h>
  50. #include <sybdb.h>
  51. #include <syberror.h>
  52. #include <dblib.h>
  53. static RETCODE _dbresults(DBPROCESS * dbproc);
  54. static int _get_printable_size(TDSCOLUMN * colinfo);
  55. static char *_dbprdate(char *timestr);
  56. static int _dbnullable(DBPROCESS * dbproc, int column);
  57. static const char *tds_prdatatype(TDS_SERVER_TYPE datatype_token);
  58. static int default_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
  59. void copy_data_to_host_var(DBPROCESS *, int, const BYTE *, int, BYTE *, DBINT, int, DBINT *);
  60. RETCODE dbgetnull(DBPROCESS *dbproc, int bindtype, int varlen, BYTE* varaddr);
  61. /**
  62. * \file dblib.c
  63. * Main implementation file for \c db-lib.
  64. */
  65. /**
  66. * \file bcp.c
  67. * Implementation of \c db-lib bulk copy functions.
  68. */
  69. /**
  70. * \defgroup dblib_api The db-lib API
  71. * Functions callable by \c db-lib client programs
  72. *
  73. * The \c db_lib interface is implemented by both Sybase and Microsoft. FreeTDS seeks to implement
  74. * first the intersection of the functions defined by the vendors.
  75. */
  76. /**
  77. * \ingroup dblib_api
  78. * \defgroup dblib_core Primary functions
  79. * Core functions needed by most db-lib programs.
  80. */
  81. /**
  82. * \ingroup dblib_api
  83. * \defgroup dblib_rpc Remote Procedure functions
  84. * Functions used with stored procedures.
  85. * Especially useful for OUTPUT parameters, because modern Microsoft servers do not
  86. * return output parameter data to the client unless the procedure was invoked
  87. * with dbrpcsend().
  88. */
  89. /**
  90. * \ingroup dblib_api
  91. * \defgroup dblib_bcp Bulk copy functions
  92. * Functions to bulk-copy (a/k/a \em bcp) data to/from the database.
  93. */
  94. /**
  95. * \ingroup dblib_bcp
  96. * \defgroup dblib_bcp_internal Internal bcp functions
  97. * Static functions internal to the bcp library.
  98. */
  99. /**
  100. * \ingroup dblib_api
  101. * \defgroup dblib_money Money functions
  102. * Functions to manipulate the MONEY datatype.
  103. */
  104. /**
  105. * \ingroup dblib_api
  106. * \defgroup dblib_datetime Datetime functions
  107. * Functions to manipulate DBDATETIME structures. Defined by Sybase only.
  108. * These are not implemented:
  109. * - dbdate4cmp()
  110. * - dbdate4zero()
  111. * - dbdatechar()
  112. * - dbdatename()
  113. * - dbdateorder()
  114. * - dbdatepart()
  115. * - dbdatezero()
  116. * - dbdayname()
  117. */
  118. /**
  119. * \ingroup dblib_api
  120. * \defgroup dblib_internal Internals
  121. * Functions called within \c db-lib for self-help.
  122. * These functions are of interest only to people hacking on the FreeTDS db-lib implementation.
  123. */
  124. /**
  125. * \ingroup dblib_api
  126. * \defgroup dblib_unimplemented Unimplemented
  127. * Functions thus far not implemented in the FreeTDS db-lib implementation.
  128. * While some of these are simply awaiting someone with time and skill (and inclination)
  129. * it might be noted here that the old browse functions (e.g. dbcolbrowse())
  130. * are on the never-to-do list.
  131. * They were defined by Sybase and were superseded long ago, although they're still
  132. * present in Microsoft's implementation.
  133. * They were never popular and today better alternatives are available.
  134. * For completeness, they are:
  135. * - dbcolbrowse()
  136. * - dbcolsource()
  137. * - dbfreequal()
  138. * - dbqual()
  139. * - dbtabbrowse()
  140. * - dbtabcount()
  141. * - dbtabname()
  142. * - dbtabsource()
  143. * - dbtsnewlen()
  144. * - dbtsnewval()
  145. * - dbtsput()
  146. */
  147. /* info/err message handler functions (or rather pointers to them) */
  148. MHANDLEFUNC _dblib_msg_handler = NULL;
  149. EHANDLEFUNC _dblib_err_handler = default_err_handler;
  150. /** \internal
  151. * \dblib_internal
  152. * \remarks A db-lib connection has an implicit TDS context.
  153. */
  154. typedef struct dblib_context
  155. {
  156. /** reference count, time dbinit called */
  157. int ref_count;
  158. /** libTDS context */
  159. TDSCONTEXT *tds_ctx;
  160. /** libTDS context reference counter */
  161. int tds_ctx_ref_count;
  162. /* save all connection in a list */
  163. TDSSOCKET **connection_list;
  164. int connection_list_size;
  165. int connection_list_size_represented;
  166. char *recftos_filename;
  167. int recftos_filenum;
  168. int login_timeout; /**< not used unless positive */
  169. int query_timeout; /**< not used unless positive */
  170. }
  171. DBLIBCONTEXT;
  172. static DBLIBCONTEXT g_dblib_ctx;
  173. static tds_mutex dblib_mutex = TDS_MUTEX_INITIALIZER;
  174. static int g_dblib_version =
  175. #ifdef TDS42
  176. DBVERSION_42;
  177. #endif
  178. #ifdef TDS50
  179. DBVERSION_100;
  180. #endif
  181. #ifdef TDS46
  182. DBVERSION_46;
  183. #endif
  184. #ifdef TDS70
  185. DBVERSION_70;
  186. #endif
  187. #ifdef TDS71
  188. DBVERSION_71;
  189. #endif
  190. #ifdef TDS72
  191. DBVERSION_72;
  192. #endif
  193. #ifdef TDS73
  194. DBVERSION_73;
  195. #endif
  196. static int
  197. dblib_add_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds)
  198. {
  199. int i = 0;
  200. const int list_size = ctx->connection_list_size_represented;
  201. tdsdump_log(TDS_DBG_FUNC, "dblib_add_connection(%p, %p)\n", ctx, tds);
  202. while (i < list_size && ctx->connection_list[i])
  203. i++;
  204. if (i == list_size) {
  205. fprintf(stderr, "Max connections reached, increase value of TDS_MAX_CONN\n");
  206. return 1;
  207. } else {
  208. ctx->connection_list[i] = tds;
  209. return 0;
  210. }
  211. }
  212. static void
  213. dblib_del_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds)
  214. {
  215. int i = 0;
  216. const int list_size = ctx->connection_list_size;
  217. tdsdump_log(TDS_DBG_FUNC, "dblib_del_connection(%p, %p)\n", ctx, tds);
  218. while (i < list_size && ctx->connection_list[i] != tds)
  219. i++;
  220. if (i == list_size) {
  221. /* connection wasn't on the free list...now what */
  222. } else {
  223. /* remove it */
  224. ctx->connection_list[i] = NULL;
  225. }
  226. }
  227. static TDSCONTEXT*
  228. dblib_get_tds_ctx(void)
  229. {
  230. tdsdump_log(TDS_DBG_FUNC, "dblib_get_tds_ctx(void)\n");
  231. tds_mutex_lock(&dblib_mutex);
  232. ++g_dblib_ctx.tds_ctx_ref_count;
  233. if (g_dblib_ctx.tds_ctx == NULL) {
  234. g_dblib_ctx.tds_ctx = tds_alloc_context(&g_dblib_ctx);
  235. /*
  236. * Set the functions in the TDS layer to point to the correct handler functions
  237. */
  238. g_dblib_ctx.tds_ctx->msg_handler = _dblib_handle_info_message;
  239. g_dblib_ctx.tds_ctx->err_handler = _dblib_handle_err_message;
  240. g_dblib_ctx.tds_ctx->int_handler = _dblib_check_and_handle_interrupt;
  241. if (g_dblib_ctx.tds_ctx->locale && !g_dblib_ctx.tds_ctx->locale->date_fmt) {
  242. /* set default in case there's no locale file */
  243. const static char date_format[] =
  244. #ifndef _WIN32
  245. "%b %e %Y %I:%M:%S:%z%p";
  246. #else
  247. "%b %d %Y %I:%M:%S:%z%p";
  248. #endif
  249. g_dblib_ctx.tds_ctx->locale->date_fmt = strdup(date_format);
  250. }
  251. }
  252. tds_mutex_unlock(&dblib_mutex);
  253. return g_dblib_ctx.tds_ctx;
  254. }
  255. static void
  256. dblib_release_tds_ctx(int count)
  257. {
  258. tdsdump_log(TDS_DBG_FUNC, "dblib_release_tds_ctx(%d)\n", count);
  259. tds_mutex_lock(&dblib_mutex);
  260. g_dblib_ctx.tds_ctx_ref_count -= count;
  261. if (g_dblib_ctx.tds_ctx_ref_count <= 0) {
  262. tds_free_context(g_dblib_ctx.tds_ctx);
  263. g_dblib_ctx.tds_ctx = NULL;
  264. }
  265. tds_mutex_unlock(&dblib_mutex);
  266. }
  267. #include "buffering.h"
  268. static void
  269. db_env_chg(TDSSOCKET * tds, int type, char *oldval, char *newval)
  270. {
  271. DBPROCESS *dbproc;
  272. assert(oldval != NULL && newval != NULL);
  273. if (strlen(oldval) == 1 && *oldval == 1)
  274. oldval = "(0x1)";
  275. tdsdump_log(TDS_DBG_FUNC, "db_env_chg(%p, %d, %s, %s)\n", tds, type, oldval, newval);
  276. if (!tds || !tds_get_parent(tds))
  277. return;
  278. dbproc = (DBPROCESS *) tds_get_parent(tds);
  279. dbproc->envchange_rcv |= (1 << (type - 1));
  280. switch (type) {
  281. case TDS_ENV_DATABASE:
  282. tds_strlcpy(dbproc->dbcurdb, newval, sizeof(dbproc->dbcurdb));
  283. break;
  284. case TDS_ENV_CHARSET:
  285. tds_strlcpy(dbproc->servcharset, newval, sizeof(dbproc->servcharset));
  286. break;
  287. default:
  288. break;
  289. }
  290. return;
  291. }
  292. /** \internal
  293. * \ingroup dblib_internal
  294. * \brief Sanity checks for column-oriented functions.
  295. *
  296. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  297. * \param pcolinfo address of pointer to a TDSCOLUMN structure.
  298. * \remarks Makes sure dbproc and the requested column are valid.
  299. * Calls dbperror() if not.
  300. * \returns appropriate error or SUCCEED
  301. */
  302. static TDSCOLUMN*
  303. dbcolptr(DBPROCESS* dbproc, int column)
  304. {
  305. if (!dbproc) {
  306. dbperror(dbproc, SYBENULL, 0);
  307. return NULL;
  308. }
  309. if (IS_TDSDEAD(dbproc->tds_socket)) {
  310. dbperror(dbproc, SYBEDDNE, 0);
  311. return NULL;
  312. }
  313. if (!dbproc->tds_socket->res_info)
  314. return NULL;
  315. if (column < 1 || column > dbproc->tds_socket->res_info->num_cols) {
  316. dbperror(dbproc, SYBECNOR, 0);
  317. return NULL;
  318. }
  319. return dbproc->tds_socket->res_info->columns[column - 1];
  320. }
  321. static TDSCOLUMN*
  322. dbacolptr(DBPROCESS* dbproc, int computeid, int column, int is_bind)
  323. {
  324. int i;
  325. TDSSOCKET *tds;
  326. TDSCOMPUTEINFO *info;
  327. if (!dbproc) {
  328. dbperror(dbproc, SYBENULL, 0);
  329. return NULL;
  330. }
  331. tds = dbproc->tds_socket;
  332. if (IS_TDSDEAD(tds)) {
  333. dbperror(dbproc, SYBEDDNE, 0);
  334. return NULL;
  335. }
  336. for (i = 0;; ++i) {
  337. if (i >= tds->num_comp_info) {
  338. /* Attempt to bind user variable to a non-existent compute row */
  339. if (is_bind)
  340. dbperror(dbproc, SYBEBNCR, 0);
  341. return NULL;
  342. }
  343. info = tds->comp_info[i];
  344. if (info->computeid == computeid)
  345. break;
  346. }
  347. /* Fail if either the compute id or the column number is invalid. */
  348. if (column < 1 || column > info->num_cols) {
  349. dbperror(dbproc, is_bind ? SYBEABNC : SYBECNOR, 0);
  350. return NULL;
  351. }
  352. return info->columns[column - 1];
  353. }
  354. /*
  355. * Default null substitution values
  356. * Binding Type Null Substitution Value
  357. * TINYBIND 0
  358. * SMALLBIND 0
  359. * INTBIND 0
  360. * CHARBIND Empty string (padded with blanks)
  361. * STRINGBIND Empty string (padded with blanks, null-terminated)
  362. * NTBSTRINGBIND Empty string (null-terminated)
  363. * VARYCHARBIND Empty string
  364. * BINARYBIND Empty array (padded with zeros)
  365. * VARYBINBIND Empty array
  366. * DATETIMEBIND 8 bytes of zeros
  367. * SMALLDATETIMEBIND 8 bytes of zeros
  368. * MONEYBIND $0.00
  369. * SMALLMONEYBIND $0.00
  370. * FLT8BIND 0.0
  371. * REALBIND 0.0
  372. * DECIMALBIND 0.0 (with default scale and precision)
  373. * NUMERICBIND 0.0 (with default scale and precision)
  374. * BOUNDARYBIND Empty string (null-terminated)
  375. * SENSITIVITYBIND Empty string (null-terminated)
  376. */
  377. static const DBBIT null_BIT = 0;
  378. static const DBTINYINT null_TINYINT = 0;
  379. static const DBSMALLINT null_SMALLINT = 0;
  380. static const DBINT null_INT = 0;
  381. static const DBBIGINT null_BIGINT = 0;
  382. static const DBFLT8 null_FLT8 = 0;
  383. static const DBREAL null_REAL = 0;
  384. static const DBCHAR null_CHAR = '\0';
  385. static const DBVARYCHAR null_VARYCHAR = { 0, {0} };
  386. static const DBBINARY null_BINARY = 0;
  387. static const DBDATETIME null_DATETIME = { 0, 0 };
  388. static const DBDATETIME4 null_SMALLDATETIME = { 0, 0 };
  389. static const DBMONEY null_MONEY = { 0, 0 };
  390. static const DBMONEY4 null_SMALLMONEY = {0};
  391. static const DBNUMERIC null_NUMERIC = { 0, 0, {0} };
  392. static const TDS_DATETIMEALL null_DATETIMEALL = { 0, 0, 0, 0 };
  393. static NULLREP default_null_representations[MAXBINDTYPES] = {
  394. /* CHARBIND 0 */ { NULL, 0 }
  395. /* STRINGBIND 1 */ , { NULL, 0 }
  396. /* NTBSTRINGBIND 2 */ , { (BYTE*) &null_CHAR, sizeof(null_CHAR) }
  397. /* VARYCHARBIND 3 */ , { (BYTE*) &null_VARYCHAR, sizeof(null_VARYCHAR) }
  398. /* VARYBINBIND 4 */ , { (BYTE*) &null_VARYCHAR, sizeof(null_VARYCHAR) }
  399. /* no such bind 5 */ , { NULL, 0 }
  400. /* TINYBIND 6 */ , { &null_TINYINT, sizeof(null_TINYINT) }
  401. /* SMALLBIND 7 */ , { (BYTE*) &null_SMALLINT, sizeof(null_SMALLINT) }
  402. /* INTBIND 8 */ , { (BYTE*) &null_INT, sizeof(null_INT) }
  403. /* FLT8BIND 9 */ , { (BYTE*) &null_FLT8, sizeof(null_FLT8) }
  404. /* REALBIND 10 */ , { (BYTE*) &null_REAL, sizeof(null_REAL) }
  405. /* DATETIMEBIND 11 */ , { (BYTE*) &null_DATETIME, sizeof(null_DATETIME) }
  406. /* SMALLDATETIMEBIND 12 */ , { (BYTE*) &null_SMALLDATETIME, sizeof(null_SMALLDATETIME) }
  407. /* MONEYBIND 13 */ , { (BYTE*) &null_MONEY, sizeof(null_MONEY) }
  408. /* SMALLMONEYBIND 14 */ , { (BYTE*) &null_SMALLMONEY, sizeof(null_SMALLMONEY) }
  409. /* BINARYBIND 15 */ , { NULL, 0 }
  410. /* BITBIND 16 */ , { &null_BIT, sizeof(null_BIT) }
  411. /* NUMERICBIND 17 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
  412. /* DECIMALBIND 18 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
  413. /* SRCNUMERICBIND 19 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
  414. /* SRCDECIMALBIND 20 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
  415. /* 21 */ , { NULL, 0 }
  416. /* 22 */ , { NULL, 0 }
  417. /* 23 */ , { NULL, 0 }
  418. /* 24 */ , { NULL, 0 }
  419. /* 25 */ , { NULL, 0 }
  420. /* 26 */ , { NULL, 0 }
  421. /* 27 */ , { NULL, 0 }
  422. /* 28 */ , { NULL, 0 }
  423. /* 29 */ , { NULL, 0 }
  424. /* BIGINTBIND 30 */ , { (BYTE*) &null_BIGINT, sizeof(null_BIGINT) }
  425. /* DATETIME2BIND 31 */ , { (BYTE*) &null_DATETIMEALL, sizeof(null_DATETIMEALL) }
  426. /* MAXBINDTYPES 32 */
  427. };
  428. static int
  429. dbbindtype(int datatype)
  430. {
  431. switch (datatype) {
  432. case SYBIMAGE:
  433. case SYBVARBINARY:
  434. case SYBBINARY: return BINARYBIND;
  435. case SYBBIT: return BITBIND;
  436. case SYBTEXT:
  437. case SYBVARCHAR:
  438. case SYBCHAR: return NTBSTRINGBIND;
  439. case SYBDATETIME: return DATETIMEBIND;
  440. case SYBDATETIME4: return SMALLDATETIMEBIND;
  441. case SYBDECIMAL: return DECIMALBIND;
  442. case SYBNUMERIC: return NUMERICBIND;
  443. case SYBFLT8: return FLT8BIND;
  444. case SYBREAL: return REALBIND;
  445. case SYBINT1: return TINYBIND;
  446. case SYBINT2: return SMALLBIND;
  447. case SYBINT4: return INTBIND;
  448. case SYBINT8: return BIGINTBIND;
  449. case SYBMONEY: return MONEYBIND;
  450. case SYBMONEY4: return SMALLMONEYBIND;
  451. case SYBMSDATE:
  452. case SYBMSTIME:
  453. case SYBMSDATETIME2:
  454. case SYBMSDATETIMEOFFSET:
  455. return DATETIME2BIND;
  456. default:
  457. assert(0 == "no such datatype");
  458. }
  459. return 0;
  460. }
  461. /** \internal
  462. * dbbind() says: "Note that if varlen is 0, no padding takes place"
  463. * dbgetnull() will not pad varaddr unless varlen is positive.
  464. * Vartype Program Type Padding Terminator
  465. * ------------------- -------------- -------------- ----------
  466. * CHARBIND DBCHAR blanks none
  467. * STRINGBIND DBCHAR blanks \0
  468. * NTBSTRINGBIND DBCHAR none \0
  469. * VARYCHARBIND DBVARYCHAR none none
  470. * BOUNDARYBIND DBCHAR none \0
  471. * SENSITIVITYBIND DBCHAR none \0
  472. */
  473. RETCODE
  474. dbgetnull(DBPROCESS *dbproc, int bindtype, int varlen, BYTE* varaddr)
  475. {
  476. NULLREP *pnullrep = default_null_representations + bindtype;
  477. tdsdump_log(TDS_DBG_FUNC, "dbgetnull(%p, %d, %d, %p)\n", dbproc, bindtype, varlen, varaddr);
  478. CHECK_PARAMETER(varaddr, SYBENULL, FAIL);
  479. CHECK_PARAMETER(0 <= bindtype && bindtype < MAXBINDTYPES, SYBEBTYP, FAIL);
  480. if (!varaddr) {
  481. dbperror(dbproc, SYBENULP, 0, "dbgetnull", "varaddr");
  482. return FAIL;
  483. }
  484. /* dbproc can be NULL */
  485. if (NULL != dbproc) {
  486. assert(dbproc->nullreps);
  487. pnullrep = dbproc->nullreps + bindtype;
  488. }
  489. /*
  490. * Fixed types: ignore varlen
  491. * Other types: ignore varlen if <= 0, else varlen must be >= pnullrep->len.
  492. */
  493. switch (bindtype) {
  494. case DATETIMEBIND:
  495. case DECIMALBIND:
  496. case SRCDECIMALBIND:
  497. case FLT8BIND:
  498. case INTBIND:
  499. case MONEYBIND:
  500. case NUMERICBIND:
  501. case SRCNUMERICBIND:
  502. case REALBIND:
  503. case SMALLBIND:
  504. case SMALLDATETIMEBIND:
  505. case SMALLMONEYBIND:
  506. case TINYBIND:
  507. case BIGINTBIND:
  508. memcpy(varaddr, pnullrep->bindval, pnullrep->len);
  509. return SUCCEED;
  510. default:
  511. if (pnullrep->bindval && (varlen <= 0 || (size_t)varlen >= pnullrep->len)) {
  512. memcpy(varaddr, pnullrep->bindval, pnullrep->len);
  513. }
  514. }
  515. /*
  516. * For variable-length types, nonpositive varlen indicates
  517. * buffer is "big enough" but also not to pad.
  518. * Apply terminator (if applicable) and go home.
  519. */
  520. if (varlen <= 0) {
  521. switch (bindtype) {
  522. case STRINGBIND:
  523. case NTBSTRINGBIND:
  524. varaddr[pnullrep->len] = '\0';
  525. /* fall thru */
  526. case CHARBIND:
  527. case VARYCHARBIND:
  528. break;
  529. #if 0
  530. case BOUNDARYBIND:
  531. case SENSITIVITYBIND:
  532. #endif
  533. default:
  534. assert(!"unknown bindtype with unknown varlen");
  535. }
  536. return SUCCEED;
  537. }
  538. if (varlen < (long)pnullrep->len) {
  539. tdsdump_log(TDS_DBG_FUNC, "dbgetnull: error: not setting varaddr(%p) because %d < %lu\n",
  540. varaddr, varlen, (unsigned long int) pnullrep->len);
  541. return FAIL;
  542. }
  543. tdsdump_log(TDS_DBG_FUNC, "varaddr(%p) varlen %d < %lu?\n",
  544. varaddr, varlen, (unsigned long int) pnullrep->len);
  545. assert(varlen > 0);
  546. /*
  547. * CHARBIND Empty string (padded with blanks)
  548. * STRINGBIND Empty string (padded with blanks, null-terminated)
  549. * NTBSTRINGBIND Empty string (unpadded, null-terminated)
  550. * BINARYBIND Empty array (padded with zeros)
  551. */
  552. varaddr += pnullrep->len;
  553. varlen -= (int)pnullrep->len;
  554. if (varlen > 0) {
  555. switch (bindtype) {
  556. case CHARBIND:
  557. memset(varaddr, ' ', varlen);
  558. break;
  559. case STRINGBIND:
  560. memset(varaddr, ' ', varlen);
  561. varaddr[varlen-1] = '\0';
  562. break;
  563. case NTBSTRINGBIND:
  564. varaddr[0] = '\0';
  565. break;
  566. case BINARYBIND:
  567. memset(varaddr, 0, varlen);
  568. break;
  569. default:
  570. assert(!"unknown bindtype");
  571. }
  572. }
  573. return SUCCEED;
  574. }
  575. /**
  576. * \ingroup dblib_core
  577. * \brief Initialize db-lib.
  578. *
  579. * \remarks Call this function before trying to use db-lib in any way.
  580. * Allocates various internal structures and reads \c locales.conf (if any) to determine the default
  581. * date format.
  582. * \retval SUCCEED normal.
  583. * \retval FAIL cannot allocate an array of \c TDS_MAX_CONN \c TDSSOCKET pointers.
  584. */
  585. RETCODE
  586. dbinit(void)
  587. {
  588. _dblib_err_handler = default_err_handler;
  589. tds_mutex_lock(&dblib_mutex);
  590. tdsdump_log(TDS_DBG_FUNC, "dbinit(void)\n");
  591. if (++g_dblib_ctx.ref_count != 1) {
  592. tds_mutex_unlock(&dblib_mutex);
  593. return SUCCEED;
  594. }
  595. /*
  596. * DBLIBCONTEXT stores a list of current connections so they may be closed with dbexit()
  597. */
  598. g_dblib_ctx.connection_list = (TDSSOCKET**) calloc(TDS_MAX_CONN, sizeof(TDSSOCKET *));
  599. if (g_dblib_ctx.connection_list == NULL) {
  600. tdsdump_log(TDS_DBG_FUNC, "dbinit: out of memory\n");
  601. tds_mutex_unlock(&dblib_mutex);
  602. return FAIL;
  603. }
  604. g_dblib_ctx.connection_list_size = TDS_MAX_CONN;
  605. g_dblib_ctx.connection_list_size_represented = TDS_MAX_CONN;
  606. g_dblib_ctx.login_timeout = -1;
  607. g_dblib_ctx.query_timeout = -1;
  608. tds_mutex_unlock(&dblib_mutex);
  609. dblib_get_tds_ctx();
  610. return SUCCEED;
  611. }
  612. /**
  613. * \ingroup dblib_core
  614. * \brief Allocate a \c LOGINREC structure.
  615. *
  616. * \remarks A \c LOGINREC structure is passed to \c dbopen() to create a connection to the database.
  617. * Does not communicate to the server; interacts strictly with library.
  618. * \retval NULL the \c LOGINREC cannot be allocated.
  619. * \retval LOGINREC* to valid memory, otherwise.
  620. */
  621. LOGINREC *
  622. dblogin(void)
  623. {
  624. LOGINREC *loginrec;
  625. tdsdump_log(TDS_DBG_FUNC, "dblogin(void)\n");
  626. if ((loginrec = (LOGINREC*) malloc(sizeof(LOGINREC))) == NULL) {
  627. dbperror(NULL, SYBEMEM, errno);
  628. return NULL;
  629. }
  630. if ((loginrec->tds_login = tds_alloc_login(1)) == NULL) {
  631. dbperror(NULL, SYBEMEM, errno);
  632. free(loginrec);
  633. return NULL;
  634. }
  635. /* set default values for loginrec */
  636. tds_set_library(loginrec->tds_login, "DB-Library");
  637. return loginrec;
  638. }
  639. /**
  640. * \ingroup dblib_core
  641. * \brief free the \c LOGINREC
  642. *
  643. */
  644. void
  645. dbloginfree(LOGINREC * login)
  646. {
  647. tdsdump_log(TDS_DBG_FUNC, "dbloginfree(%p)\n", login);
  648. if (login) {
  649. tds_free_login(login->tds_login);
  650. TDS_ZERO_FREE(login);
  651. }
  652. }
  653. /** \internal
  654. * \ingroup dblib_internal
  655. * \brief Set the value of a string in a \c LOGINREC structure.
  656. *
  657. * Called by various macros to populate \a login.
  658. * \param login the \c LOGINREC* to modify.
  659. * \param value the value to set it to.
  660. * \param which the field to set.
  661. * \retval SUCCEED the value was set.
  662. * \retval FAIL \c DBSETHID or other invalid \a which was tried.
  663. */
  664. RETCODE
  665. dbsetlname(LOGINREC * login, const char *value, int which)
  666. {
  667. tdsdump_log(TDS_DBG_FUNC, "dbsetlname(%p, %s, %d)\n", login, value, which);
  668. if( login == NULL ) {
  669. dbperror(NULL, SYBEASNL, 0);
  670. return FAIL;
  671. }
  672. if (TDS_MAX_LOGIN_STR_SZ < strlen(value)) {
  673. dbperror(NULL, SYBENTLL, 0);
  674. return FAIL;
  675. }
  676. switch (which) {
  677. case DBSETHOST:
  678. tds_set_host(login->tds_login, value);
  679. return SUCCEED;
  680. break;
  681. case DBSETUSER:
  682. tds_set_user(login->tds_login, value);
  683. return SUCCEED;
  684. break;
  685. case DBSETPWD:
  686. tds_set_passwd(login->tds_login, value);
  687. return SUCCEED;
  688. break;
  689. case DBSETAPP:
  690. tds_set_app(login->tds_login, value);
  691. return SUCCEED;
  692. break;
  693. case DBSETCHARSET:
  694. tds_set_client_charset(login->tds_login, value ? value : "");
  695. return SUCCEED;
  696. break;
  697. case DBSETNATLANG:
  698. tds_set_language(login->tds_login, value);
  699. return SUCCEED;
  700. break;
  701. case DBSETDBNAME:
  702. if (!tds_dstr_copy(&login->tds_login->database, value ? value : ""))
  703. return FAIL;
  704. return SUCCEED;
  705. break;
  706. default:
  707. dbperror(NULL, SYBEASUL, 0); /* Attempt to set unknown LOGINREC field */
  708. return FAIL;
  709. break;
  710. }
  711. }
  712. /** \internal
  713. * \ingroup dblib_internal
  714. * \brief Set an integer value in a \c LOGINREC structure.
  715. *
  716. * Called by various macros to populate \a login.
  717. * \param login the \c LOGINREC* to modify.
  718. * \param value the value to set it to.
  719. * \param which the field to set.
  720. * \retval SUCCEED the value was set.
  721. * \retval FAIL anything other than \c DBSETPACKET was passed for \a which.
  722. */
  723. RETCODE
  724. dbsetllong(LOGINREC * login, long value, int which)
  725. {
  726. tdsdump_log(TDS_DBG_FUNC, "dbsetllong(%p, %ld, %d)\n", login, value, which);
  727. if( login == NULL ) {
  728. dbperror(NULL, SYBEASNL, 0);
  729. return FAIL;
  730. }
  731. switch (which) {
  732. case DBSETPACKET:
  733. if (0 <= value && value <= 999999) {
  734. tds_set_packet(login->tds_login, value);
  735. return SUCCEED;
  736. }
  737. dbperror(0, SYBEBADPK, 0, (int) value, (int) login->tds_login->block_size);
  738. return FAIL;
  739. break;
  740. default:
  741. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetllong() which = %d\n", which);
  742. return FAIL;
  743. break;
  744. }
  745. }
  746. #if defined(DBLIB_UNIMPLEMENTED)
  747. /** \internal
  748. * \ingroup dblib_internal
  749. * \brief Set an integer value in a \c LOGINREC structure.
  750. *
  751. * Called by various macros to populate \a login.
  752. * \param login the \c LOGINREC* to modify.
  753. * \param value the value to set it to.
  754. * \param which the field to set.
  755. * \retval SUCCEED the value was set.
  756. * \retval FAIL anything other than \c DBSETHIER was passed for \a which.
  757. */
  758. RETCODE
  759. dbsetlshort(LOGINREC * login, int value, int which)
  760. {
  761. tdsdump_log(TDS_DBG_FUNC, "dbsetlshort(%p, %d, %d)\n", login, value, which);
  762. if( login == NULL ) {
  763. dbperror(NULL, SYBEASNL, 0);
  764. return FAIL;
  765. }
  766. switch (which) {
  767. case DBSETHIER:
  768. default:
  769. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetlshort() which = %d\n", which);
  770. return FAIL;
  771. break;
  772. }
  773. }
  774. #endif
  775. /** \internal
  776. * \ingroup dblib_internal
  777. * \brief Set a boolean value in a \c LOGINREC structure.
  778. *
  779. * Called by various macros to populate \a login.
  780. * \param login the \c LOGINREC* to modify.
  781. * \param value the value to set it to.
  782. * \param which the field to set.
  783. * \remark Only DBSETBCP is implemented.
  784. * \retval SUCCEED the value was set.
  785. * \retval FAIL invalid value passed for \a which.
  786. * \todo DBSETNOSHORT, DBSETENCRYPT, DBSETLABELED
  787. */
  788. RETCODE
  789. dbsetlbool(LOGINREC * login, int value, int which)
  790. {
  791. tdsdump_log(TDS_DBG_FUNC, "dbsetlbool(%p, %d, %d)\n", login, value, which);
  792. if( login == NULL ) {
  793. dbperror(NULL, SYBEASNL, 0);
  794. return FAIL;
  795. }
  796. switch (which) {
  797. case DBSETBCP:
  798. tds_set_bulk(login->tds_login, (TDS_TINYINT) value);
  799. return SUCCEED;
  800. break;
  801. case DBSETENCRYPT:
  802. case DBSETLABELED:
  803. default:
  804. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetlbool() which = %d\n", which);
  805. return FAIL;
  806. break;
  807. }
  808. }
  809. /**
  810. * \ingroup dblib_core
  811. * \brief Set TDS version for future connections
  812. *
  813. */
  814. RETCODE
  815. dbsetlversion (LOGINREC * login, BYTE version)
  816. {
  817. tdsdump_log(TDS_DBG_FUNC, "dbsetlversion(%p, %x)\n", login, version);
  818. if( login == NULL ) {
  819. dbperror(NULL, SYBEASNL, 0);
  820. return FAIL;
  821. }
  822. assert(login->tds_login != NULL);
  823. switch (version) {
  824. case DBVER42:
  825. login->tds_login->tds_version = 0x402;
  826. return SUCCEED;
  827. case DBVER60:
  828. login->tds_login->tds_version = 0x700;
  829. return SUCCEED;
  830. case DBVERSION_100:
  831. tds_set_version(login->tds_login, 5, 0);
  832. return SUCCEED;
  833. case DBVERSION_71:
  834. tds_set_version(login->tds_login, 7, 1);
  835. return SUCCEED;
  836. case DBVERSION_72:
  837. tds_set_version(login->tds_login, 7, 2);
  838. return SUCCEED;
  839. case DBVERSION_73:
  840. tds_set_version(login->tds_login, 7, 3);
  841. return SUCCEED;
  842. }
  843. return FAIL;
  844. }
  845. static void
  846. dbstring_free(DBSTRING ** dbstrp)
  847. {
  848. DBSTRING *curr, *next;
  849. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_free(%p)\n", dbstrp); */
  850. if (!dbstrp)
  851. return;
  852. curr = *dbstrp;
  853. *dbstrp = NULL;
  854. for (; curr; ) {
  855. next = curr->strnext;
  856. free(curr->strtext);
  857. free(curr);
  858. curr = next;
  859. }
  860. }
  861. static RETCODE
  862. dbstring_concat(DBSTRING ** dbstrp, const char *p)
  863. {
  864. DBSTRING **strp = dbstrp;
  865. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_concat(%p, %s)\n", *dbstrp, p); */
  866. while (*strp != NULL) {
  867. strp = &((*strp)->strnext);
  868. }
  869. if ((*strp = (DBSTRING*) malloc(sizeof(DBSTRING))) == NULL) {
  870. dbperror(NULL, SYBEMEM, errno);
  871. return FAIL;
  872. }
  873. (*strp)->strtotlen = (DBINT)strlen(p);
  874. if (((*strp)->strtext = (BYTE*) malloc((*strp)->strtotlen)) == NULL) {
  875. TDS_ZERO_FREE(*strp);
  876. dbperror(NULL, SYBEMEM, errno);
  877. return FAIL;
  878. }
  879. memcpy((*strp)->strtext, p, (*strp)->strtotlen);
  880. (*strp)->strnext = NULL;
  881. return SUCCEED;
  882. }
  883. static RETCODE
  884. dbstring_assign(DBSTRING ** dbstrp, const char *p)
  885. {
  886. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_assign(%p, %s)\n", *dbstrp, p); */
  887. dbstring_free(dbstrp);
  888. return dbstring_concat(dbstrp, p);
  889. }
  890. static DBINT
  891. dbstring_length(DBSTRING * dbstr)
  892. {
  893. DBINT len = 0;
  894. DBSTRING *next;
  895. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_length(%p)\n", dbstr); */
  896. for (next = dbstr; next != NULL; next = next->strnext) {
  897. len += next->strtotlen;
  898. }
  899. return len;
  900. }
  901. static int
  902. dbstring_getchar(DBSTRING * dbstr, int i)
  903. {
  904. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_getchar(%p, %d)\n", dbstr, i); */
  905. if (dbstr == NULL) {
  906. return -1;
  907. }
  908. if (i < 0) {
  909. return -1;
  910. }
  911. if (i < dbstr->strtotlen) {
  912. return dbstr->strtext[i];
  913. }
  914. return dbstring_getchar(dbstr->strnext, i - dbstr->strtotlen);
  915. }
  916. static char *
  917. dbstring_get(DBSTRING * dbstr)
  918. {
  919. DBSTRING *next;
  920. int len;
  921. char *ret;
  922. char *cp;
  923. /* tdsdump_log(TDS_DBG_FUNC, "dbstring_get(%p)\n", dbstr); */
  924. if (dbstr == NULL) {
  925. return NULL;
  926. }
  927. len = dbstring_length(dbstr);
  928. if ((ret = (char*) malloc(len + 1)) == NULL) {
  929. dbperror(NULL, SYBEMEM, errno);
  930. return NULL;
  931. }
  932. cp = ret;
  933. for (next = dbstr; next != NULL; next = next->strnext) {
  934. memcpy(cp, next->strtext, next->strtotlen);
  935. cp += next->strtotlen;
  936. }
  937. *cp = '\0';
  938. return ret;
  939. }
  940. static const char *const opttext[DBNUMOPTIONS] = {
  941. "parseonly",
  942. "estimate",
  943. "showplan",
  944. "noexec",
  945. "arithignore",
  946. "nocount",
  947. "arithabort",
  948. "textlimit",
  949. "browse",
  950. "offsets",
  951. "statistics",
  952. "errlvl",
  953. "confirm",
  954. "spid",
  955. "buffer",
  956. "noautofree",
  957. "rowcount",
  958. "textsize",
  959. "language",
  960. "dateformat",
  961. "prpad",
  962. "prcolsep",
  963. "prlinelen",
  964. "prlinesep",
  965. "lfconvert",
  966. "datefirst",
  967. "chained",
  968. "fipsflagger",
  969. "transaction isolation level",
  970. "auth",
  971. "identity_insert",
  972. "no_identity_column",
  973. "cnv_date2char_short",
  974. "client cursors",
  975. "set time",
  976. "quoted_identifier"
  977. };
  978. static DBOPTION *
  979. init_dboptions(void)
  980. {
  981. DBOPTION *dbopts;
  982. int i;
  983. if ((dbopts = (DBOPTION*) calloc(DBNUMOPTIONS, sizeof(DBOPTION))) == NULL) {
  984. dbperror(NULL, SYBEMEM, errno);
  985. return NULL;
  986. }
  987. for (i = 0; i < DBNUMOPTIONS; i++) {
  988. tds_strlcpy(dbopts[i].text, opttext[i], sizeof(dbopts[i].text));
  989. dbopts[i].param = NULL;
  990. dbopts[i].factive = FALSE;
  991. }
  992. dbstring_assign(&(dbopts[DBPRPAD].param), " ");
  993. dbstring_assign(&(dbopts[DBPRCOLSEP].param), " ");
  994. dbstring_assign(&(dbopts[DBPRLINELEN].param), "80");
  995. dbstring_assign(&(dbopts[DBPRLINESEP].param), "\n");
  996. dbstring_assign(&(dbopts[DBCLIENTCURSORS].param), " ");
  997. dbstring_assign(&(dbopts[DBSETTIME].param), " ");
  998. return dbopts;
  999. }
  1000. /** \internal
  1001. * \ingroup dblib_internal
  1002. * \brief Form a connection with the server.
  1003. *
  1004. * Called by the \c dbopen() macro, normally. If FreeTDS was configured with \c --enable-msdblib, this
  1005. * function is called by (exported) \c dbopen() function. \c tdsdbopen is so-named to avoid
  1006. * namespace conflicts with other database libraries that use the same function name.
  1007. * \param login \c LOGINREC* carrying the account information.
  1008. * \param server name of the dataserver to connect to.
  1009. * \return valid pointer on successful login.
  1010. * \retval NULL insufficient memory, unable to connect for any reason.
  1011. * \sa dbopen()
  1012. * \todo use \c asprintf() to avoid buffer overflow.
  1013. * \todo separate error messages for \em no-such-server and \em no-such-user.
  1014. */
  1015. DBPROCESS *
  1016. tdsdbopen(LOGINREC * login, const char *server, int msdblib)
  1017. {
  1018. DBPROCESS *dbproc = NULL;
  1019. TDSLOGIN *connection;
  1020. char *tdsdump = getenv("TDSDUMP");
  1021. if (tdsdump && *tdsdump) {
  1022. tdsdump_open(tdsdump);
  1023. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen(%p, %s, [%s])\n", login, server? server : "0x0", msdblib? "microsoft" : "sybase");
  1024. }
  1025. /*
  1026. * Sybase supports the DSQUERY environment variable and falls back to "SYBASE" if server is NULL.
  1027. * Microsoft uses a NULL or "" server to indicate a local server.
  1028. * FIXME: support local server for win32.
  1029. */
  1030. if (!server && !msdblib) {
  1031. if ((server = getenv("TDSQUERY")) == NULL)
  1032. if ((server = getenv("DSQUERY")) == NULL)
  1033. server = "SYBASE";
  1034. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: servername set to %s\n", server);
  1035. }
  1036. if ((dbproc = (DBPROCESS*) calloc(1, sizeof(DBPROCESS))) == NULL) {
  1037. dbperror(NULL, SYBEMEM, errno);
  1038. return NULL;
  1039. }
  1040. dbproc->msdblib = msdblib;
  1041. dbproc->dbopts = init_dboptions();
  1042. if (dbproc->dbopts == NULL) {
  1043. free(dbproc);
  1044. return NULL;
  1045. }
  1046. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: dbproc->dbopts = %p\n", dbproc->dbopts);
  1047. dbproc->dboptcmd = NULL;
  1048. dbproc->avail_flag = TRUE;
  1049. dbproc->command_state = DBCMDNONE;
  1050. tds_set_server(login->tds_login, server);
  1051. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: tds_set_server(%p, \"%s\")\n", login->tds_login, server);
  1052. if ((dbproc->tds_socket = tds_alloc_socket(dblib_get_tds_ctx(), 512)) == NULL ){
  1053. dbperror(NULL, SYBEMEM, 0);
  1054. free(dbproc);
  1055. return NULL;
  1056. }
  1057. tds_set_parent(dbproc->tds_socket, dbproc);
  1058. dbproc->tds_socket->env_chg_func = db_env_chg;
  1059. dbproc->envchange_rcv = 0;
  1060. dbproc->dbcurdb[0] = '\0';
  1061. dbproc->servcharset[0] = '\0';
  1062. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: About to call tds_read_config_info...\n");
  1063. connection = tds_read_config_info(dbproc->tds_socket, login->tds_login, g_dblib_ctx.tds_ctx->locale);
  1064. if (!connection) {
  1065. dbclose(dbproc);
  1066. return NULL;
  1067. }
  1068. connection->option_flag2 &= ~0x02; /* we're not an ODBC driver */
  1069. tds_fix_login(connection); /* initialize from Environment variables */
  1070. dbproc->chkintr = NULL;
  1071. dbproc->hndlintr = NULL;
  1072. tds_mutex_lock(&dblib_mutex);
  1073. /* override connection timeout if dbsetlogintime() was called */
  1074. if (g_dblib_ctx.login_timeout > 0) {
  1075. connection->connect_timeout = g_dblib_ctx.login_timeout;
  1076. }
  1077. /* override query timeout if dbsettime() was called */
  1078. if (g_dblib_ctx.query_timeout > 0) {
  1079. connection->query_timeout = g_dblib_ctx.query_timeout;
  1080. }
  1081. tds_mutex_unlock(&dblib_mutex);
  1082. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: Calling tds_connect_and_login(%p, %p)\n",
  1083. dbproc->tds_socket, connection);
  1084. if (TDS_FAILED(tds_connect_and_login(dbproc->tds_socket, connection))) {
  1085. tdsdump_log(TDS_DBG_ERROR, "tdsdbopen: tds_connect_and_login failed for \"%s\"!\n",
  1086. tds_dstr_cstr(&connection->server_name));
  1087. tds_free_login(connection);
  1088. dbclose(dbproc);
  1089. return NULL;
  1090. }
  1091. tds_free_login(connection);
  1092. dbproc->dbbuf = NULL;
  1093. dbproc->dbbufsz = 0;
  1094. tds_mutex_lock(&dblib_mutex);
  1095. dblib_add_connection(&g_dblib_ctx, dbproc->tds_socket);
  1096. tds_mutex_unlock(&dblib_mutex);
  1097. /* set the DBBUFFER capacity to nil */
  1098. buffer_set_capacity(dbproc, 0);
  1099. tds_mutex_lock(&dblib_mutex);
  1100. if (g_dblib_ctx.recftos_filename != NULL) {
  1101. char *temp_filename = NULL;
  1102. const int len = asprintf(&temp_filename, "%s.%d",
  1103. g_dblib_ctx.recftos_filename, g_dblib_ctx.recftos_filenum);
  1104. if (len >= 0) {
  1105. dbproc->ftos = fopen(temp_filename, "w");
  1106. if (dbproc->ftos != NULL) {
  1107. fprintf(dbproc->ftos, "/* dbopen() at %s */\n", _dbprdate(temp_filename));
  1108. fflush(dbproc->ftos);
  1109. g_dblib_ctx.recftos_filenum++;
  1110. }
  1111. free(temp_filename);
  1112. }
  1113. }
  1114. memcpy(dbproc->nullreps, default_null_representations, sizeof(default_null_representations));
  1115. tds_mutex_unlock(&dblib_mutex);
  1116. tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: Returning dbproc = %p\n", dbproc);
  1117. return dbproc;
  1118. }
  1119. /**
  1120. * \ingroup dblib_core
  1121. * \brief \c printf-like way to form SQL to send to the server.
  1122. *
  1123. * Forms a command string and writes to the command buffer with dbcmd().
  1124. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1125. * \param fmt <tt> man vasprintf</tt> for details.
  1126. * \retval SUCCEED success.
  1127. * \retval FAIL insufficient memory, or dbcmd() failed.
  1128. * \sa dbcmd(), dbfreebuf(), dbgetchar(), dbopen(), dbstrcpy(), dbstrlen().
  1129. */
  1130. RETCODE
  1131. dbfcmd(DBPROCESS * dbproc, const char *fmt, ...)
  1132. {
  1133. va_list ap;
  1134. char *s;
  1135. int len;
  1136. RETCODE ret;
  1137. tdsdump_log(TDS_DBG_FUNC, "dbfcmd(%p, %s, ...)\n", dbproc, fmt);
  1138. CHECK_CONN(FAIL);
  1139. CHECK_NULP(fmt, "dbfcmd", 2, FAIL);
  1140. va_start(ap, fmt);
  1141. len = vasprintf(&s, fmt, ap);
  1142. va_end(ap);
  1143. if (len < 0) {
  1144. dbperror(dbproc, SYBEMEM, errno);
  1145. return FAIL;
  1146. }
  1147. ret = dbcmd(dbproc, s);
  1148. free(s);
  1149. return ret;
  1150. }
  1151. /**
  1152. * \ingroup dblib_core
  1153. * \brief \c Append SQL to the command buffer.
  1154. *
  1155. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1156. * \param cmdstring SQL to append to the command buffer.
  1157. * \retval SUCCEED success.
  1158. * \retval FAIL insufficient memory.
  1159. * \remarks set command state to \c DBCMDPEND unless the command state is DBCMDSENT, in which case
  1160. * it frees the command buffer. This latter may or may not be the Right Thing to do.
  1161. * \sa dbfcmd(), dbfreebuf(), dbgetchar(), dbopen(), dbstrcpy(), dbstrlen().
  1162. */
  1163. RETCODE
  1164. dbcmd(DBPROCESS * dbproc, const char cmdstring[])
  1165. {
  1166. tdsdump_log(TDS_DBG_FUNC, "dbcmd(%p, %s)\n", dbproc, cmdstring);
  1167. CHECK_CONN(FAIL);
  1168. CHECK_NULP(cmdstring, "dbcmd", 2, FAIL);
  1169. dbproc->avail_flag = FALSE;
  1170. tdsdump_log(TDS_DBG_FUNC, "dbcmd() bufsz = %d\n", dbproc->dbbufsz);
  1171. if (dbproc->command_state == DBCMDSENT) {
  1172. if (!dbproc->noautofree) {
  1173. dbfreebuf(dbproc);
  1174. }
  1175. }
  1176. if (dbproc->dbbufsz == 0) {
  1177. dbproc->dbbuf = (unsigned char*) malloc(strlen(cmdstring) + 1);
  1178. if (dbproc->dbbuf == NULL) {
  1179. dbperror(dbproc, SYBEMEM, errno);
  1180. return FAIL;
  1181. }
  1182. strcpy((char *) dbproc->dbbuf, cmdstring);
  1183. dbproc->dbbufsz = (int)strlen(cmdstring) + 1;
  1184. } else {
  1185. size_t newsz = strlen(cmdstring) + dbproc->dbbufsz;
  1186. if (!TDS_RESIZE(dbproc->dbbuf, newsz)) {
  1187. dbperror(dbproc, SYBEMEM, errno);
  1188. return FAIL;
  1189. }
  1190. strcat((char *) dbproc->dbbuf, cmdstring);
  1191. dbproc->dbbufsz = (int)newsz;
  1192. }
  1193. dbproc->command_state = DBCMDPEND;
  1194. return SUCCEED;
  1195. }
  1196. /**
  1197. * \ingroup dblib_core
  1198. * \brief send the SQL command to the server and wait for an answer.
  1199. *
  1200. * Please be patient. This function waits for the server to respond. \c dbsqlexec is equivalent
  1201. * to dbsqlsend() followed by dbsqlok().
  1202. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1203. * \retval SUCCEED query was processed without errors.
  1204. * \retval FAIL was returned by dbsqlsend() or dbsqlok().
  1205. * \sa dbcmd(), dbfcmd(), dbnextrow(), dbresults(), dbretstatus(), dbsettime(), dbsqlok(), dbsqlsend()
  1206. */
  1207. RETCODE
  1208. dbsqlexec(DBPROCESS * dbproc)
  1209. {
  1210. RETCODE rc = FAIL;
  1211. tdsdump_log(TDS_DBG_FUNC, "dbsqlexec(%p)\n", dbproc);
  1212. CHECK_CONN(FAIL);
  1213. if (SUCCEED == (rc = dbsqlsend(dbproc))) {
  1214. rc = dbsqlok(dbproc);
  1215. }
  1216. return rc;
  1217. }
  1218. /**
  1219. * \ingroup dblib_core
  1220. * \brief Change current database.
  1221. *
  1222. * Analagous to the unix command \c cd, dbuse() makes \a name the default database. Waits for an answer
  1223. * from the server.
  1224. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1225. * \param name database to use.
  1226. * \retval SUCCEED query was processed without errors.
  1227. * \retval FAIL query was not processed
  1228. * \sa dbchange(), dbname().
  1229. */
  1230. RETCODE
  1231. dbuse(DBPROCESS * dbproc, const char *name)
  1232. {
  1233. RETCODE rc;
  1234. char *query;
  1235. tdsdump_log(TDS_DBG_FUNC, "dbuse(%p, %s)\n", dbproc, name);
  1236. CHECK_CONN(FAIL);
  1237. CHECK_NULP(name, "dbuse", 2, FAIL);
  1238. if (!dbproc->tds_socket)
  1239. return FAIL;
  1240. /* quote name */
  1241. query = (char*) malloc(tds_quote_id(dbproc->tds_socket, NULL, name, -1) + 6);
  1242. if (!query) {
  1243. dbperror(dbproc, SYBEMEM, errno);
  1244. return FAIL;
  1245. }
  1246. strcpy(query, "use ");
  1247. /* TODO PHP suggest to quote by yourself with []... what should I do ?? quote or not ?? */
  1248. if (name[0] == '[' && name[strlen(name)-1] == ']')
  1249. strcat(query, name);
  1250. else
  1251. tds_quote_id(dbproc->tds_socket, query + 4, name, -1);
  1252. rc = SUCCEED;
  1253. if ((dbcmd(dbproc, query) == FAIL)
  1254. || (dbsqlexec(dbproc) == FAIL)
  1255. || (dbresults(dbproc) == FAIL)
  1256. || (dbcanquery(dbproc) == FAIL))
  1257. rc = FAIL;
  1258. free(query);
  1259. return rc;
  1260. }
  1261. /**
  1262. * \ingroup dblib_core
  1263. * \brief Close a connection to the server and free associated resources.
  1264. *
  1265. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1266. * \sa dbexit(), dbopen().
  1267. */
  1268. void
  1269. dbclose(DBPROCESS * dbproc)
  1270. {
  1271. TDSSOCKET *tds;
  1272. int i;
  1273. char timestr[256];
  1274. tdsdump_log(TDS_DBG_FUNC, "dbclose(%p)\n", dbproc);
  1275. CHECK_PARAMETER(dbproc, SYBENULL, );
  1276. tds = dbproc->tds_socket;
  1277. if (tds) {
  1278. /*
  1279. * this MUST be done before socket destruction
  1280. * it is possible that a TDSSOCKET is allocated on same position
  1281. */
  1282. tds_mutex_lock(&dblib_mutex);
  1283. dblib_del_connection(&g_dblib_ctx, dbproc->tds_socket);
  1284. tds_mutex_unlock(&dblib_mutex);
  1285. tds_close_socket(tds);
  1286. tds_free_socket(tds);
  1287. dblib_release_tds_ctx(1);
  1288. }
  1289. buffer_free(&(dbproc->row_buf));
  1290. if (dbproc->ftos != NULL) {
  1291. fprintf(dbproc->ftos, "/* dbclose() at %s */\n", _dbprdate(timestr));
  1292. fclose(dbproc->ftos);
  1293. }
  1294. if (dbproc->bcpinfo)
  1295. free(dbproc->bcpinfo->tablename);
  1296. if (dbproc->hostfileinfo) {
  1297. free(dbproc->hostfileinfo->hostfile);
  1298. free(dbproc->hostfileinfo->errorfile);
  1299. if (dbproc->hostfileinfo->host_columns) {
  1300. for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
  1301. free(dbproc->hostfileinfo->host_columns[i]->terminator);
  1302. free(dbproc->hostfileinfo->host_columns[i]);
  1303. }
  1304. free(dbproc->hostfileinfo->host_columns);
  1305. }
  1306. }
  1307. for (i = 0; i < DBNUMOPTIONS; i++) {
  1308. dbstring_free(&(dbproc->dbopts[i].param));
  1309. }
  1310. free(dbproc->dbopts);
  1311. dbstring_free(&(dbproc->dboptcmd));
  1312. for (i=0; i < MAXBINDTYPES; i++) {
  1313. if (dbproc->nullreps[i].bindval != default_null_representations[i].bindval)
  1314. free((BYTE*)dbproc->nullreps[i].bindval);
  1315. }
  1316. dbfreebuf(dbproc);
  1317. free(dbproc);
  1318. return;
  1319. }
  1320. /**
  1321. * \ingroup dblib_core
  1322. * \brief Close server connections and free all related structures.
  1323. *
  1324. * \sa dbclose(), dbinit(), dbopen().
  1325. * \todo breaks if ctlib/dblib used in same process.
  1326. */
  1327. void
  1328. dbexit()
  1329. {
  1330. TDSSOCKET *tds;
  1331. DBPROCESS *dbproc;
  1332. int i, list_size, count = 1;
  1333. tdsdump_log(TDS_DBG_FUNC, "dbexit(void)\n");
  1334. tds_mutex_lock(&dblib_mutex);
  1335. if (--g_dblib_ctx.ref_count != 0) {
  1336. tds_mutex_unlock(&dblib_mutex);
  1337. return;
  1338. }
  1339. list_size = g_dblib_ctx.connection_list_size;
  1340. for (i = 0; i < list_size; i++) {
  1341. tds = g_dblib_ctx.connection_list[i];
  1342. g_dblib_ctx.connection_list[i] = NULL;
  1343. if (tds) {
  1344. ++count;
  1345. dbproc = (DBPROCESS *) tds_get_parent(tds);
  1346. tds_close_socket(tds);
  1347. tds_free_socket(tds);
  1348. if (dbproc) {
  1349. /* avoid locking in dbclose */
  1350. dbproc->tds_socket = NULL;
  1351. dbclose(dbproc);
  1352. }
  1353. }
  1354. }
  1355. if (g_dblib_ctx.connection_list) {
  1356. TDS_ZERO_FREE(g_dblib_ctx.connection_list);
  1357. g_dblib_ctx.connection_list_size = 0;
  1358. }
  1359. tds_mutex_unlock(&dblib_mutex);
  1360. dblib_release_tds_ctx(count);
  1361. }
  1362. static const char *
  1363. prdbresults_state(int retcode)
  1364. {
  1365. static char unknown[24];
  1366. switch(retcode) {
  1367. case _DB_RES_INIT: return "_DB_RES_INIT";
  1368. case _DB_RES_RESULTSET_EMPTY: return "_DB_RES_RESULTSET_EMPTY";
  1369. case _DB_RES_RESULTSET_ROWS: return "_DB_RES_RESULTSET_ROWS";
  1370. case _DB_RES_NEXT_RESULT: return "_DB_RES_NEXT_RESULT";
  1371. case _DB_RES_NO_MORE_RESULTS: return "_DB_RES_NO_MORE_RESULTS";
  1372. case _DB_RES_SUCCEED: return "_DB_RES_SUCCEED";
  1373. default:
  1374. sprintf(unknown, "oops: %u ??", retcode);
  1375. }
  1376. return unknown;
  1377. }
  1378. static const char *
  1379. prdbretcode(RETCODE retcode)
  1380. {
  1381. static char unknown[24];
  1382. switch(retcode) {
  1383. case REG_ROW: return "REG_ROW/MORE_ROWS";
  1384. case NO_MORE_ROWS: return "NO_MORE_ROWS";
  1385. case BUF_FULL: return "BUF_FULL";
  1386. case NO_MORE_RESULTS: return "NO_MORE_RESULTS";
  1387. case SUCCEED: return "SUCCEED";
  1388. case FAIL: return "FAIL";
  1389. default:
  1390. sprintf(unknown, "oops: %u ??", retcode);
  1391. }
  1392. return unknown;
  1393. }
  1394. static const char *
  1395. prretcode(int retcode)
  1396. {
  1397. static char unknown[24];
  1398. switch(retcode) {
  1399. case TDS_SUCCESS: return "TDS_SUCCESS";
  1400. case TDS_FAIL: return "TDS_FAIL";
  1401. case TDS_NO_MORE_RESULTS: return "TDS_NO_MORE_RESULTS";
  1402. case TDS_CANCELLED: return "TDS_CANCELLED";
  1403. default:
  1404. sprintf(unknown, "oops: %u ??", retcode);
  1405. }
  1406. return unknown;
  1407. }
  1408. static const char *
  1409. prresult_type(int result_type)
  1410. {
  1411. static char unknown[24];
  1412. switch(result_type) {
  1413. case TDS_ROW_RESULT: return "TDS_ROW_RESULT";
  1414. case TDS_PARAM_RESULT: return "TDS_PARAM_RESULT";
  1415. case TDS_STATUS_RESULT: return "TDS_STATUS_RESULT";
  1416. case TDS_MSG_RESULT: return "TDS_MSG_RESULT";
  1417. case TDS_COMPUTE_RESULT: return "TDS_COMPUTE_RESULT";
  1418. case TDS_CMD_DONE: return "TDS_CMD_DONE";
  1419. case TDS_CMD_SUCCEED: return "TDS_CMD_SUCCEED";
  1420. case TDS_CMD_FAIL: return "TDS_CMD_FAIL";
  1421. case TDS_ROWFMT_RESULT: return "TDS_ROWFMT_RESULT";
  1422. case TDS_COMPUTEFMT_RESULT: return "TDS_COMPUTEFMT_RESULT";
  1423. case TDS_DESCRIBE_RESULT: return "TDS_DESCRIBE_RESULT";
  1424. case TDS_DONE_RESULT: return "TDS_DONE_RESULT";
  1425. case TDS_DONEPROC_RESULT: return "TDS_DONEPROC_RESULT";
  1426. case TDS_DONEINPROC_RESULT: return "TDS_DONEINPROC_RESULT";
  1427. case TDS_OTHERS_RESULT: return "TDS_OTHERS_RESULT";
  1428. default:
  1429. sprintf(unknown, "oops: %u ??", result_type);
  1430. }
  1431. return unknown;
  1432. }
  1433. /**
  1434. * \ingroup dblib_core
  1435. * \brief Set up query results.
  1436. *
  1437. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1438. * \retval SUCCEED Some results are available.
  1439. * \retval FAIL query was not processed successfully by the server
  1440. * \retval NO_MORE_RESULTS query produced no results.
  1441. *
  1442. * \remarks Call dbresults() after calling dbsqlexec() or dbsqlok(), or dbrpcsend() returns SUCCEED. Unless
  1443. * one of them fails, dbresults will return either SUCCEED or NO_MORE_RESULTS.
  1444. *
  1445. * The meaning of \em results is very specific and not very intuitive. Results are created by either
  1446. * - a SELECT statement
  1447. * - a stored procedure
  1448. *
  1449. * When dbresults returns SUCCEED, therefore, it indicates the server processed the query successfully and
  1450. * that one or more of these is present:
  1451. * - metadata -- dbnumcols() returns 1 or more
  1452. * - data -- dbnextrow() returns SUCCEED
  1453. * - return status -- dbhasretstat() returns TRUE
  1454. * - output parameters -- dbnumrets() returns 1 or more
  1455. *
  1456. * If none of the above are present, dbresults() returns NO_MORE_RESULTS.
  1457. *
  1458. * SUCCEED does not imply that DBROWS() will return TRUE or even that dbnumcols() will return nonzero.
  1459. * A general algorithm for reading results will call dbresults() until it return NO_MORE_RESULTS (or FAIL).
  1460. * An application should check for all the above kinds of results within the dbresults() loop.
  1461. *
  1462. * \sa dbsqlexec(), dbsqlok(), dbrpcsend(), dbcancel(), DBROWS(), dbnextrow(), dbnumcols(), dbhasretstat(), dbretstatus(), dbnumrets()
  1463. */
  1464. RETCODE
  1465. dbresults(DBPROCESS * dbproc)
  1466. {
  1467. RETCODE erc = _dbresults(dbproc);
  1468. tdsdump_log(TDS_DBG_FUNC, "dbresults returning %d (%s)\n", erc, prdbretcode(erc));
  1469. return erc;
  1470. }
  1471. static RETCODE
  1472. _dbresults(DBPROCESS * dbproc)
  1473. {
  1474. TDSSOCKET *tds;
  1475. int result_type = 0, done_flags;
  1476. tdsdump_log(TDS_DBG_FUNC, "dbresults(%p)\n", dbproc);
  1477. CHECK_CONN(FAIL);
  1478. tds = dbproc->tds_socket;
  1479. tdsdump_log(TDS_DBG_FUNC, "dbresults: dbresults_state is %d (%s)\n",
  1480. dbproc->dbresults_state, prdbresults_state(dbproc->dbresults_state));
  1481. switch ( dbproc->dbresults_state ) {
  1482. case _DB_RES_SUCCEED:
  1483. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1484. return SUCCEED;
  1485. break;
  1486. case _DB_RES_RESULTSET_ROWS:
  1487. dbperror(dbproc, SYBERPND, 0); /* dbresults called while rows outstanding.... */
  1488. return FAIL;
  1489. break;
  1490. case _DB_RES_NO_MORE_RESULTS:
  1491. return NO_MORE_RESULTS;
  1492. break;
  1493. default:
  1494. break;
  1495. }
  1496. for (;;) {
  1497. TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS);
  1498. tdsdump_log(TDS_DBG_FUNC, "dbresults() tds_process_tokens returned %d (%s),\n\t\t\tresult_type %s\n",
  1499. retcode, prretcode(retcode), prresult_type(result_type));
  1500. switch (retcode) {
  1501. case TDS_SUCCESS:
  1502. switch (result_type) {
  1503. case TDS_ROWFMT_RESULT:
  1504. buffer_free(&dbproc->row_buf);
  1505. buffer_alloc(dbproc);
  1506. dbproc->dbresults_state = _DB_RES_RESULTSET_EMPTY;
  1507. break;
  1508. case TDS_COMPUTEFMT_RESULT:
  1509. break;
  1510. case TDS_ROW_RESULT:
  1511. case TDS_COMPUTE_RESULT:
  1512. dbproc->dbresults_state = _DB_RES_RESULTSET_ROWS;
  1513. return SUCCEED;
  1514. break;
  1515. case TDS_DONE_RESULT:
  1516. case TDS_DONEPROC_RESULT:
  1517. tdsdump_log(TDS_DBG_FUNC, "dbresults(): dbresults_state is %d (%s)\n",
  1518. dbproc->dbresults_state, prdbresults_state(dbproc->dbresults_state));
  1519. /* A done token signifies the end of a logical command.
  1520. * There are three possibilities:
  1521. * 1. Simple command with no result set, i.e. update, delete, insert
  1522. * 2. Command with result set but no rows
  1523. * 3. Command with result set and rows
  1524. */
  1525. switch (dbproc->dbresults_state) {
  1526. case _DB_RES_INIT:
  1527. case _DB_RES_NEXT_RESULT:
  1528. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1529. if (done_flags & TDS_DONE_ERROR)
  1530. return FAIL;
  1531. break;
  1532. case _DB_RES_RESULTSET_EMPTY:
  1533. case _DB_RES_RESULTSET_ROWS:
  1534. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1535. return SUCCEED;
  1536. break;
  1537. default:
  1538. assert(0);
  1539. break;
  1540. }
  1541. break;
  1542. case TDS_DONEINPROC_RESULT:
  1543. /*
  1544. * Return SUCCEED on a command within a stored procedure
  1545. * only if the command returned a result set.
  1546. */
  1547. switch (dbproc->dbresults_state) {
  1548. case _DB_RES_INIT:
  1549. case _DB_RES_NEXT_RESULT:
  1550. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1551. break;
  1552. case _DB_RES_RESULTSET_EMPTY :
  1553. case _DB_RES_RESULTSET_ROWS :
  1554. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1555. return SUCCEED;
  1556. break;
  1557. case _DB_RES_NO_MORE_RESULTS:
  1558. case _DB_RES_SUCCEED:
  1559. break;
  1560. }
  1561. break;
  1562. case TDS_STATUS_RESULT:
  1563. case TDS_MSG_RESULT:
  1564. case TDS_DESCRIBE_RESULT:
  1565. case TDS_PARAM_RESULT:
  1566. default:
  1567. break;
  1568. }
  1569. break;
  1570. case TDS_NO_MORE_RESULTS:
  1571. dbproc->dbresults_state = _DB_RES_NO_MORE_RESULTS;
  1572. return NO_MORE_RESULTS;
  1573. break;
  1574. default:
  1575. assert(TDS_FAILED(retcode));
  1576. dbproc->dbresults_state = _DB_RES_INIT;
  1577. return FAIL;
  1578. break;
  1579. }
  1580. }
  1581. }
  1582. /**
  1583. * \ingroup dblib_core
  1584. * \brief Return number of regular columns in a result set.
  1585. *
  1586. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1587. * \sa dbcollen(), dbcolname(), dbnumalts().
  1588. */
  1589. int
  1590. dbnumcols(DBPROCESS * dbproc)
  1591. {
  1592. tdsdump_log(TDS_DBG_FUNC, "dbnumcols(%p)\n", dbproc);
  1593. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  1594. if (dbproc && dbproc->tds_socket && dbproc->tds_socket->res_info)
  1595. return dbproc->tds_socket->res_info->num_cols;
  1596. return 0;
  1597. }
  1598. /**
  1599. * \ingroup dblib_core
  1600. * \brief Return name of a regular result column.
  1601. *
  1602. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1603. * \param column Nth in the result set, starting with 1.
  1604. * \return pointer to ASCII null-terminated string, the name of the column.
  1605. * \retval NULL \a column is not in range.
  1606. * \sa dbcollen(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols().
  1607. * \bug Relies on ASCII column names, post iconv conversion.
  1608. * Will not work as described for UTF-8 or UCS-2 clients.
  1609. * But maybe it shouldn't.
  1610. */
  1611. char *
  1612. dbcolname(DBPROCESS * dbproc, int column)
  1613. {
  1614. TDSCOLUMN *colinfo;
  1615. tdsdump_log(TDS_DBG_FUNC, "dbcolname(%p, %d)\n", dbproc, column);
  1616. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  1617. colinfo = dbcolptr(dbproc, column);
  1618. if (!colinfo)
  1619. return NULL;
  1620. return tds_dstr_buf(&colinfo->column_name);
  1621. }
  1622. /**
  1623. * \ingroup dblib_core
  1624. * \brief Read a row from the row buffer.
  1625. *
  1626. * When row buffering is enabled (DBBUFFER option is on), the client can use dbgetrow() to re-read a row previously fetched
  1627. * with dbnextrow(). The effect is to move the row pointer -- analogous to fseek() -- back to \a row.
  1628. * Calls to dbnextrow() read from \a row + 1 until the buffer is exhausted, at which point it resumes
  1629. * its normal behavior, except that as each row is fetched from the server, it is added to the row
  1630. * buffer (in addition to being returned to the client). When the buffer is filled, dbnextrow() returns
  1631. * \c FAIL until the buffer is at least partially emptied with dbclrbuf().
  1632. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1633. * \param row Nth row to read, starting with 1.
  1634. * \retval REG_ROW returned row is a regular row.
  1635. * \returns computeid when returned row is a compute row.
  1636. * \retval NO_MORE_ROWS no such row in the row buffer. Current row is unchanged.
  1637. * \retval FAIL unsuccessful; row buffer may be full.
  1638. * \sa dbaltbind(), dbbind(), dbclrbuf(), DBCURROW(), DBFIRSTROW(), DBLASTROW(), dbnextrow(), dbsetrow().
  1639. */
  1640. RETCODE
  1641. dbgetrow(DBPROCESS * dbproc, DBINT row)
  1642. {
  1643. RETCODE result = FAIL;
  1644. const int idx = buffer_row2idx(&dbproc->row_buf, row);
  1645. tdsdump_log(TDS_DBG_FUNC, "dbgetrow(%p, %d)\n", dbproc, row);
  1646. CHECK_CONN(FAIL);
  1647. if (-1 == idx)
  1648. return NO_MORE_ROWS;
  1649. dbproc->row_buf.current = idx;
  1650. buffer_transfer_bound_data(&dbproc->row_buf, TDS_ROW_RESULT, 0, dbproc, idx);
  1651. result = REG_ROW;
  1652. return result;
  1653. }
  1654. /**
  1655. * \ingroup dblib_core
  1656. * \brief Define substitution values to be used when binding null values.
  1657. *
  1658. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1659. * \param bindtype type of binding to which the substitute value will apply.
  1660. * \param bindlen size of the substitute value you are supplying, in bytes.
  1661. * Ignored except for CHARBIND and BINARYBIND.
  1662. * \param bindval pointer to a buffer containing the substitute value.
  1663. * \retval SUCCEED query was processed without errors.
  1664. * \retval FAIL query was not processed
  1665. * \sa dbaltbind(), dbbind(), dbconvert(), dbnullbind().
  1666. */
  1667. RETCODE
  1668. dbsetnull(DBPROCESS * dbproc, int bindtype, int bindlen, BYTE *bindval)
  1669. {
  1670. BYTE *pval;
  1671. tdsdump_log(TDS_DBG_FUNC, "dbsetnull(%p, %d, %d, %p)\n", dbproc, bindtype, bindlen, bindval);
  1672. CHECK_CONN(FAIL);
  1673. CHECK_PARAMETER(bindval, SYBENBVP, FAIL);
  1674. switch (bindtype) {
  1675. case DATETIMEBIND:
  1676. case DECIMALBIND:
  1677. case SRCDECIMALBIND:
  1678. case FLT8BIND:
  1679. case INTBIND:
  1680. case MONEYBIND:
  1681. case NUMERICBIND:
  1682. case SRCNUMERICBIND:
  1683. case REALBIND:
  1684. case SMALLBIND:
  1685. case SMALLDATETIMEBIND:
  1686. case SMALLMONEYBIND:
  1687. case TINYBIND:
  1688. case BIGINTBIND:
  1689. bindlen = (int)default_null_representations[bindtype].len;
  1690. break;
  1691. case CHARBIND:
  1692. case BINARYBIND:
  1693. CHECK_PARAMETER(bindlen >= 0, SYBEBBL, FAIL);
  1694. break;
  1695. case NTBSTRINGBIND: bindlen = (int)strlen((char *) bindval);
  1696. break;
  1697. case STRINGBIND: bindlen = (int)strlen((char *) bindval);
  1698. break;
  1699. case VARYBINBIND: bindlen = ((DBVARYBIN*) bindval)->len;
  1700. break;
  1701. case VARYCHARBIND: bindlen = ((DBVARYCHAR*) bindval)->len;
  1702. break;
  1703. #if 0
  1704. case SENSITIVITYBIND:
  1705. case BOUNDARYBIND:
  1706. #endif
  1707. default:
  1708. dbperror(dbproc, SYBEBTYP, 0);
  1709. return FAIL;
  1710. }
  1711. if ((pval = (BYTE*) malloc(bindlen)) == NULL) {
  1712. dbperror(dbproc, SYBEMEM, errno);
  1713. return FAIL;
  1714. }
  1715. /* free any prior allocation */
  1716. if (dbproc->nullreps[bindtype].bindval != default_null_representations[bindtype].bindval)
  1717. free((BYTE*)dbproc->nullreps[bindtype].bindval);
  1718. memcpy(pval, bindval, bindlen);
  1719. dbproc->nullreps[bindtype].bindval = pval;
  1720. dbproc->nullreps[bindtype].len = bindlen;
  1721. tdsdump_dump_buf(TDS_DBG_NETWORK, "null representation set ", pval, bindlen);
  1722. return SUCCEED;
  1723. }
  1724. /**
  1725. * \ingroup dblib_core
  1726. * \brief Make a buffered row "current" without fetching it into bound variables.
  1727. *
  1728. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1729. * \retval MORE_ROWS row found
  1730. * \retval NO_MORE_ROWS row not found
  1731. * \retval FAIL \a dbproc is dead or not enabled
  1732. * \sa dbaltbind(), dbbind(), dbcanquery(), dbclrbuf(), dbgetrow(), dbnextrow(), dbprrow().
  1733. */
  1734. STATUS
  1735. dbsetrow(DBPROCESS * dbproc, DBINT row)
  1736. {
  1737. const int idx = buffer_row2idx(&dbproc->row_buf, row);
  1738. tdsdump_log(TDS_DBG_FUNC, "dbsetrow(%p, %d)\n", dbproc, row);
  1739. CHECK_CONN(FAIL);
  1740. if (-1 == idx)
  1741. return NO_MORE_ROWS;
  1742. dbproc->row_buf.current = idx;
  1743. /* FIXME: should determine REG_ROW or compute_id; */
  1744. return REG_ROW;
  1745. }
  1746. /**
  1747. * \ingroup dblib_core
  1748. * \brief Read result row into the row buffer and into any bound host variables.
  1749. *
  1750. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1751. * \retval REG_ROW regular row has been read.
  1752. * \returns computeid when a compute row is read.
  1753. * \retval BUF_FULL reading next row would cause the buffer to be exceeded (and buffering is turned on).
  1754. * No row was read from the server
  1755. * \sa dbaltbind(), dbbind(), dbcanquery(), dbclrbuf(), dbgetrow(), dbprrow(), dbsetrow().
  1756. */
  1757. struct pivot_t;
  1758. STATUS
  1759. dbnextrow(DBPROCESS * dbproc)
  1760. {
  1761. TDSRESULTINFO *resinfo;
  1762. TDSSOCKET *tds;
  1763. STATUS result = FAIL;
  1764. TDS_INT res_type;
  1765. TDS_INT computeid;
  1766. int idx; /* row buffer index. Unless DBUFFER is on, idx will always be 0. */
  1767. struct pivot_t *pivot;
  1768. tdsdump_log(TDS_DBG_FUNC, "dbnextrow(%p)\n", dbproc);
  1769. CHECK_CONN(FAIL);
  1770. tds = dbproc->tds_socket;
  1771. if (IS_TDSDEAD(tds)) {
  1772. dbperror(dbproc, SYBEDDNE, 0);
  1773. return FAIL;
  1774. }
  1775. resinfo = tds->res_info;
  1776. tdsdump_log(TDS_DBG_FUNC, "dbnextrow() dbresults_state = %d (%s)\n",
  1777. dbproc->dbresults_state, prdbresults_state(dbproc->dbresults_state));
  1778. if (!resinfo || dbproc->dbresults_state != _DB_RES_RESULTSET_ROWS) {
  1779. /* no result set or result set empty (no rows) */
  1780. tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %d (NO_MORE_ROWS)\n", NO_MORE_ROWS);
  1781. return dbproc->row_type = NO_MORE_ROWS;
  1782. }
  1783. /*
  1784. * Try to get the dbproc->row_buf.current item from the buffered rows, if any.
  1785. * Else read from the stream, unless the buffer is exhausted.
  1786. * If no rows are read, DBROWTYPE() will report NO_MORE_ROWS.
  1787. */
  1788. dbproc->row_type = NO_MORE_ROWS;
  1789. computeid = REG_ROW;
  1790. if (-1 != (idx = buffer_current_index(dbproc))) {
  1791. /*
  1792. * Cool, the item we want is already there
  1793. */
  1794. result = dbproc->row_type = REG_ROW;
  1795. res_type = TDS_ROW_RESULT;
  1796. } else if (buffer_is_full(&dbproc->row_buf)) {
  1797. result = BUF_FULL;
  1798. res_type = TDS_ROWFMT_RESULT;
  1799. } else if ((pivot = dbrows_pivoted(dbproc)) != NULL) {
  1800. tdsdump_log(TDS_DBG_FUNC, "returning pivoted row\n");
  1801. return dbnextrow_pivoted(dbproc, pivot);
  1802. } else {
  1803. const int mask = TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE;
  1804. buffer_save_row(dbproc);
  1805. /* Get the row from the TDS stream. */
  1806. switch (tds_process_tokens(tds, &res_type, NULL, mask)) {
  1807. case TDS_SUCCESS:
  1808. if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) {
  1809. if (res_type == TDS_COMPUTE_RESULT)
  1810. computeid = tds->current_results->computeid;
  1811. /* Add the row to the row buffer, whose capacity is always at least 1 */
  1812. resinfo = tds->current_results;
  1813. idx = buffer_add_row(dbproc, resinfo);
  1814. assert(idx != -1);
  1815. result = dbproc->row_type = (res_type == TDS_ROW_RESULT)? REG_ROW : computeid;
  1816. #if 0 /* TODO */
  1817. tds_process_tokens(tds, &res_type, NULL, TDS_TOKEN_TRAILING);
  1818. #endif
  1819. break;
  1820. }
  1821. case TDS_NO_MORE_RESULTS:
  1822. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  1823. result = NO_MORE_ROWS;
  1824. break;
  1825. default:
  1826. tdsdump_log(TDS_DBG_FUNC, "unexpected: leaving dbnextrow() returning FAIL\n");
  1827. return FAIL;
  1828. break;
  1829. }
  1830. }
  1831. if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) {
  1832. /*
  1833. * Transfer the data from the row buffer to the bound variables.
  1834. */
  1835. buffer_transfer_bound_data(&dbproc->row_buf, res_type, computeid, dbproc, idx);
  1836. }
  1837. if (res_type == TDS_COMPUTE_RESULT) {
  1838. tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning compute_id %d\n", result);
  1839. } else {
  1840. tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %s\n", prdbretcode(result));
  1841. }
  1842. return result;
  1843. } /* dbnextrow() */
  1844. static int
  1845. dblib_bound_type(int bindtype)
  1846. {
  1847. switch (bindtype) {
  1848. case CHARBIND:
  1849. case STRINGBIND:
  1850. case NTBSTRINGBIND:
  1851. return SYBCHAR;
  1852. break;
  1853. case FLT8BIND:
  1854. return SYBFLT8;
  1855. break;
  1856. case REALBIND:
  1857. return SYBREAL;
  1858. break;
  1859. case INTBIND:
  1860. return SYBINT4;
  1861. break;
  1862. case SMALLBIND:
  1863. return SYBINT2;
  1864. break;
  1865. case TINYBIND:
  1866. return SYBINT1;
  1867. break;
  1868. case BIGINTBIND:
  1869. return SYBINT8;
  1870. break;
  1871. case DATETIMEBIND:
  1872. return SYBDATETIME;
  1873. break;
  1874. case SMALLDATETIMEBIND:
  1875. return SYBDATETIME4;
  1876. break;
  1877. case MONEYBIND:
  1878. return SYBMONEY;
  1879. break;
  1880. case SMALLMONEYBIND:
  1881. return SYBMONEY4;
  1882. break;
  1883. case BINARYBIND:
  1884. return SYBBINARY;
  1885. break;
  1886. case VARYBINBIND:
  1887. return SYBVARBINARY;
  1888. break;
  1889. case VARYCHARBIND:
  1890. return SYBVARCHAR;
  1891. break;
  1892. case BITBIND:
  1893. return SYBBIT;
  1894. break;
  1895. case NUMERICBIND:
  1896. case SRCNUMERICBIND:
  1897. case DECIMALBIND:
  1898. case SRCDECIMALBIND:
  1899. return SYBNUMERIC;
  1900. break;
  1901. case DATETIME2BIND:
  1902. return SYBMSDATETIMEOFFSET;
  1903. break;
  1904. default:
  1905. return -1;
  1906. break;
  1907. }
  1908. }
  1909. /**
  1910. * \ingroup dblib_core
  1911. * \brief Convert one datatype to another.
  1912. *
  1913. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  1914. * \param srctype datatype of the data to convert.
  1915. * \param src buffer to convert
  1916. * \param srclen length of \a src
  1917. * \param desttype target datatype
  1918. * \param dest output buffer
  1919. * \param destlen size of \a dest
  1920. * \returns On success, the count of output bytes in \a dest, else -1. On failure, it will call any user-supplied error handler.
  1921. * \remarks Causes of failure:
  1922. * - No such conversion unavailable.
  1923. * - Character data output was truncated, or numerical data overflowed or lost precision.
  1924. * - In converting character data to one of the numeric types, the string could not be interpreted as a number.
  1925. *
  1926. * Conversion functions are handled in the TDS layer.
  1927. *
  1928. * The main reason for this is that \c ct-lib and \c ODBC (and presumably \c DBI) need
  1929. * to be able to do conversions between datatypes. This is possible because
  1930. * the format of complex data (dates, money, numeric, decimal) is defined by
  1931. * its representation on the wire; thus what we call \c DBMONEY is exactly its
  1932. * format on the wire. CLIs that need a different representation (ODBC?)
  1933. * need to convert from this format anyway, so the code would already be in
  1934. * place.
  1935. *
  1936. * Each datatype is also defined by its Server-type so all CLIs should be
  1937. * able to map native types to server types as well.
  1938. *
  1939. * tds_convert() copies from src to dest and returns the output data length,
  1940. * period. All padding and termination is the responsibility of the API library
  1941. * and is done post-conversion. The peculiar rule in dbconvert() is that
  1942. * a \a destlen of -1 and a \a desttype of \c SYBCHAR means the output buffer
  1943. * should be null-terminated.
  1944. *
  1945. * \sa dbaltbind(), dbaltbind_ps(), dbbind(), dbbind_ps(), dbconvert_ps(), dberrhandle(), dbsetnull(), dbsetversion(), dbwillconvert().
  1946. * \todo What happens if client does not reset values?
  1947. * \todo Microsoft and Sybase define this function differently.
  1948. */
  1949. DBINT
  1950. dbconvert(DBPROCESS * dbproc, int srctype, const BYTE * src, DBINT srclen, int desttype, BYTE * dest, DBINT destlen)
  1951. {
  1952. CONV_RESULT dres;
  1953. DBINT ret;
  1954. int i;
  1955. int len;
  1956. DBNUMERIC *num;
  1957. tdsdump_log(TDS_DBG_FUNC, "dbconvert(%p, %s, %p, %d, %s, %p, %d)\n",
  1958. dbproc, tds_prdatatype(srctype), src, srclen, tds_prdatatype(desttype), dest, destlen);
  1959. /* dbproc and src can be NULLs */
  1960. CHECK_PARAMETER(dest, SYBEACNV, -1);
  1961. if (0 == destlen)
  1962. return 0;
  1963. if (src == NULL || srclen == 0) {
  1964. int bind = dbbindtype(desttype);
  1965. int size = tds_get_size_by_type(desttype);
  1966. if (SYBCHAR == desttype) {
  1967. if (destlen > 0) {
  1968. size = destlen;
  1969. bind = CHARBIND;
  1970. } else {
  1971. size = 1;
  1972. bind = NTBSTRINGBIND;
  1973. }
  1974. }
  1975. dbgetnull(dbproc, bind, size, dest);
  1976. return size;
  1977. }
  1978. /* srclen of -1 means the source data is definitely NULL terminated */
  1979. if (srclen == -1)
  1980. srclen = (int)strlen((const char *) src);
  1981. /* FIXME what happen if client do not reset values ??? */
  1982. /* FIXME act differently for ms and sybase */
  1983. if (is_numeric_type(desttype)) {
  1984. num = (DBNUMERIC *) dest; /* num->scale is unsigned */
  1985. if (num->precision <= 0 || num->precision > MAXPRECISION || num->scale > num->precision) {
  1986. dres.n.precision = 18;
  1987. dres.n.scale = 0;
  1988. } else {
  1989. dres.n.precision = num->precision;
  1990. dres.n.scale = num->scale;
  1991. }
  1992. /* oft times we are asked to convert a data type to itself */
  1993. } else if (srctype == desttype) {
  1994. ret = -2; /* to make sure we always set it */
  1995. tdsdump_log(TDS_DBG_INFO1, "dbconvert() srctype == desttype\n");
  1996. switch (desttype) {
  1997. case SYBBINARY:
  1998. case SYBVARBINARY:
  1999. case SYBIMAGE:
  2000. if (srclen > destlen && destlen >= 0) {
  2001. dbperror(dbproc, SYBECOFL, 0);
  2002. ret = -1;
  2003. } else {
  2004. memcpy(dest, src, srclen);
  2005. if (srclen < destlen)
  2006. memset(dest + srclen, 0, destlen - srclen);
  2007. ret = srclen;
  2008. }
  2009. break;
  2010. case SYBCHAR:
  2011. case SYBVARCHAR:
  2012. case SYBTEXT:
  2013. /* srclen of -1 means the source data is definitely NULL terminated */
  2014. if (srclen == -1)
  2015. srclen = (int)strlen((const char *) src);
  2016. switch (destlen) {
  2017. case 0: /* nothing to copy */
  2018. ret = 0;
  2019. break;
  2020. case -1: /* rtrim and null terminate */
  2021. while (srclen && src[srclen - 1] == ' ') {
  2022. --srclen;
  2023. }
  2024. /* fall thru */
  2025. case -2: /* just null terminate */
  2026. memcpy(dest, src, srclen);
  2027. dest[srclen] = '\0';
  2028. ret = srclen;
  2029. break;
  2030. default:
  2031. assert(destlen > 0);
  2032. if (destlen < 0 || srclen > destlen) {
  2033. dbperror(dbproc, SYBECOFL, 0);
  2034. ret = -1;
  2035. } else {
  2036. memcpy(dest, src, srclen);
  2037. for (i = srclen; i < destlen; i++)
  2038. dest[i] = ' ';
  2039. ret = srclen;
  2040. }
  2041. break;
  2042. }
  2043. break;
  2044. case SYBINT1:
  2045. case SYBINT2:
  2046. case SYBINT4:
  2047. case SYBINT8:
  2048. case SYBFLT8:
  2049. case SYBREAL:
  2050. case SYBBIT:
  2051. case SYBBITN:
  2052. case SYBMONEY:
  2053. case SYBMONEY4:
  2054. case SYBDATETIME:
  2055. case SYBDATETIME4:
  2056. case SYBUNIQUE:
  2057. ret = tds_get_size_by_type(desttype);
  2058. memcpy(dest, src, ret);
  2059. break;
  2060. case SYBMSDATE:
  2061. case SYBMSTIME:
  2062. case SYBMSDATETIME2:
  2063. case SYBMSDATETIMEOFFSET:
  2064. ret = sizeof(TDS_DATETIMEALL);
  2065. memcpy(dest, src, ret);
  2066. break;
  2067. default:
  2068. ret = -1;
  2069. break;
  2070. }
  2071. assert(ret > -2);
  2072. return ret;
  2073. }
  2074. /* end srctype == desttype */
  2075. /*
  2076. * Character types need no conversion. Just move the data.
  2077. */
  2078. if (is_similar_type(srctype, desttype)) {
  2079. if (src && dest && srclen > 0 && destlen >= srclen) {
  2080. memcpy(dest, src, srclen);
  2081. return srclen;
  2082. }
  2083. }
  2084. tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
  2085. len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *) src, srclen, desttype, &dres);
  2086. tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", len);
  2087. switch (len) {
  2088. case TDS_CONVERT_NOAVAIL:
  2089. dbperror(dbproc, SYBERDCN, 0);
  2090. return -1;
  2091. break;
  2092. case TDS_CONVERT_SYNTAX:
  2093. dbperror(dbproc, SYBECSYN, 0);
  2094. return -1;
  2095. break;
  2096. case TDS_CONVERT_NOMEM:
  2097. dbperror(dbproc, SYBEMEM, ENOMEM);
  2098. return -1;
  2099. break;
  2100. case TDS_CONVERT_OVERFLOW:
  2101. dbperror(dbproc, SYBECOFL, 0);
  2102. return -1;
  2103. break;
  2104. case TDS_CONVERT_FAIL:
  2105. dbperror(dbproc, SYBECINTERNAL, 0);
  2106. return -1;
  2107. break;
  2108. default:
  2109. if (len < 0) { /* logic error: should be captured above */
  2110. dbperror(dbproc, SYBECINTERNAL, 0);
  2111. return -1;
  2112. }
  2113. break;
  2114. }
  2115. switch (desttype) {
  2116. case SYBBINARY:
  2117. case SYBVARBINARY:
  2118. case SYBIMAGE:
  2119. if (len > destlen && destlen >= 0) {
  2120. dbperror(dbproc, SYBECOFL, 0);
  2121. ret = -1;
  2122. } else {
  2123. memcpy(dest, dres.ib, len);
  2124. free(dres.ib);
  2125. if (len < destlen)
  2126. memset(dest + len, 0, destlen - len);
  2127. ret = len;
  2128. }
  2129. break;
  2130. case SYBINT1:
  2131. memcpy(dest, &(dres.ti), 1);
  2132. ret = 1;
  2133. break;
  2134. case SYBINT2:
  2135. memcpy(dest, &(dres.si), 2);
  2136. ret = 2;
  2137. break;
  2138. case SYBINT4:
  2139. memcpy(dest, &(dres.i), 4);
  2140. ret = 4;
  2141. break;
  2142. case SYBINT8:
  2143. memcpy(dest, &(dres.bi), 8);
  2144. ret = 8;
  2145. break;
  2146. case SYBFLT8:
  2147. memcpy(dest, &(dres.f), 8);
  2148. ret = 8;
  2149. break;
  2150. case SYBREAL:
  2151. memcpy(dest, &(dres.r), 4);
  2152. ret = 4;
  2153. break;
  2154. case SYBBIT:
  2155. case SYBBITN:
  2156. memcpy(dest, &(dres.ti), 1);
  2157. ret = 1;
  2158. break;
  2159. case SYBMONEY:
  2160. memcpy(dest, &(dres.m), sizeof(TDS_MONEY));
  2161. ret = sizeof(TDS_MONEY);
  2162. break;
  2163. case SYBMONEY4:
  2164. memcpy(dest, &(dres.m4), sizeof(TDS_MONEY4));
  2165. ret = sizeof(TDS_MONEY4);
  2166. break;
  2167. case SYBDATETIME:
  2168. memcpy(dest, &(dres.dt), sizeof(TDS_DATETIME));
  2169. ret = sizeof(TDS_DATETIME);
  2170. break;
  2171. case SYBDATETIME4:
  2172. memcpy(dest, &(dres.dt4), sizeof(TDS_DATETIME4));
  2173. ret = sizeof(TDS_DATETIME4);
  2174. break;
  2175. case SYBNUMERIC:
  2176. case SYBDECIMAL:
  2177. memcpy(dest, &(dres.n), sizeof(TDS_NUMERIC));
  2178. ret = sizeof(TDS_NUMERIC);
  2179. break;
  2180. case SYBUNIQUE:
  2181. memcpy(dest, &(dres.u), sizeof(TDS_UNIQUE));
  2182. ret = sizeof(TDS_UNIQUE);
  2183. break;
  2184. case SYBMSDATE:
  2185. case SYBMSTIME:
  2186. case SYBMSDATETIME2:
  2187. case SYBMSDATETIMEOFFSET:
  2188. memcpy(dest, &(dres.dta), sizeof(TDS_DATETIMEALL));
  2189. ret = sizeof(TDS_DATETIMEALL);
  2190. break;
  2191. case SYBCHAR:
  2192. case SYBVARCHAR:
  2193. case SYBTEXT:
  2194. tdsdump_log(TDS_DBG_INFO1, "dbconvert() outputting %d bytes character data destlen = %d \n", len, destlen);
  2195. if (destlen < -2)
  2196. destlen = 0; /* failure condition */
  2197. switch (destlen) {
  2198. case 0:
  2199. ret = FAIL;
  2200. break;
  2201. case -1: /* rtrim and null terminate */
  2202. for (i = len - 1; i >= 0 && dres.c[i] == ' '; --i) {
  2203. len = i;
  2204. }
  2205. memcpy(dest, dres.c, len);
  2206. dest[len] = '\0';
  2207. ret = len;
  2208. break;
  2209. case -2: /* just null terminate */
  2210. memcpy(dest, dres.c, len);
  2211. dest[len] = 0;
  2212. ret = len;
  2213. break;
  2214. default:
  2215. assert(destlen > 0);
  2216. if (destlen < 0 || len > destlen) {
  2217. dbperror(dbproc, SYBECOFL, 0);
  2218. ret = -1;
  2219. tdsdump_log(TDS_DBG_INFO1, "%d bytes type %d -> %d, destlen %d < %d required\n",
  2220. srclen, srctype, desttype, destlen, len);
  2221. break;
  2222. }
  2223. /* else pad with blanks */
  2224. memcpy(dest, dres.c, len);
  2225. for (i = len; i < destlen; i++)
  2226. dest[i] = ' ';
  2227. ret = len;
  2228. break;
  2229. }
  2230. free(dres.c);
  2231. break;
  2232. default:
  2233. tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
  2234. ret = -1;
  2235. break;
  2236. }
  2237. return (ret);
  2238. }
  2239. /**
  2240. * \ingroup dblib_core
  2241. * \brief cf. dbconvert(), above
  2242. *
  2243. * \em Sybase: Convert numeric types.
  2244. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2245. * \param srctype datatype of the data to convert.
  2246. * \param src buffer to convert
  2247. * \param srclen length of \a src
  2248. * \param desttype target datatype
  2249. * \param dest output buffer
  2250. * \param destlen size of \a dest
  2251. * \param typeinfo address of a \c DBTYPEINFO structure that governs the precision & scale of the output, may be \c NULL.
  2252. * \sa dbaltbind(), dbaltbind_ps(), dbbind(), dbbind_ps(), dbconvert(), dberrhandle(), dbsetnull(), dbsetversion(), dbwillconvert().
  2253. */
  2254. DBINT
  2255. dbconvert_ps(DBPROCESS * dbproc,
  2256. int srctype, const BYTE * src, DBINT srclen, int desttype, BYTE * dest, DBINT destlen, DBTYPEINFO * typeinfo)
  2257. {
  2258. DBNUMERIC *s;
  2259. DBNUMERIC *d;
  2260. tdsdump_log(TDS_DBG_FUNC, "dbconvert_ps(%p)\n", dbproc);
  2261. /* dbproc can be NULL*/
  2262. if (is_numeric_type(desttype)) {
  2263. if (typeinfo == NULL) {
  2264. if (is_numeric_type(srctype)) {
  2265. s = (DBNUMERIC *) src;
  2266. d = (DBNUMERIC *) dest;
  2267. d->precision = s->precision;
  2268. d->scale = s->scale;
  2269. } else {
  2270. d = (DBNUMERIC *) dest;
  2271. d->precision = 18;
  2272. d->scale = 0;
  2273. }
  2274. } else {
  2275. d = (DBNUMERIC *) dest;
  2276. d->precision = typeinfo->precision;
  2277. d->scale = typeinfo->scale;
  2278. }
  2279. }
  2280. return dbconvert(dbproc, srctype, src, srclen, desttype, dest, destlen);
  2281. }
  2282. /**
  2283. * \ingroup dblib_core
  2284. * \brief Tie a host variable to a resultset column.
  2285. *
  2286. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2287. * \param column Nth column, starting at 1.
  2288. * \param vartype datatype of the host variable that will receive the data
  2289. * \param varlen size of host variable pointed to \a varaddr
  2290. * \param varaddr address of host variable
  2291. * \retval SUCCEED everything worked.
  2292. * \retval FAIL no such \a column or no such conversion possible, or target buffer too small.
  2293. * \sa
  2294. */
  2295. RETCODE
  2296. dbbind(DBPROCESS * dbproc, int column, int vartype, DBINT varlen, BYTE * varaddr)
  2297. {
  2298. TDSCOLUMN *colinfo = NULL;
  2299. TDSRESULTINFO* results;
  2300. int srctype = -1;
  2301. int desttype = -1;
  2302. tdsdump_log(TDS_DBG_FUNC, "dbbind(%p, %d, %d, %d, %p)\n", dbproc, column, vartype, varlen, varaddr);
  2303. CHECK_CONN(FAIL);
  2304. CHECK_PARAMETER(varaddr, SYBEABNV, FAIL);
  2305. results = dbproc->tds_socket->res_info;
  2306. if (results == NULL || results->num_cols < column || column < 1) {
  2307. dbperror(dbproc, SYBEABNC, 0);
  2308. return FAIL;
  2309. }
  2310. if (varlen < 0) {
  2311. switch (vartype) {
  2312. case CHARBIND:
  2313. case STRINGBIND:
  2314. case NTBSTRINGBIND:
  2315. case VARYCHARBIND:
  2316. case VARYBINBIND:
  2317. /*
  2318. * No message for this error. Documentation doesn't define varlen < 0, but
  2319. * experimentation with Sybase db-lib shows it's accepted as if zero.
  2320. */
  2321. tdsdump_log(TDS_DBG_FUNC, "dbbind: setting varlen (%d) to 0\n", varlen);
  2322. varlen = 0;
  2323. break;
  2324. }
  2325. }
  2326. if (0 == varlen) { /* "Note that if varlen is 0, no padding takes place." */
  2327. switch (vartype) {
  2328. case CHARBIND:
  2329. case STRINGBIND:
  2330. case NTBSTRINGBIND:
  2331. varlen = -1;
  2332. break;
  2333. default:
  2334. break; /* dbconvert: "The destlen is ignored for all fixed-length, non-NULL data types." */
  2335. }
  2336. }
  2337. dbproc->avail_flag = FALSE;
  2338. colinfo = dbproc->tds_socket->res_info->columns[column - 1];
  2339. srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  2340. if (-1 == (desttype = dblib_bound_type(vartype))) {
  2341. dbperror(dbproc, SYBEBTYP, 0);
  2342. return FAIL;
  2343. }
  2344. if (! dbwillconvert(srctype, desttype)) {
  2345. dbperror(dbproc, SYBEABMT, 0);
  2346. return FAIL;
  2347. }
  2348. colinfo->column_varaddr = (char *) varaddr;
  2349. colinfo->column_bindtype = vartype;
  2350. colinfo->column_bindlen = varlen;
  2351. return SUCCEED;
  2352. } /* dbbind() */
  2353. /**
  2354. * \ingroup dblib_core
  2355. * \brief set name and location of the \c interfaces file FreeTDS should use to look up a servername.
  2356. *
  2357. * Does not affect lookups or location of \c freetds.conf.
  2358. * \param filename name of \c interfaces
  2359. * \sa dbopen()
  2360. */
  2361. void
  2362. dbsetifile(char *filename)
  2363. {
  2364. tdsdump_log(TDS_DBG_FUNC, "dbsetifile(%s)\n", filename? filename : "0x00");
  2365. if (filename == NULL) {
  2366. dbperror(NULL, SYBENULP, 0);
  2367. return;
  2368. }
  2369. tds_set_interfaces_file_loc(filename);
  2370. }
  2371. /**
  2372. * \ingroup dblib_core
  2373. * \brief Tie a null-indicator to a regular result column.
  2374. *
  2375. *
  2376. * When a row is fetched, the indicator variable tells the state of the column's data.
  2377. *
  2378. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2379. * \param column Nth column in the result set, starting with 1.
  2380. * \param indicator address of host variable.
  2381. * \retval SUCCEED variable accepted.
  2382. * \retval FAIL \a indicator is NULL or \a column is out of range.
  2383. * \remarks Contents of \a indicator are set with \c dbnextrow(). Possible values are:
  2384. * - 0 \a column bound successfully
  2385. * - -1 \a column is NULL.
  2386. * - >0 true length of data, had \a column not been truncated due to insufficient space in the columns bound host variable .
  2387. * \sa dbanullbind(), dbbind(), dbdata(), dbdatlen(), dbnextrow().
  2388. */
  2389. RETCODE
  2390. dbnullbind(DBPROCESS * dbproc, int column, DBINT * indicator)
  2391. {
  2392. TDSCOLUMN *colinfo;
  2393. tdsdump_log(TDS_DBG_FUNC, "dbnullbind(%p, %d, %p)\n", dbproc, column, indicator);
  2394. colinfo = dbcolptr(dbproc, column);
  2395. if (!colinfo)
  2396. return FAIL; /* dbcolptr sent SYBECNOR, Column number out of range */
  2397. colinfo->column_nullbind = (TDS_SMALLINT *)indicator;
  2398. return SUCCEED;
  2399. }
  2400. /**
  2401. * \ingroup dblib_core
  2402. * \brief Tie a null-indicator to a compute result column.
  2403. *
  2404. *
  2405. * When a row is fetched, the indicator variable tells the state of the column's data.
  2406. *
  2407. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2408. * \param computeid identifies which one of potientially many compute rows is meant. The first compute
  2409. * clause has \a computeid == 1.
  2410. * \param column Nth column in the result set, starting with 1.
  2411. * \param indicator address of host variable.
  2412. * \retval SUCCEED variable accepted.
  2413. * \retval FAIL \a indicator is NULL or \a column is out of range.
  2414. * \remarks Contents of \a indicator are set with \c dbnextrow(). Possible values are:
  2415. * - 0 \a column bound successfully
  2416. * - -1 \a column is NULL.
  2417. * - >0 true length of data, had \a column not been truncated due to insufficient space in the columns bound host variable .
  2418. * \sa dbadata(), dbadlen(), dbaltbind(), dbnextrow(), dbnullbind().
  2419. * \todo Never fails, but only because failure conditions aren't checked.
  2420. */
  2421. RETCODE
  2422. dbanullbind(DBPROCESS * dbproc, int computeid, int column, DBINT * indicator)
  2423. {
  2424. TDSCOLUMN *curcol;
  2425. tdsdump_log(TDS_DBG_FUNC, "dbanullbind(%p, %d, %d, %p)\n", dbproc, computeid, column, indicator);
  2426. curcol = dbacolptr(dbproc, computeid, column, 1);
  2427. if (!curcol)
  2428. return FAIL;
  2429. /*
  2430. * XXX Need to check for possibly problems before assuming
  2431. * everything is okay
  2432. */
  2433. curcol->column_nullbind = (TDS_SMALLINT *)indicator;
  2434. return SUCCEED;
  2435. }
  2436. /**
  2437. * \ingroup dblib_core
  2438. * \brief Indicates whether or not the count returned by dbcount is real (Microsoft-compatibility feature).
  2439. *
  2440. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2441. * \returns TRUE if the count returned by dbcount is real or FALSE if the count returned by dbcount is not real.
  2442. * \sa DBCOUNT(), dbcount().
  2443. */
  2444. BOOL
  2445. dbiscount(DBPROCESS * dbproc)
  2446. {
  2447. tdsdump_log(TDS_DBG_FUNC, "dbiscount(%p)\n", dbproc);
  2448. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  2449. return dbproc->tds_socket && dbproc->tds_socket->rows_affected != TDS_NO_COUNT;
  2450. }
  2451. /**
  2452. * \ingroup dblib_core
  2453. * \brief Get count of rows processed
  2454. *
  2455. *
  2456. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2457. * \returns
  2458. * - for insert/update/delete, count of rows affected.
  2459. * - for select, count of rows returned, after all rows have been fetched.
  2460. * \sa DBCOUNT(), dbnextrow(), dbresults().
  2461. */
  2462. DBINT
  2463. dbcount(DBPROCESS * dbproc)
  2464. {
  2465. tdsdump_log(TDS_DBG_FUNC, "dbcount(%p)\n", dbproc);
  2466. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  2467. if (!dbproc || !dbproc->tds_socket || dbproc->tds_socket->rows_affected == TDS_NO_COUNT)
  2468. return -1;
  2469. return (DBINT)dbproc->tds_socket->rows_affected;
  2470. }
  2471. /**
  2472. * \ingroup dblib_core
  2473. * \brief Clear \a n rows from the row buffer.
  2474. *
  2475. *
  2476. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2477. * \param n number of rows to remove, >= 0.
  2478. * \sa dbgetrow(), dbnextrow(), dbsetopt().
  2479. */
  2480. void
  2481. dbclrbuf(DBPROCESS * dbproc, DBINT n)
  2482. {
  2483. tdsdump_log(TDS_DBG_FUNC, "dbclrbuf(%p, %d)\n", dbproc, n);
  2484. CHECK_PARAMETER(dbproc, SYBENULL, );
  2485. if (n <= 0)
  2486. return;
  2487. if (dbproc->dbopts[DBBUFFER].factive) {
  2488. DBPROC_ROWBUF * buf = &(dbproc->row_buf);
  2489. int count = buffer_count(buf);
  2490. if (n >= count)
  2491. n = count - 1;
  2492. buffer_delete_rows(&(dbproc->row_buf), n);
  2493. }
  2494. }
  2495. /**
  2496. * \ingroup dblib_core
  2497. * \brief Test whether or not a datatype can be converted to another datatype
  2498. *
  2499. * \param srctype type converting from
  2500. * \param desttype type converting to
  2501. * \remarks dbwillconvert() lies sometimes. Some datatypes \em should be convertible but aren't yet in our implementation.
  2502. * Legal unimplemented conversions return \em TRUE.
  2503. * \retval TRUE convertible, or should be.
  2504. * \retval FAIL not convertible.
  2505. * \sa dbaltbind(), dbbind(), dbconvert(), dbconvert_ps(), \c src/dblib/unittests/convert().c().
  2506. */
  2507. DBBOOL
  2508. dbwillconvert(int srctype, int desttype)
  2509. {
  2510. tdsdump_log(TDS_DBG_FUNC, "dbwillconvert(%s, %s)\n", tds_prdatatype(srctype), tds_prdatatype(desttype));
  2511. return tds_willconvert(srctype, desttype) ? TRUE : FALSE;
  2512. }
  2513. /**
  2514. * \ingroup dblib_core
  2515. * \brief Get the datatype of a regular result set column.
  2516. *
  2517. *
  2518. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2519. * \param column Nth in the result set, starting from 1.
  2520. * \returns \c SYB* datetype token value, or zero if \a column out of range
  2521. * \sa dbcollen(), dbcolname(), dbdata(), dbdatlen(), dbnumcols(), dbprtype(), dbvarylen().
  2522. */
  2523. int
  2524. dbcoltype(DBPROCESS * dbproc, int column)
  2525. {
  2526. TDSCOLUMN *colinfo;
  2527. tdsdump_log(TDS_DBG_FUNC, "dbcoltype(%p, %d)\n", dbproc, column);
  2528. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2529. colinfo = dbcolptr(dbproc, column);
  2530. if (!colinfo)
  2531. return -1;
  2532. switch (colinfo->column_type) {
  2533. case SYBVARCHAR:
  2534. return SYBCHAR;
  2535. case SYBVARBINARY:
  2536. return SYBBINARY;
  2537. }
  2538. return tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  2539. }
  2540. /**
  2541. * \ingroup dblib_core
  2542. * \brief Get user-defined datatype of a regular result column.
  2543. *
  2544. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2545. * \param column Nth in the result set, starting from 1.
  2546. * \returns \c SYB* datetype token value, or -1 if \a column out of range
  2547. * \sa dbaltutype(), dbcoltype().
  2548. */
  2549. int
  2550. dbcolutype(DBPROCESS * dbproc, int column)
  2551. {
  2552. TDSCOLUMN *colinfo;
  2553. tdsdump_log(TDS_DBG_FUNC, "dbcolutype(%p, %d)\n", dbproc, column);
  2554. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2555. colinfo = dbcolptr(dbproc, column);
  2556. if (!colinfo)
  2557. return -1;
  2558. return colinfo->column_usertype;
  2559. }
  2560. /**
  2561. * \ingroup dblib_core
  2562. * \brief Get precision and scale information for a regular result column.
  2563. *
  2564. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2565. * \param column Nth in the result set, starting from 1.
  2566. * \return Pointer to a DBTYPEINFO structure . NULL \a column is out of range.
  2567. * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols(), dbprtype(), dbvarylen().
  2568. */
  2569. DBTYPEINFO *
  2570. dbcoltypeinfo(DBPROCESS * dbproc, int column)
  2571. {
  2572. /* moved typeinfo from static into dbproc structure to make thread safe. (mlilback 11/7/01) */
  2573. TDSCOLUMN *colinfo;
  2574. tdsdump_log(TDS_DBG_FUNC, "dbcoltypeinfo(%p, %d)\n", dbproc, column);
  2575. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2576. colinfo = dbcolptr(dbproc, column);
  2577. if (!colinfo)
  2578. return NULL;
  2579. dbproc->typeinfo.precision = colinfo->column_prec;
  2580. dbproc->typeinfo.scale = colinfo->column_scale;
  2581. return &dbproc->typeinfo;
  2582. }
  2583. /**
  2584. * \brief Get a bunch of column attributes with a single call (Microsoft-compatibility feature).
  2585. *
  2586. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2587. * \param type must be CI_REGULAR or CI_ALTERNATE (CI_CURSOR is defined by the vendor, but is not yet implemented).
  2588. * \param column Nth in the result set, starting from 1.
  2589. * \param computeid (ignored)
  2590. * \param pdbcol address of structure to be populated by this function.
  2591. * \return SUCCEED or FAIL.
  2592. * \sa dbcolbrowse(), dbqual(), dbtabbrowse(), dbtabcount(), dbtabname(), dbtabsource(), dbtsnewlen(), dbtsnewval(), dbtsput().
  2593. * \todo Support cursor rows.
  2594. */
  2595. RETCODE
  2596. dbcolinfo (DBPROCESS *dbproc, CI_TYPE type, DBINT column, DBINT computeid, DBCOL *pdbcol )
  2597. {
  2598. DBTYPEINFO *ps;
  2599. TDSCOMPUTEINFO *info;
  2600. TDSCOLUMN *colinfo;
  2601. int i;
  2602. tdsdump_log(TDS_DBG_FUNC, "dbcolinfo(%p, %d, %d, %d, %p)\n", dbproc, type, column, computeid, pdbcol);
  2603. CHECK_PARAMETER(dbproc, SYBENULL, FAIL);
  2604. colinfo = dbcolptr(dbproc, column);
  2605. if (!colinfo)
  2606. return FAIL;
  2607. CHECK_NULP(pdbcol, "dbcolinfo", 5, FAIL);
  2608. if (type == CI_REGULAR) {
  2609. tds_strlcpy(pdbcol->Name, dbcolname(dbproc, column), sizeof(pdbcol->Name));
  2610. tds_strlcpy(pdbcol->ActualName, dbcolname(dbproc, column), sizeof(pdbcol->ActualName));
  2611. pdbcol->Type = dbcoltype(dbproc, column);
  2612. pdbcol->UserType = dbcolutype(dbproc, column);
  2613. pdbcol->MaxLength = dbcollen(dbproc, column);
  2614. pdbcol->Null = _dbnullable(dbproc, column);
  2615. pdbcol->VarLength = dbvarylen(dbproc, column);
  2616. ps = dbcoltypeinfo(dbproc, column);
  2617. if( ps ) {
  2618. pdbcol->Precision = ps->precision;
  2619. pdbcol->Scale = ps->scale;
  2620. }
  2621. pdbcol->Updatable = colinfo->column_writeable ? TRUE : FALSE;
  2622. pdbcol->Identity = colinfo->column_identity ? TRUE : FALSE;
  2623. return SUCCEED;
  2624. }
  2625. if (type == CI_ALTERNATE) {
  2626. if (computeid == 0)
  2627. return FAIL;
  2628. for (i = 0;; ++i) {
  2629. if (i >= dbproc->tds_socket->num_comp_info)
  2630. return FAIL;
  2631. info = dbproc->tds_socket->comp_info[i];
  2632. if (info->computeid == computeid)
  2633. break;
  2634. }
  2635. /* if either the compute id or the column number are invalid, return -1 */
  2636. if (column < 1 || column > info->num_cols)
  2637. return FAIL;
  2638. colinfo = info->columns[column - 1];
  2639. tds_strlcpy(pdbcol->Name, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->Name));
  2640. tds_strlcpy(pdbcol->ActualName, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->ActualName));
  2641. pdbcol->Type = dbalttype(dbproc, computeid, column);
  2642. pdbcol->UserType = dbaltutype(dbproc, computeid, column);
  2643. pdbcol->MaxLength = dbaltlen(dbproc, computeid, column);
  2644. if (colinfo->column_nullable)
  2645. pdbcol->Null = TRUE;
  2646. else
  2647. pdbcol->Null = FALSE;
  2648. pdbcol->VarLength = FALSE;
  2649. if (colinfo->column_nullable
  2650. || is_nullable_type(colinfo->column_type))
  2651. pdbcol->VarLength = TRUE;
  2652. pdbcol->Precision = colinfo->column_prec;
  2653. pdbcol->Scale = colinfo->column_scale;
  2654. pdbcol->Updatable = colinfo->column_writeable ? TRUE : FALSE ;
  2655. pdbcol->Identity = colinfo->column_identity ? TRUE : FALSE ;
  2656. return SUCCEED;
  2657. }
  2658. return FAIL;
  2659. }
  2660. /**
  2661. * \ingroup dblib_core
  2662. * \brief Get base database column name for a result set column.
  2663. *
  2664. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2665. * \param column Nth in the result set, starting from 1.
  2666. * \return pointer to ASCII null-terminated string, the name of the column. On error, NULL.
  2667. * \sa dbcolbrowse(), dbqual(), dbtabbrowse(), dbtabcount(), dbtabname(), dbtabsource(), dbtsnewlen(), dbtsnewval(), dbtsput().
  2668. */
  2669. char *
  2670. dbcolsource(DBPROCESS * dbproc, int column)
  2671. {
  2672. TDSCOLUMN *colinfo;
  2673. tdsdump_log(TDS_DBG_FUNC, "dbcolsource(%p, %d)\n", dbproc, column);
  2674. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2675. colinfo = dbcolptr(dbproc, column);
  2676. if (!colinfo)
  2677. return NULL;
  2678. return tds_dstr_buf(tds_dstr_isempty(&colinfo->table_column_name) ?
  2679. &colinfo->column_name :
  2680. &colinfo->table_column_name);
  2681. }
  2682. /**
  2683. * \ingroup dblib_core
  2684. * \brief Get size of a regular result column.
  2685. *
  2686. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2687. * \param column Nth in the result set, starting from 1.
  2688. * \return size of the column (not of data in any particular row). On error, -1.
  2689. * \sa dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols().
  2690. */
  2691. DBINT
  2692. dbcollen(DBPROCESS * dbproc, int column)
  2693. {
  2694. TDSCOLUMN *colinfo;
  2695. tdsdump_log(TDS_DBG_FUNC, "dbcollen(%p, %d)\n", dbproc, column);
  2696. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  2697. colinfo = dbcolptr(dbproc, column);
  2698. if (!colinfo)
  2699. return -1;
  2700. return colinfo->column_size;
  2701. }
  2702. /* dbvarylen(), pkleef@openlinksw.com 01/21/02 */
  2703. /**
  2704. * \ingroup dblib_core
  2705. * \brief Determine whether a column can vary in size.
  2706. *
  2707. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2708. * \param column Nth in the result set, starting from 1.
  2709. * \retval TRUE datatype of column can vary in size, or is nullable.
  2710. * \retval FALSE datatype of column is fixed and is not nullable.
  2711. * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols(), dbprtype().
  2712. */
  2713. DBINT
  2714. dbvarylen(DBPROCESS * dbproc, int column)
  2715. {
  2716. TDSCOLUMN *colinfo;
  2717. tdsdump_log(TDS_DBG_FUNC, "dbvarylen(%p, %d)\n", dbproc, column);
  2718. CHECK_PARAMETER(dbproc, SYBENULL, FALSE);
  2719. colinfo = dbcolptr(dbproc, column);
  2720. if (!colinfo)
  2721. return FALSE;
  2722. if (colinfo->column_nullable)
  2723. return TRUE;
  2724. switch (colinfo->column_type) {
  2725. /* variable length fields */
  2726. case SYBNVARCHAR:
  2727. case SYBVARBINARY:
  2728. case SYBVARCHAR:
  2729. return TRUE;
  2730. /* types that can be null */
  2731. case SYBBITN:
  2732. case SYBDATETIMN:
  2733. case SYBDECIMAL:
  2734. case SYBFLTN:
  2735. case SYBINTN:
  2736. case SYBMONEYN:
  2737. case SYBNUMERIC:
  2738. return TRUE;
  2739. /* blob types */
  2740. case SYBIMAGE:
  2741. case SYBNTEXT:
  2742. case SYBTEXT:
  2743. return TRUE;
  2744. }
  2745. return FALSE;
  2746. }
  2747. /**
  2748. * \ingroup dblib_core
  2749. * \brief Get size of current row's data in a regular result column.
  2750. *
  2751. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2752. * \param column Nth in the result set, starting from 1.
  2753. * \return size of the data, in bytes.
  2754. * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbnumcols().
  2755. */
  2756. DBINT
  2757. dbdatlen(DBPROCESS * dbproc, int column)
  2758. {
  2759. DBINT len;
  2760. TDSCOLUMN *colinfo;
  2761. tdsdump_log(TDS_DBG_FUNC, "dbdatlen(%p, %d)\n", dbproc, column);
  2762. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  2763. colinfo = dbcolptr(dbproc, column);
  2764. if (!colinfo)
  2765. return -1;
  2766. len = (colinfo->column_cur_size < 0)? 0 : colinfo->column_cur_size;
  2767. tdsdump_log(TDS_DBG_FUNC, "dbdatlen() type = %d, len= %d\n", colinfo->column_type, len);
  2768. return len;
  2769. }
  2770. /**
  2771. * \ingroup dblib_core
  2772. * \brief Get address of data in a regular result column.
  2773. *
  2774. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2775. * \param column Nth in the result set, starting from 1.
  2776. * \return pointer the data, or NULL if data are NULL, or if \a column is out of range.
  2777. * \sa dbbind(), dbcollen(), dbcolname(), dbcoltype(), dbdatlen(), dbnumcols().
  2778. */
  2779. BYTE *
  2780. dbdata(DBPROCESS * dbproc, int column)
  2781. {
  2782. TDSCOLUMN *colinfo;
  2783. const static BYTE empty[1] = { 0 };
  2784. tdsdump_log(TDS_DBG_FUNC, "dbdata(%p, %d)\n", dbproc, column);
  2785. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2786. colinfo = dbcolptr(dbproc, column);
  2787. if (!colinfo)
  2788. return NULL;
  2789. if (colinfo->column_cur_size < 0)
  2790. return NULL;
  2791. if (is_blob_col(colinfo)) {
  2792. BYTE *res = (BYTE *) ((TDSBLOB *) colinfo->column_data)->textvalue;
  2793. if (!res)
  2794. return (BYTE *) empty;
  2795. return res;
  2796. }
  2797. return (BYTE *) colinfo->column_data;
  2798. }
  2799. /**
  2800. * \ingroup dblib_core
  2801. * \brief Cancel the current command batch.
  2802. *
  2803. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2804. * \retval SUCCEED always.
  2805. * \sa dbcanquery(), dbnextrow(), dbresults(), dbsetinterrupt(), dbsqlexec(), dbsqlok(), dbsqlsend().
  2806. * \todo Check for failure and return accordingly.
  2807. */
  2808. RETCODE
  2809. dbcancel(DBPROCESS * dbproc)
  2810. {
  2811. TDSSOCKET *tds;
  2812. tdsdump_log(TDS_DBG_FUNC, "dbcancel(%p)\n", dbproc);
  2813. CHECK_CONN(FAIL);
  2814. tds = dbproc->tds_socket;
  2815. tds_send_cancel(tds);
  2816. tds_process_cancel(tds);
  2817. return SUCCEED;
  2818. }
  2819. /**
  2820. * \ingroup dblib_core
  2821. * \brief Determine size buffer required to hold the results returned by dbsprhead(), dbsprline(), and dbspr1row().
  2822. *
  2823. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2824. * \return size of buffer requirement, in bytes.
  2825. * \remarks An esoteric function.
  2826. * \sa dbprhead(), dbprrow(), dbspr1row(), dbsprhead(), dbsprline().
  2827. */
  2828. DBINT
  2829. dbspr1rowlen(DBPROCESS * dbproc)
  2830. {
  2831. TDSSOCKET *tds;
  2832. int col, len = 0;
  2833. tdsdump_log(TDS_DBG_FUNC, "dbspr1rowlen(%p)\n", dbproc);
  2834. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  2835. CHECK_PARAMETER(dbproc->tds_socket, SYBEDDNE, 0);
  2836. tds = dbproc->tds_socket;
  2837. for (col = 0; col < tds->res_info->num_cols; col++) {
  2838. TDSCOLUMN *colinfo = tds->res_info->columns[col];
  2839. int collen = _get_printable_size(colinfo);
  2840. int namlen = tds_dstr_len(&colinfo->column_name);
  2841. len += collen > namlen ? collen : namlen;
  2842. if (col > 0) /* allow for the space between columns */
  2843. len += dbstring_length(dbproc->dbopts[DBPRCOLSEP].param);
  2844. }
  2845. return ++len; /* allow for the nul */
  2846. }
  2847. /**
  2848. * \ingroup dblib_core
  2849. * \brief Print a regular result row to a buffer.
  2850. *
  2851. * Fills a buffer with one data row, represented as a null-terminated ASCII string. Helpful for debugging.
  2852. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2853. * \param buffer \em output: Address of a buffer to hold ASCII null-terminated string.
  2854. * \param buf_len size of \a buffer, in bytes.
  2855. * \retval SUCCEED on success.
  2856. * \retval FAIL trouble encountered.
  2857. * \sa dbclropt(), dbisopt(), dbprhead(), dbprrow(), dbspr1rowlen(), dbsprhead(), dbsprline().
  2858. */
  2859. RETCODE
  2860. dbspr1row(DBPROCESS * dbproc, char *buffer, DBINT buf_len)
  2861. {
  2862. TDSSOCKET *tds;
  2863. TDSDATEREC when;
  2864. int i, c, col;
  2865. int desttype, srctype;
  2866. DBINT len;
  2867. tdsdump_log(TDS_DBG_FUNC, "dbspr1row(%p, %s, %d)\n", dbproc, buffer, buf_len);
  2868. CHECK_CONN(FAIL);
  2869. CHECK_NULP(buffer, "dbspr1row", 2, FAIL);
  2870. if (!dbproc->tds_socket)
  2871. return FAIL;
  2872. tds = dbproc->tds_socket;
  2873. for (col = 0; col < tds->res_info->num_cols; col++) {
  2874. int padlen, collen, namlen;
  2875. TDSCOLUMN *colinfo = tds->res_info->columns[col];
  2876. if (colinfo->column_cur_size < 0) {
  2877. len = 4;
  2878. if (buf_len <= len) {
  2879. return FAIL;
  2880. }
  2881. strcpy(buffer, "NULL");
  2882. } else {
  2883. desttype = dblib_bound_type(STRINGBIND);
  2884. srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  2885. if (srctype == SYBDATETIME || srctype == SYBDATETIME4) {
  2886. tds_datecrack(srctype, dbdata(dbproc, col + 1), &when);
  2887. len = (int)tds_strftime(buffer, buf_len, "%b %d %Y %I:%M%p", &when, 3);
  2888. } else {
  2889. len = dbconvert(dbproc, srctype, dbdata(dbproc, col + 1), dbdatlen(dbproc, col + 1),
  2890. desttype, (BYTE *) buffer, buf_len);
  2891. }
  2892. if (len == -1) {
  2893. return FAIL;
  2894. }
  2895. }
  2896. buffer += len;
  2897. buf_len -= len;
  2898. collen = _get_printable_size(colinfo);
  2899. namlen = tds_dstr_len(&colinfo->column_name);
  2900. padlen = (collen > namlen ? collen : namlen) - len;
  2901. if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
  2902. c = ' ';
  2903. }
  2904. for (; padlen > 0; padlen--) {
  2905. if (buf_len < 1) {
  2906. return FAIL;
  2907. }
  2908. *buffer++ = c;
  2909. buf_len--;
  2910. }
  2911. if ((col + 1) < tds->res_info->num_cols) {
  2912. i = 0;
  2913. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
  2914. if (buf_len < 1) {
  2915. return FAIL;
  2916. }
  2917. *buffer++ = c;
  2918. buf_len--;
  2919. i++;
  2920. }
  2921. }
  2922. }
  2923. if (buf_len < 1) {
  2924. return FAIL;
  2925. }
  2926. *buffer = '\0';
  2927. return SUCCEED;
  2928. }
  2929. /**
  2930. * \ingroup dblib_core
  2931. * \brief Print a result set to stdout.
  2932. *
  2933. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  2934. * \sa dbbind(), dbnextrow(), dbprhead(), dbresults(), dbspr1row(), dbsprhead(), dbsprline().
  2935. */
  2936. RETCODE
  2937. dbprrow(DBPROCESS * dbproc)
  2938. {
  2939. TDSCOLUMN *colinfo;
  2940. TDSRESULTINFO *resinfo;
  2941. TDSSOCKET *tds;
  2942. int i, col, collen, namlen, len;
  2943. char dest[8192];
  2944. int desttype, srctype;
  2945. TDSDATEREC when;
  2946. STATUS status;
  2947. int padlen;
  2948. int c;
  2949. int selcol;
  2950. int linechar;
  2951. int op;
  2952. const char *opname;
  2953. /* these are for compute rows */
  2954. DBINT computeid, num_cols, colid;
  2955. TDS_SMALLINT *col_printlens = NULL;
  2956. tdsdump_log(TDS_DBG_FUNC, "dbprrow(%p)\n", dbproc);
  2957. CHECK_CONN(FAIL);
  2958. tds = dbproc->tds_socket;
  2959. while ((status = dbnextrow(dbproc)) != NO_MORE_ROWS) {
  2960. if (status == FAIL) {
  2961. free(col_printlens);
  2962. return FAIL;
  2963. }
  2964. if (status == REG_ROW) {
  2965. resinfo = tds->res_info;
  2966. if (col_printlens == NULL) {
  2967. if ((col_printlens = (TDS_SMALLINT*) calloc(resinfo->num_cols, sizeof(TDS_SMALLINT))) == NULL) {
  2968. dbperror(dbproc, SYBEMEM, errno);
  2969. return FAIL;
  2970. }
  2971. }
  2972. for (col = 0; col < resinfo->num_cols; col++) {
  2973. colinfo = resinfo->columns[col];
  2974. if (colinfo->column_cur_size < 0) {
  2975. len = 4;
  2976. strcpy(dest, "NULL");
  2977. } else {
  2978. desttype = dblib_bound_type(STRINGBIND);
  2979. srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  2980. if (srctype == SYBDATETIME || srctype == SYBDATETIME4) {
  2981. tds_datecrack(srctype, dbdata(dbproc, col + 1), &when);
  2982. len = (int)tds_strftime(dest, sizeof(dest), STD_DATETIME_FMT, &when, 3);
  2983. } else {
  2984. len = dbconvert(dbproc, srctype, dbdata(dbproc, col + 1), dbdatlen(dbproc, col + 1),
  2985. desttype, (BYTE *) dest, sizeof(dest));
  2986. }
  2987. }
  2988. printf("%.*s", len, dest);
  2989. collen = _get_printable_size(colinfo);
  2990. namlen = tds_dstr_len(&colinfo->column_name);
  2991. padlen = (collen > namlen ? collen : namlen) - len;
  2992. c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0);
  2993. for (; c > -1 && padlen > 0; padlen--) {
  2994. putchar(c);
  2995. }
  2996. if ((col + 1) < resinfo->num_cols) {
  2997. i = 0;
  2998. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  2999. putchar(c);
  3000. }
  3001. }
  3002. col_printlens[col] = collen;
  3003. }
  3004. i = 0;
  3005. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
  3006. putchar(c);
  3007. }
  3008. } else {
  3009. computeid = status;
  3010. for (i = 0;; ++i) {
  3011. if (i >= tds->num_comp_info) {
  3012. free(col_printlens);
  3013. return FAIL;
  3014. }
  3015. resinfo = tds->comp_info[i];
  3016. if (resinfo->computeid == computeid)
  3017. break;
  3018. }
  3019. num_cols = dbnumalts(dbproc, computeid);
  3020. tdsdump_log(TDS_DBG_FUNC, "dbprrow num compute cols = %d\n", num_cols);
  3021. i = 0;
  3022. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
  3023. putchar(c);
  3024. }
  3025. for (selcol = col = 1; col <= num_cols; col++) {
  3026. tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
  3027. colid = dbaltcolid(dbproc, computeid, col);
  3028. /*
  3029. * The pad character is pointed to by dbopts[DBPRPAD].param. If that pointer
  3030. * is NULL -- meaning padding is turned off -- dbstring_getchar returns -1.
  3031. */
  3032. while (selcol < colid) {
  3033. for (i = 0; i < col_printlens[selcol - 1]; i++) {
  3034. if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) >= 0)
  3035. putchar(c);
  3036. }
  3037. selcol++;
  3038. i = 0;
  3039. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3040. putchar(c);
  3041. }
  3042. }
  3043. op = dbaltop(dbproc, computeid, col);
  3044. opname = dbprtype(op);
  3045. printf("%s", opname);
  3046. for (i = 0; i < ((long) col_printlens[selcol - 1] - (long) strlen(opname)); i++) {
  3047. if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) >= 0)
  3048. putchar(c);
  3049. }
  3050. selcol++;
  3051. if ((colid + 1) < num_cols) {
  3052. i = 0;
  3053. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3054. putchar(c);
  3055. }
  3056. }
  3057. }
  3058. i = 0;
  3059. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
  3060. putchar(c);
  3061. }
  3062. for (selcol = col = 1; col <= num_cols; col++) {
  3063. tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
  3064. colid = dbaltcolid(dbproc, computeid, col);
  3065. while (selcol < colid) {
  3066. for (i = 0; i < col_printlens[selcol - 1]; i++) {
  3067. putchar(' ');
  3068. }
  3069. selcol++;
  3070. i = 0;
  3071. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3072. putchar(c);
  3073. }
  3074. }
  3075. if (resinfo->by_cols > 0) {
  3076. linechar = '-';
  3077. } else {
  3078. linechar = '=';
  3079. }
  3080. for (i = 0; i < col_printlens[colid - 1]; i++)
  3081. putchar(linechar);
  3082. selcol++;
  3083. if ((colid + 1) < num_cols) {
  3084. i = 0;
  3085. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3086. putchar(c);
  3087. }
  3088. }
  3089. }
  3090. i = 0;
  3091. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
  3092. putchar(c);
  3093. }
  3094. for (selcol = col = 1; col <= num_cols; col++) {
  3095. colinfo = resinfo->columns[col - 1];
  3096. desttype = dblib_bound_type(STRINGBIND);
  3097. srctype = dbalttype(dbproc, computeid, col);
  3098. if (srctype == SYBDATETIME || srctype == SYBDATETIME4) {
  3099. tds_datecrack(srctype, dbadata(dbproc, computeid, col), &when);
  3100. len = (int)tds_strftime(dest, sizeof(dest), STD_DATETIME_FMT, &when, 3);
  3101. } else {
  3102. len = dbconvert(dbproc, srctype, dbadata(dbproc, computeid, col), -1, desttype,
  3103. (BYTE *) dest, sizeof(dest));
  3104. }
  3105. tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
  3106. colid = dbaltcolid(dbproc, computeid, col);
  3107. tdsdump_log(TDS_DBG_FUNC, "dbprrow select column = %d\n", colid);
  3108. while (selcol < colid) {
  3109. for (i = 0; i < col_printlens[selcol - 1]; i++) {
  3110. putchar(' ');
  3111. }
  3112. selcol++;
  3113. i = 0;
  3114. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3115. putchar(c);
  3116. }
  3117. }
  3118. printf("%.*s", len, dest);
  3119. collen = _get_printable_size(colinfo);
  3120. namlen = tds_dstr_len(&colinfo->column_name);
  3121. padlen = (collen > namlen ? collen : namlen) - len;
  3122. if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
  3123. c = ' ';
  3124. }
  3125. for (; padlen > 0; padlen--) {
  3126. putchar(c);
  3127. }
  3128. selcol++;
  3129. if ((colid + 1) < num_cols) {
  3130. i = 0;
  3131. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
  3132. putchar(c);
  3133. }
  3134. }
  3135. }
  3136. i = 0;
  3137. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
  3138. putchar(c);
  3139. }
  3140. }
  3141. }
  3142. free(col_printlens);
  3143. return SUCCEED;
  3144. }
  3145. /*
  3146. * src/tds/convert.c::tds_willconvert() returns same information.
  3147. * Available to user via dbwillconvert().
  3148. */
  3149. static int
  3150. _get_printable_size(TDSCOLUMN * colinfo)
  3151. {
  3152. switch (colinfo->column_type) {
  3153. case SYBINTN:
  3154. switch (colinfo->column_size) {
  3155. case 1:
  3156. return 3;
  3157. case 2:
  3158. return 6;
  3159. case 4:
  3160. return 11;
  3161. case 8:
  3162. return 21;
  3163. }
  3164. case SYBINT1:
  3165. return 3;
  3166. case SYBINT2:
  3167. return 6;
  3168. case SYBINT4:
  3169. return 11;
  3170. case SYBINT8:
  3171. return 21;
  3172. case SYBVARCHAR:
  3173. case SYBCHAR:
  3174. return colinfo->column_size;
  3175. case SYBFLT8:
  3176. case SYBREAL:
  3177. return 11; /* FIX ME -- we do not track precision */
  3178. case SYBMONEY:
  3179. case SYBMONEY4:
  3180. return 12;
  3181. case SYBDATETIME:
  3182. case SYBDATETIME4:
  3183. case SYBDATETIMN:
  3184. return 26;
  3185. case SYBUNIQUE:
  3186. return 36;
  3187. case SYBBIT:
  3188. case SYBBITN:
  3189. return 1;
  3190. /* FIX ME -- not all types present */
  3191. default:
  3192. return 0;
  3193. }
  3194. }
  3195. /**
  3196. * \ingroup dblib_core
  3197. * \brief Get formatted string for underlining dbsprhead() column names.
  3198. *
  3199. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3200. * \param buffer output buffer
  3201. * \param buf_len size of \a buffer
  3202. * \param line_char character to use to represent underlining.
  3203. * \retval SUCCEED \a buffer filled.
  3204. * \retval FAIL insufficient space in \a buffer, usually.
  3205. * \sa dbprhead(), dbprrow(), dbspr1row(), dbspr1rowlen(), dbsprhead().
  3206. */
  3207. RETCODE
  3208. dbsprline(DBPROCESS * dbproc, char *buffer, DBINT buf_len, DBCHAR line_char)
  3209. {
  3210. TDSCOLUMN *colinfo;
  3211. TDSRESULTINFO *resinfo;
  3212. TDSSOCKET *tds;
  3213. int i, col, len, collen, namlen;
  3214. int c;
  3215. tdsdump_log(TDS_DBG_FUNC, "dbsprline(%p, %s, %d, '%c')\n", dbproc, buffer, buf_len, line_char);
  3216. CHECK_CONN(FAIL);
  3217. CHECK_NULP(buffer, "dbsprline", 2, FAIL);
  3218. tds = dbproc->tds_socket;
  3219. resinfo = tds->res_info;
  3220. for (col = 0; col < resinfo->num_cols; col++) {
  3221. colinfo = resinfo->columns[col];
  3222. collen = _get_printable_size(colinfo);
  3223. namlen = tds_dstr_len(&colinfo->column_name);
  3224. len = collen > namlen ? collen : namlen;
  3225. for (i = 0; i < len; i++) {
  3226. if (buf_len < 1) {
  3227. return FAIL;
  3228. }
  3229. *buffer++ = line_char;
  3230. buf_len--;
  3231. }
  3232. if ((col + 1) < resinfo->num_cols) {
  3233. i = 0;
  3234. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
  3235. if (buf_len < 1) {
  3236. return FAIL;
  3237. }
  3238. *buffer++ = c;
  3239. buf_len--;
  3240. i++;
  3241. }
  3242. }
  3243. }
  3244. if (buf_len < 1) {
  3245. return FAIL;
  3246. }
  3247. *buffer = '\0';
  3248. return SUCCEED;
  3249. }
  3250. /**
  3251. * \ingroup dblib_core
  3252. * \brief Print result set headings to a buffer.
  3253. *
  3254. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3255. * \param buffer output buffer
  3256. * \param buf_len size of \a buffer
  3257. * \retval SUCCEED \a buffer filled.
  3258. * \retval FAIL insufficient spaace in \a buffer, usually.
  3259. * \sa dbprhead(), dbprrow(), dbsetopt(), dbspr1row(), dbspr1rowlen(), dbsprline().
  3260. */
  3261. RETCODE
  3262. dbsprhead(DBPROCESS * dbproc, char *buffer, DBINT buf_len)
  3263. {
  3264. TDSCOLUMN *colinfo;
  3265. TDSRESULTINFO *resinfo;
  3266. TDSSOCKET *tds;
  3267. int i, col, collen, namlen;
  3268. int padlen;
  3269. int c;
  3270. tdsdump_log(TDS_DBG_FUNC, "dbsprhead(%p, %s, %d)\n", dbproc, buffer, buf_len);
  3271. CHECK_CONN(FAIL);
  3272. CHECK_NULP(buffer, "dbsprhead", 2, FAIL);
  3273. tds = dbproc->tds_socket;
  3274. resinfo = tds->res_info;
  3275. for (col = 0; col < resinfo->num_cols; col++) {
  3276. colinfo = resinfo->columns[col];
  3277. collen = _get_printable_size(colinfo);
  3278. namlen = tds_dstr_len(&colinfo->column_name);
  3279. padlen = (collen > namlen ? collen : namlen) - namlen;
  3280. if (buf_len < namlen) {
  3281. return FAIL;
  3282. }
  3283. strncpy(buffer, tds_dstr_cstr(&colinfo->column_name), namlen);
  3284. buffer += namlen;
  3285. if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
  3286. c = ' ';
  3287. }
  3288. for (; padlen > 0; padlen--) {
  3289. if (buf_len < 1) {
  3290. return FAIL;
  3291. }
  3292. *buffer++ = c;
  3293. buf_len--;
  3294. }
  3295. if ((col + 1) < resinfo->num_cols) {
  3296. i = 0;
  3297. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
  3298. if (buf_len < 1) {
  3299. return FAIL;
  3300. }
  3301. *buffer++ = c;
  3302. buf_len--;
  3303. i++;
  3304. }
  3305. }
  3306. }
  3307. if (buf_len < 1) {
  3308. return FAIL;
  3309. }
  3310. *buffer = '\0';
  3311. return SUCCEED;
  3312. }
  3313. /**
  3314. * \ingroup dblib_core
  3315. * \brief Print result set headings to stdout.
  3316. *
  3317. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3318. * \sa
  3319. */
  3320. void
  3321. dbprhead(DBPROCESS * dbproc)
  3322. {
  3323. TDSCOLUMN *colinfo;
  3324. TDSRESULTINFO *resinfo;
  3325. TDSSOCKET *tds;
  3326. int i, col, len, collen, namlen;
  3327. int padlen;
  3328. int c;
  3329. tdsdump_log(TDS_DBG_FUNC, "dbprhead(%p)\n", dbproc);
  3330. CHECK_PARAMETER(dbproc, SYBENULL, );
  3331. tds = dbproc->tds_socket;
  3332. resinfo = tds->res_info;
  3333. if (resinfo == NULL) {
  3334. return;
  3335. }
  3336. for (col = 0; col < resinfo->num_cols; col++) {
  3337. colinfo = resinfo->columns[col];
  3338. collen = _get_printable_size(colinfo);
  3339. namlen = tds_dstr_len(&colinfo->column_name);
  3340. padlen = (collen > namlen ? collen : namlen) - namlen;
  3341. printf("%s", tds_dstr_cstr(&colinfo->column_name));
  3342. c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0);
  3343. if (c == -1) {
  3344. c = ' ';
  3345. }
  3346. for (; padlen > 0; padlen--) {
  3347. putchar(c);
  3348. }
  3349. if ((col + 1) < resinfo->num_cols) {
  3350. i = 0;
  3351. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
  3352. putchar(c);
  3353. i++;
  3354. }
  3355. }
  3356. }
  3357. i = 0;
  3358. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i)) != -1) {
  3359. putchar(c);
  3360. i++;
  3361. }
  3362. for (col = 0; col < resinfo->num_cols; col++) {
  3363. colinfo = resinfo->columns[col];
  3364. collen = _get_printable_size(colinfo);
  3365. namlen = tds_dstr_len(&colinfo->column_name);
  3366. len = collen > namlen ? collen : namlen;
  3367. for (i = 0; i < len; i++)
  3368. putchar('-');
  3369. if ((col + 1) < resinfo->num_cols) {
  3370. i = 0;
  3371. while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
  3372. putchar(c);
  3373. i++;
  3374. }
  3375. }
  3376. }
  3377. i = 0;
  3378. while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i)) != -1) {
  3379. putchar(c);
  3380. i++;
  3381. }
  3382. }
  3383. /** \internal
  3384. * \ingroup dblib_internal
  3385. * \brief Indicate whether a query returned rows.
  3386. *
  3387. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3388. * \sa DBROWS(), DBCMDROW(), dbnextrow(), dbresults(), DBROWTYPE().
  3389. */
  3390. RETCODE
  3391. dbrows(DBPROCESS * dbproc)
  3392. {
  3393. TDSSOCKET *tds;
  3394. tdsdump_log(TDS_DBG_FUNC, "dbrows(%p)\n", dbproc);
  3395. CHECK_CONN(FAIL);
  3396. if (!(tds=dbproc->tds_socket))
  3397. return FAIL;
  3398. return (tds->res_info && tds->res_info->rows_exist)? SUCCEED : FAIL;
  3399. }
  3400. #if defined(DBLIB_UNIMPLEMENTED)
  3401. /**
  3402. * \ingroup dblib_core
  3403. * \brief Set the default character set for an application.
  3404. *
  3405. * \param language ASCII null-terminated string.
  3406. * \sa dbsetdeflang(), dbsetdefcharset(), dblogin(), dbopen().
  3407. * \retval SUCCEED Always.
  3408. * \todo Unimplemented.
  3409. */
  3410. RETCODE
  3411. dbsetdeflang(char *language)
  3412. {
  3413. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetdeflang(%s)\n", language);
  3414. CHECK_PARAMETER_NOPROC(language, SYBENULP);
  3415. return SUCCEED;
  3416. }
  3417. #endif
  3418. /**
  3419. * \ingroup dblib_core
  3420. * \brief Get TDS packet size for the connection.
  3421. *
  3422. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3423. * \return TDS packet size, in bytes.
  3424. * \sa DBSETLPACKET()
  3425. */
  3426. int
  3427. dbgetpacket(DBPROCESS * dbproc)
  3428. {
  3429. TDSSOCKET *tds;
  3430. tdsdump_log(TDS_DBG_FUNC, "dbgetpacket(%p)\n", dbproc);
  3431. CHECK_PARAMETER(dbproc, SYBENULL, TDS_DEF_BLKSZ);
  3432. tds = dbproc->tds_socket;
  3433. if (!tds) {
  3434. return TDS_DEF_BLKSZ;
  3435. } else {
  3436. return tds->conn->env.block_size;
  3437. }
  3438. }
  3439. /**
  3440. * \ingroup dblib_core
  3441. * \brief Set maximum simultaneous connections db-lib will open to the server.
  3442. *
  3443. * \param maxprocs Limit for process.
  3444. * \retval SUCCEED Always.
  3445. * \sa dbgetmaxprocs(), dbopen()
  3446. */
  3447. RETCODE
  3448. dbsetmaxprocs(int maxprocs)
  3449. {
  3450. int i, j;
  3451. TDSSOCKET **old_list;
  3452. tdsdump_log(TDS_DBG_FUNC, "UNTESTED dbsetmaxprocs(%d)\n", maxprocs);
  3453. /* not too few elements */
  3454. if (maxprocs <= 0)
  3455. return FAIL;
  3456. tds_mutex_lock(&dblib_mutex);
  3457. old_list = g_dblib_ctx.connection_list;
  3458. /* "compress" array */
  3459. for (i = 0; i < g_dblib_ctx.connection_list_size; ++i) {
  3460. /* if empty replace with first no-empty */
  3461. if (old_list[i])
  3462. continue;
  3463. for (j = i + 1; j < g_dblib_ctx.connection_list_size; ++j)
  3464. if (old_list[j]) {
  3465. old_list[i] = old_list[j];
  3466. old_list[j] = NULL;
  3467. break;
  3468. }
  3469. if (j >= g_dblib_ctx.connection_list_size)
  3470. break;
  3471. }
  3472. /* do not restrict too much, i here contains minimun size */
  3473. if (maxprocs < i)
  3474. maxprocs = i;
  3475. /*
  3476. * Don't reallocate less memory.
  3477. * If maxprocs is less than was initially allocated, just reduce the represented list size.
  3478. * If larger, reallocate and copy.
  3479. * We probably should check for valid connections beyond the new max.
  3480. */
  3481. if (maxprocs <= g_dblib_ctx.connection_list_size) {
  3482. g_dblib_ctx.connection_list_size_represented = maxprocs;
  3483. tds_mutex_unlock(&dblib_mutex);
  3484. return SUCCEED;
  3485. }
  3486. g_dblib_ctx.connection_list = (TDSSOCKET**) calloc(maxprocs, sizeof(TDSSOCKET *));
  3487. if (g_dblib_ctx.connection_list == NULL) {
  3488. g_dblib_ctx.connection_list = old_list;
  3489. tds_mutex_unlock(&dblib_mutex);
  3490. dbperror(NULL, SYBEMEM, errno);
  3491. return FAIL;
  3492. }
  3493. for (i = 0; i < g_dblib_ctx.connection_list_size; i++) {
  3494. g_dblib_ctx.connection_list[i] = old_list[i];
  3495. }
  3496. g_dblib_ctx.connection_list_size = maxprocs;
  3497. g_dblib_ctx.connection_list_size_represented = maxprocs;
  3498. tds_mutex_unlock(&dblib_mutex);
  3499. return SUCCEED;
  3500. }
  3501. /**
  3502. * \ingroup dblib_core
  3503. * \brief get maximum simultaneous connections db-lib will open to the server.
  3504. *
  3505. * \return Current maximum.
  3506. * \sa dbsetmaxprocs(), dbopen()
  3507. */
  3508. int
  3509. dbgetmaxprocs(void)
  3510. {
  3511. int r;
  3512. tdsdump_log(TDS_DBG_FUNC, "dbgetmaxprocs(void)\n");
  3513. tds_mutex_lock(&dblib_mutex);
  3514. r = g_dblib_ctx.connection_list_size_represented;
  3515. tds_mutex_unlock(&dblib_mutex);
  3516. return r;
  3517. }
  3518. /**
  3519. * \ingroup dblib_core
  3520. * \brief Set maximum seconds db-lib waits for a server response to query.
  3521. *
  3522. * \param seconds New limit for application.
  3523. * \retval SUCCEED Always.
  3524. * \sa dberrhandle(), DBGETTIME(), dbsetlogintime(), dbsqlexec(), dbsqlok(), dbsqlsend().
  3525. */
  3526. RETCODE
  3527. dbsettime(int seconds)
  3528. {
  3529. TDSSOCKET **tds;
  3530. int i;
  3531. tdsdump_log(TDS_DBG_FUNC, "dbsettime(%d)\n", seconds);
  3532. tds_mutex_lock(&dblib_mutex);
  3533. g_dblib_ctx.query_timeout = seconds;
  3534. tds = g_dblib_ctx.connection_list;
  3535. for (i = 0; i < TDS_MAX_CONN; i++) {
  3536. if (tds[i])
  3537. tds[i]->query_timeout = seconds;
  3538. }
  3539. tds_mutex_unlock(&dblib_mutex);
  3540. return SUCCEED;
  3541. }
  3542. /**
  3543. * \ingroup dblib_core
  3544. * \brief Get maximum seconds db-lib waits for a server response to query.
  3545. *
  3546. * \retval query timeout limit, in seconds
  3547. * \sa dberrhandle(), DBSETTIME(), dbsetlogintime(), dbsqlexec(), dbsqlok(), dbsqlsend().
  3548. */
  3549. int
  3550. dbgettime(void)
  3551. {
  3552. tdsdump_log(TDS_DBG_FUNC, "dbgettime()\n");
  3553. return g_dblib_ctx.query_timeout;
  3554. }
  3555. /**
  3556. * \ingroup dblib_core
  3557. * \brief Set maximum seconds db-lib waits for a server response to a login attempt.
  3558. *
  3559. * \param seconds New limit for application.
  3560. * \retval SUCCEED Always.
  3561. * \sa dberrhandle(), dbsettime()
  3562. */
  3563. RETCODE
  3564. dbsetlogintime(int seconds)
  3565. {
  3566. tdsdump_log(TDS_DBG_FUNC, "dbsetlogintime(%d)\n", seconds);
  3567. tds_mutex_lock(&dblib_mutex);
  3568. g_dblib_ctx.login_timeout = seconds;
  3569. tds_mutex_unlock(&dblib_mutex);
  3570. return SUCCEED;
  3571. }
  3572. /** \internal
  3573. * \ingroup dblib_internal
  3574. * \brief See if the current command can return rows.
  3575. *
  3576. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3577. * \retval SUCCEED Yes, it can.
  3578. * \retval FAIL No, it can't.
  3579. * \remarks Use DBCMDROW() macro instead.
  3580. * \sa DBCMDROW(), dbnextrow(), dbresults(), DBROWS(), DBROWTYPE().
  3581. */
  3582. RETCODE
  3583. dbcmdrow(DBPROCESS * dbproc)
  3584. {
  3585. TDSSOCKET *tds;
  3586. tdsdump_log(TDS_DBG_FUNC, "dbcmdrow(%p)\n", dbproc);
  3587. CHECK_CONN(FAIL);
  3588. tds = dbproc->tds_socket;
  3589. if (tds->res_info)
  3590. return SUCCEED;
  3591. return FAIL;
  3592. }
  3593. /**
  3594. * \ingroup dblib_core
  3595. * \brief Get column ID of a compute column.
  3596. *
  3597. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3598. * \param computeid of \c COMPUTE clause to which we're referring.
  3599. * \param column Nth column in \a computeid, starting from 1.
  3600. * \return Nth column in the base result set, on which \a column was computed.
  3601. * \sa dbadata(), dbadlen(), dbaltlen(), dbgetrow(), dbnextrow(), dbnumalts(), dbprtype().
  3602. */
  3603. int
  3604. dbaltcolid(DBPROCESS * dbproc, int computeid, int column)
  3605. {
  3606. TDSCOLUMN *curcol;
  3607. tdsdump_log(TDS_DBG_FUNC, "dbaltcolid(%p, %d, %d)\n", dbproc, computeid, column);
  3608. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  3609. curcol = dbacolptr(dbproc, computeid, column, 0);
  3610. if (!curcol)
  3611. return -1;
  3612. return curcol->column_operand;
  3613. }
  3614. /**
  3615. * \ingroup dblib_core
  3616. * \brief Get size of data in a compute column.
  3617. *
  3618. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3619. * \param computeid of \c COMPUTE clause to which we're referring.
  3620. * \param column Nth column in \a computeid, starting from 1.
  3621. * \return size of the data, in bytes.
  3622. * \retval -1 no such \a column or \a computeid.
  3623. * \retval 0 data are NULL.
  3624. * \sa dbadata(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumalts().
  3625. */
  3626. DBINT
  3627. dbadlen(DBPROCESS * dbproc, int computeid, int column)
  3628. {
  3629. TDSCOLUMN *colinfo;
  3630. DBINT len;
  3631. tdsdump_log(TDS_DBG_FUNC, "dbadlen(%p, %d, %d)\n", dbproc, computeid, column);
  3632. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  3633. colinfo = dbacolptr(dbproc, computeid, column, 0);
  3634. if (!colinfo)
  3635. return -1;
  3636. len = colinfo->column_cur_size < 0? 0 : colinfo->column_cur_size;
  3637. tdsdump_log(TDS_DBG_FUNC, "leaving dbadlen() type = %d, returning %d\n", colinfo->column_type, len);
  3638. return len;
  3639. }
  3640. /**
  3641. * \ingroup dblib_core
  3642. * \brief Get datatype for a compute column.
  3643. *
  3644. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3645. * \param computeid of \c COMPUTE clause to which we're referring.
  3646. * \param column Nth column in \a computeid, starting from 1.
  3647. * \return \c SYB* dataype token.
  3648. * \retval -1 no such \a column or \a computeid.
  3649. * \sa dbadata(), dbadlen(), dbaltlen(), dbnextrow(), dbnumalts(), dbprtype().
  3650. */
  3651. int
  3652. dbalttype(DBPROCESS * dbproc, int computeid, int column)
  3653. {
  3654. TDSCOLUMN *colinfo;
  3655. tdsdump_log(TDS_DBG_FUNC, "dbalttype(%p, %d, %d)\n", dbproc, computeid, column);
  3656. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  3657. colinfo = dbacolptr(dbproc, computeid, column, 0);
  3658. if (!colinfo)
  3659. return -1;
  3660. switch (colinfo->column_type) {
  3661. case SYBVARCHAR:
  3662. return SYBCHAR;
  3663. case SYBVARBINARY:
  3664. return SYBBINARY;
  3665. }
  3666. return tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  3667. }
  3668. /**
  3669. * \ingroup dblib_core
  3670. * \brief Bind a compute column to a program variable.
  3671. *
  3672. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3673. * \param computeid of \c COMPUTE clause to which we're referring.
  3674. * \param column Nth column in \a computeid, starting from 1.
  3675. * \param vartype datatype of the host variable that will receive the data
  3676. * \param varlen size of host variable pointed to \a varaddr
  3677. * \param varaddr address of host variable
  3678. * \retval SUCCEED everything worked.
  3679. * \retval FAIL no such \a computeid or \a column, or no such conversion possible, or target buffer too small.
  3680. * \sa dbadata(), dbaltbind_ps(), dbanullbind(), dbbind(), dbbind_ps(), dbconvert(),
  3681. * dbconvert_ps(), dbnullbind(), dbsetnull(), dbsetversion(), dbwillconvert().
  3682. */
  3683. RETCODE
  3684. dbaltbind(DBPROCESS * dbproc, int computeid, int column, int vartype, DBINT varlen, BYTE * varaddr)
  3685. {
  3686. int srctype = -1;
  3687. int desttype = -1;
  3688. TDSCOLUMN *colinfo = NULL;
  3689. tdsdump_log(TDS_DBG_FUNC, "dbaltbind(%p, %d, %d, %d, %d, %p)\n", dbproc, computeid, column, vartype, varlen, varaddr);
  3690. CHECK_PARAMETER(dbproc, SYBENULL, FAIL);
  3691. colinfo = dbacolptr(dbproc, computeid, column, 1);
  3692. if (!colinfo)
  3693. return FAIL;
  3694. CHECK_PARAMETER(varaddr, SYBEABNV, FAIL);
  3695. dbproc->avail_flag = FALSE;
  3696. srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  3697. desttype = dblib_bound_type(vartype);
  3698. tdsdump_log(TDS_DBG_INFO1, "dbaltbind() srctype = %d desttype = %d \n", srctype, desttype);
  3699. if (!dbwillconvert(srctype, desttype)) {
  3700. dbperror(dbproc, SYBEAAMT, 0);
  3701. return FAIL;
  3702. }
  3703. colinfo->column_varaddr = (char *) varaddr;
  3704. colinfo->column_bindtype = vartype;
  3705. colinfo->column_bindlen = varlen;
  3706. return SUCCEED;
  3707. }
  3708. /**
  3709. * \ingroup dblib_core
  3710. * \brief Get address of compute column data.
  3711. *
  3712. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3713. * \param computeid of \c COMPUTE clause to which we're referring.
  3714. * \param column Nth column in \a computeid, starting from 1.
  3715. * \return pointer to columns's data buffer.
  3716. * \retval NULL no such \a computeid or \a column.
  3717. * \sa dbadlen(), dbaltbind(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumalts().
  3718. */
  3719. BYTE *
  3720. dbadata(DBPROCESS * dbproc, int computeid, int column)
  3721. {
  3722. TDSCOLUMN *colinfo;
  3723. tdsdump_log(TDS_DBG_FUNC, "dbadata(%p, %d, %d)\n", dbproc, computeid, column);
  3724. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  3725. colinfo = dbacolptr(dbproc, computeid, column, 0);
  3726. if (!colinfo)
  3727. return NULL;
  3728. if (is_blob_col(colinfo)) {
  3729. return (BYTE *) ((TDSBLOB *) colinfo->column_data)->textvalue;
  3730. }
  3731. return (BYTE *) colinfo->column_data;
  3732. }
  3733. /**
  3734. * \ingroup dblib_core
  3735. * \brief Get aggregation operator for a compute column.
  3736. *
  3737. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3738. * \param computeid of \c COMPUTE clause to which we're referring.
  3739. * \param column Nth column in \a computeid, starting from 1.
  3740. * \return token value for the type of the compute column's aggregation operator.
  3741. * \retval -1 no such \a computeid or \a column.
  3742. * \sa dbadata(), dbadlen(), dbaltlen(), dbnextrow(), dbnumalts(), dbprtype().
  3743. */
  3744. int
  3745. dbaltop(DBPROCESS * dbproc, int computeid, int column)
  3746. {
  3747. TDSCOLUMN *curcol;
  3748. tdsdump_log(TDS_DBG_FUNC, "dbaltop(%p, %d, %d)\n", dbproc, computeid, column);
  3749. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  3750. if ((curcol=dbacolptr(dbproc, computeid, column, 0)) == NULL)
  3751. return -1;
  3752. return curcol->column_operator;
  3753. }
  3754. /**
  3755. * \ingroup dblib_core
  3756. * \brief Set db-lib or server option.
  3757. *
  3758. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3759. * \param option option to set.
  3760. * \param char_param value to set \a option to, if it wants a null-teminated ASCII string.
  3761. * \param int_param value to set \a option to, if it wants an integer value.
  3762. * \retval SUCCEED everything worked.
  3763. * \retval FAIL no such \a option, or insufficient memory, or unimplemented.
  3764. * \remarks Many are unimplemented.
  3765. * \sa dbclropt(), dbisopt().
  3766. * \todo Implement more options.
  3767. */
  3768. RETCODE
  3769. dbsetopt(DBPROCESS * dbproc, int option, const char *char_param, int int_param)
  3770. {
  3771. char *cmd;
  3772. RETCODE rc;
  3773. tdsdump_log(TDS_DBG_FUNC, "dbsetopt(%p, %d, %s, %d)\n", dbproc, option, char_param, int_param);
  3774. CHECK_CONN(FAIL);
  3775. CHECK_NULP(char_param, "dbsetopt", 3, FAIL);
  3776. if ((option < 0) || (option >= DBNUMOPTIONS)) {
  3777. dbperror(dbproc, SYBEUNOP, 0);
  3778. return FAIL;
  3779. }
  3780. dbproc->dbopts[option].factive = 1;
  3781. switch (option) {
  3782. case DBARITHABORT:
  3783. case DBARITHIGNORE:
  3784. case DBCHAINXACTS:
  3785. case DBFIPSFLAG:
  3786. case DBISOLATION:
  3787. case DBNOCOUNT:
  3788. case DBNOEXEC:
  3789. case DBPARSEONLY:
  3790. case DBSHOWPLAN:
  3791. case DBSTORPROCID:
  3792. case DBQUOTEDIDENT:
  3793. /* server options (on/off) */
  3794. if (asprintf(&cmd, "set %s on\n", dbproc->dbopts[option].text) < 0) {
  3795. return FAIL;
  3796. }
  3797. rc = dbstring_concat(&(dbproc->dboptcmd), cmd);
  3798. free(cmd);
  3799. return rc;
  3800. break;
  3801. case DBNATLANG:
  3802. case DBDATEFIRST:
  3803. case DBDATEFORMAT:
  3804. /* server options (char_param) */
  3805. if (asprintf(&cmd, "set %s %s\n", dbproc->dbopts[option].text, char_param) < 0) {
  3806. return FAIL;
  3807. }
  3808. rc = dbstring_concat(&(dbproc->dboptcmd), cmd);
  3809. free(cmd);
  3810. return rc;
  3811. break;
  3812. case DBOFFSET:
  3813. /* server option */
  3814. /* requires param
  3815. * "select", "from", "table", "order", "compute",
  3816. * "statement", "procedure", "execute", or "param"
  3817. */
  3818. break;
  3819. case DBROWCOUNT:
  3820. /* server option */
  3821. /* requires param "0" to "2147483647" */
  3822. break;
  3823. case DBSTAT:
  3824. /* server option */
  3825. /* requires param "io" or "time" */
  3826. break;
  3827. case DBTEXTLIMIT:
  3828. /* dblib option */
  3829. /* requires param "0" to "2147483647" */
  3830. /* dblib do not return more than this length from text/image */
  3831. /* TODO required for PHP */
  3832. break;
  3833. case DBTEXTSIZE:
  3834. /* server option */
  3835. /* requires param "0" to "2147483647" */
  3836. /* limit text/image from network */
  3837. break;
  3838. case DBAUTH:
  3839. /* ??? */
  3840. break;
  3841. case DBNOAUTOFREE:
  3842. /* dblib option */
  3843. break;
  3844. case DBBUFFER:
  3845. /*
  3846. * Requires param "2" to "2147483647"
  3847. * (0 or 1 is an error, < 0 yields the default 100)
  3848. */
  3849. {
  3850. int nrows;
  3851. /* 100 is the default, according to Microsoft */
  3852. if( !char_param )
  3853. char_param = "100";
  3854. nrows = atoi(char_param);
  3855. nrows = (nrows < 0 )? 100 : nrows;
  3856. if( 1 < nrows && nrows <= 2147483647 ) {
  3857. buffer_set_capacity(dbproc, nrows);
  3858. return SUCCEED;
  3859. }
  3860. }
  3861. break;
  3862. case DBPRCOLSEP:
  3863. case DBPRLINELEN:
  3864. case DBPRLINESEP:
  3865. rc = dbstring_assign(&(dbproc->dbopts[option].param), char_param);
  3866. return rc;
  3867. case DBPRPAD:
  3868. /*
  3869. * "If the character is not specified, the ASCII space character is used."
  3870. * A NULL pointer to the pad character signifies that padding is turned off.
  3871. */
  3872. if (int_param) {
  3873. rc = dbstring_assign(&(dbproc->dbopts[option].param), char_param? char_param : " ");
  3874. } else {
  3875. rc = dbstring_assign(&(dbproc->dbopts[option].param), NULL);
  3876. }
  3877. return rc;
  3878. break;
  3879. default:
  3880. break;
  3881. }
  3882. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetopt(option = %d)\n", option);
  3883. return FAIL;
  3884. }
  3885. /**
  3886. * \ingroup dblib_core
  3887. * \brief Set interrupt handler for db-lib to use while blocked against a read from the server.
  3888. *
  3889. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3890. * \param chkintr
  3891. * \param hndlintr
  3892. * \sa dbcancel(), dbgetuserdata(), dbsetuserdata(), dbsetbusy(), dbsetidle().
  3893. */
  3894. void
  3895. dbsetinterrupt(DBPROCESS * dbproc, DB_DBCHKINTR_FUNC chkintr, DB_DBHNDLINTR_FUNC hndlintr)
  3896. {
  3897. tdsdump_log(TDS_DBG_FUNC, "dbsetinterrupt(%p, %p, %p)\n", dbproc, chkintr, hndlintr);
  3898. CHECK_PARAMETER(dbproc, SYBENULL, );
  3899. dbproc->chkintr = chkintr;
  3900. dbproc->hndlintr = hndlintr;
  3901. }
  3902. /**
  3903. * \ingroup dblib_rpc
  3904. * \brief Determine if query generated a return status number.
  3905. *
  3906. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3907. * \retval TRUE fetch return status with dbretstatus().
  3908. * \retval FALSE no return status.
  3909. * \sa dbnextrow(), dbresults(), dbretdata(), dbretstatus(), dbrpcinit(), dbrpcparam(), dbrpcsend().
  3910. */
  3911. DBBOOL
  3912. dbhasretstat(DBPROCESS * dbproc)
  3913. {
  3914. TDSSOCKET *tds;
  3915. tdsdump_log(TDS_DBG_FUNC, "dbhasretstat(%p)\n", dbproc);
  3916. CHECK_PARAMETER(dbproc, SYBENULL, FALSE);
  3917. tds = dbproc->tds_socket;
  3918. if (tds->has_status) {
  3919. return TRUE;
  3920. } else {
  3921. return FALSE;
  3922. }
  3923. }
  3924. /**
  3925. * \ingroup dblib_rpc
  3926. * \brief Fetch status value returned by query or remote procedure call.
  3927. *
  3928. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3929. * \return return value
  3930. * \sa dbhasretstat(), dbnextrow(), dbresults(), dbretdata(), dbrpcinit(), dbrpcparam(), dbrpcsend().
  3931. */
  3932. DBINT
  3933. dbretstatus(DBPROCESS * dbproc)
  3934. {
  3935. tdsdump_log(TDS_DBG_FUNC, "dbretstatus(%p)\n", dbproc);
  3936. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  3937. return dbproc->tds_socket->ret_status;
  3938. }
  3939. /**
  3940. * \ingroup dblib_rpc
  3941. * \brief Get count of output parameters filled by a stored procedure.
  3942. *
  3943. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3944. * \return How many, possibly zero.
  3945. * \remarks This name sounds funny.
  3946. * \sa
  3947. */
  3948. int
  3949. dbnumrets(DBPROCESS * dbproc)
  3950. {
  3951. TDSSOCKET *tds;
  3952. TDS_INT result_type;
  3953. tdsdump_log(TDS_DBG_FUNC, "dbnumrets(%p)\n", dbproc);
  3954. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  3955. tds = dbproc->tds_socket;
  3956. tdsdump_log(TDS_DBG_FUNC, "dbnumrets() finds %d columns\n", (tds->param_info? tds->param_info->num_cols : 0));
  3957. /* try to fetch output parameters and return status, if we have not already done so */
  3958. if (!tds->param_info)
  3959. tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
  3960. if (!tds->param_info)
  3961. return 0;
  3962. return tds->param_info->num_cols;
  3963. }
  3964. /**
  3965. * \ingroup dblib_rpc
  3966. * \brief Get name of an output parameter filled by a stored procedure.
  3967. *
  3968. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3969. * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
  3970. * \returns ASCII null-terminated string, \c NULL if no such \a retnum.
  3971. * \sa dbnextrow(), dbnumrets(), dbresults(), dbretdata(), dbretlen(), dbrettype(), dbrpcinit(), dbrpcparam().
  3972. */
  3973. char *
  3974. dbretname(DBPROCESS * dbproc, int retnum)
  3975. {
  3976. TDSPARAMINFO *param_info;
  3977. tdsdump_log(TDS_DBG_FUNC, "dbretname(%p, %d)\n", dbproc, retnum);
  3978. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  3979. if (!dbproc->tds_socket)
  3980. return NULL;
  3981. dbnumrets(dbproc);
  3982. param_info = dbproc->tds_socket->param_info;
  3983. if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
  3984. return NULL;
  3985. return tds_dstr_buf(&param_info->columns[retnum - 1]->column_name);
  3986. }
  3987. /**
  3988. * \ingroup dblib_rpc
  3989. * \brief Get value of an output parameter filled by a stored procedure.
  3990. *
  3991. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  3992. * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
  3993. * \returns Address of a return parameter value, or \c NULL if no such \a retnum.
  3994. * \sa dbnextrow(), dbnumrets(), dbresults(), dbretlen(), dbretname(), dbrettype(), dbrpcinit(), dbrpcparam().
  3995. * \todo Handle blobs.
  3996. */
  3997. BYTE *
  3998. dbretdata(DBPROCESS * dbproc, int retnum)
  3999. {
  4000. TDSCOLUMN *column;
  4001. TDSPARAMINFO *param_info;
  4002. tdsdump_log(TDS_DBG_FUNC, "dbretdata(%p, %d)\n", dbproc, retnum);
  4003. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  4004. dbnumrets(dbproc);
  4005. param_info = dbproc->tds_socket->param_info;
  4006. if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
  4007. return NULL;
  4008. column = param_info->columns[retnum - 1];
  4009. /* FIXME blob are stored is different way */
  4010. return (BYTE *) column->column_data;
  4011. }
  4012. /**
  4013. * \ingroup dblib_rpc
  4014. * \brief Get size of an output parameter filled by a stored procedure.
  4015. *
  4016. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4017. * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
  4018. * \returns Size of a return parameter value, or \c NULL if no such \a retnum.
  4019. * \sa dbnextrow(), dbnumrets(), dbresults(), dbretdata(), dbretname(), dbrettype(), dbrpcinit(), dbrpcparam().
  4020. */
  4021. int
  4022. dbretlen(DBPROCESS * dbproc, int retnum)
  4023. {
  4024. TDSCOLUMN *column;
  4025. TDSPARAMINFO *param_info;
  4026. TDSSOCKET *tds;
  4027. tdsdump_log(TDS_DBG_FUNC, "dbretlen(%p, %d)\n", dbproc, retnum);
  4028. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  4029. dbnumrets(dbproc);
  4030. tds = dbproc->tds_socket;
  4031. param_info = tds->param_info;
  4032. if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
  4033. return -1;
  4034. column = param_info->columns[retnum - 1];
  4035. if (column->column_cur_size < 0)
  4036. return 0;
  4037. return column->column_cur_size;
  4038. }
  4039. /**
  4040. * \ingroup dblib_core
  4041. * \brief Wait for results of a query from the server.
  4042. *
  4043. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4044. * \retval SUCCEED everything worked, fetch results with \c dbnextresults().
  4045. * \retval FAIL SQL syntax error, typically.
  4046. * \sa dbcmd(), dbfcmd(), DBIORDESC(), DBIOWDESC(), dbmoretext(), dbnextrow(),
  4047. dbpoll(), DBRBUF(), dbresults(), dbretstatus(), dbrpcsend(), dbsettime(), dbsqlexec(),
  4048. dbsqlsend(), dbwritetext().
  4049. */
  4050. RETCODE
  4051. dbsqlok(DBPROCESS * dbproc)
  4052. {
  4053. TDSSOCKET *tds;
  4054. TDS_INT result_type;
  4055. RETCODE return_code = SUCCEED;
  4056. tdsdump_log(TDS_DBG_FUNC, "dbsqlok(%p)\n", dbproc);
  4057. CHECK_CONN(FAIL);
  4058. tds = dbproc->tds_socket;
  4059. /*
  4060. * dbsqlok has been called after dbmoretext()
  4061. * This is the trigger to send the text data.
  4062. */
  4063. if (dbproc->text_sent) {
  4064. tds_flush_packet(tds);
  4065. dbproc->text_sent = 0;
  4066. }
  4067. /*
  4068. * See what the next packet from the server is.
  4069. * We want to skip any messages which are not processable.
  4070. * We're looking for a result token or a done token.
  4071. */
  4072. for (;;) {
  4073. TDSRET tds_code;
  4074. int done_flags = 0;
  4075. /*
  4076. * If we hit an end token -- e.g. if the command
  4077. * submitted returned no data (like an insert) -- then
  4078. * we process the end token to extract the status code.
  4079. */
  4080. tdsdump_log(TDS_DBG_FUNC, "dbsqlok() not done, calling tds_process_tokens()\n");
  4081. tds_code = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS);
  4082. /*
  4083. * The error flag may be set for any intervening DONEINPROC packet, in particular
  4084. * by a RAISERROR statement. Microsoft db-lib returns FAIL in that case.
  4085. */
  4086. if (done_flags & TDS_DONE_ERROR) {
  4087. return_code = FAIL;
  4088. }
  4089. switch (tds_code) {
  4090. case TDS_NO_MORE_RESULTS:
  4091. return SUCCEED;
  4092. break;
  4093. case TDS_SUCCESS:
  4094. switch (result_type) {
  4095. case TDS_ROWFMT_RESULT:
  4096. buffer_free(&dbproc->row_buf);
  4097. buffer_alloc(dbproc);
  4098. case TDS_COMPUTEFMT_RESULT:
  4099. dbproc->dbresults_state = _DB_RES_RESULTSET_EMPTY;
  4100. case TDS_COMPUTE_RESULT:
  4101. case TDS_ROW_RESULT:
  4102. tdsdump_log(TDS_DBG_FUNC, "dbsqlok() found result token\n");
  4103. return SUCCEED;
  4104. break;
  4105. case TDS_DONEINPROC_RESULT:
  4106. break;
  4107. case TDS_DONE_RESULT:
  4108. case TDS_DONEPROC_RESULT:
  4109. tdsdump_log(TDS_DBG_FUNC, "dbsqlok() end status is %s\n", prdbretcode(return_code));
  4110. #if 1
  4111. if (done_flags & TDS_DONE_ERROR) {
  4112. if (done_flags & TDS_DONE_MORE_RESULTS) {
  4113. dbproc->dbresults_state = _DB_RES_NEXT_RESULT;
  4114. } else {
  4115. dbproc->dbresults_state = _DB_RES_NO_MORE_RESULTS;
  4116. }
  4117. } else {
  4118. tdsdump_log(TDS_DBG_FUNC, "dbsqlok() end status was success\n");
  4119. dbproc->dbresults_state = _DB_RES_SUCCEED;
  4120. }
  4121. return return_code;
  4122. break;
  4123. #else
  4124. int retcode = (done_flags & TDS_DONE_ERROR)? FAIL : SUCCEED;
  4125. dbproc->dbresults_state = (done_flags & TDS_DONE_MORE_RESULTS)?
  4126. _DB_RES_NEXT_RESULT : _DB_RES_NO_MORE_RESULTS;
  4127. tdsdump_log(TDS_DBG_FUNC, "dbsqlok: returning %s with %s (%#x)\n",
  4128. prdbretcode(retcode), prdbresults_state(dbproc->dbresults_state), done_flags);
  4129. if (retcode == SUCCEED && (done_flags & TDS_DONE_MORE_RESULTS))
  4130. continue;
  4131. return retcode;
  4132. #endif
  4133. default:
  4134. tdsdump_log(TDS_DBG_FUNC, "%s %d: logic error: tds_process_tokens result_type %d\n",
  4135. __FILE__, __LINE__, result_type);
  4136. break;
  4137. }
  4138. break;
  4139. default:
  4140. assert(TDS_FAILED(tds_code));
  4141. return FAIL;
  4142. break;
  4143. }
  4144. }
  4145. return SUCCEED;
  4146. }
  4147. /**
  4148. * \ingroup dblib_core
  4149. * \brief Get count of columns in a compute row.
  4150. *
  4151. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4152. * \param computeid of \c COMPUTE clause to which we're referring.
  4153. * \return number of columns, else -1 if no such \a computeid.
  4154. * \sa dbadata(), dbadlen(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumcols().
  4155. */
  4156. int
  4157. dbnumalts(DBPROCESS * dbproc, int computeid)
  4158. {
  4159. TDSSOCKET *tds;
  4160. TDSCOMPUTEINFO *info;
  4161. TDS_SMALLINT compute_id;
  4162. int i;
  4163. tdsdump_log(TDS_DBG_FUNC, "dbnumalts(%p, %d)\n", dbproc, computeid);
  4164. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  4165. tds = dbproc->tds_socket;
  4166. compute_id = computeid;
  4167. for (i = 0;; ++i) {
  4168. if (i >= tds->num_comp_info)
  4169. return -1;
  4170. info = tds->comp_info[i];
  4171. if (info->computeid == compute_id)
  4172. break;
  4173. }
  4174. return info->num_cols;
  4175. }
  4176. /**
  4177. * \ingroup dblib_core
  4178. * \brief Get count of \c COMPUTE clauses for a result set.
  4179. *
  4180. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4181. * \return number of compute clauses for the current query, possibly zero.
  4182. * \sa dbnumalts(), dbresults().
  4183. */
  4184. int
  4185. dbnumcompute(DBPROCESS * dbproc)
  4186. {
  4187. TDSSOCKET *tds;
  4188. tdsdump_log(TDS_DBG_FUNC, "dbnumcompute(%p)\n", dbproc);
  4189. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  4190. tds = dbproc->tds_socket;
  4191. return tds->num_comp_info;
  4192. }
  4193. /**
  4194. * \ingroup dblib_core
  4195. * \brief Get \c bylist for a compute row.
  4196. *
  4197. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4198. * \param computeid of \c COMPUTE clause to which we're referring.
  4199. * \param size \em output: size of \c bylist buffer whose address is returned, possibly zero.
  4200. * \return address of \c bylist for \a computeid.
  4201. * \retval NULL no such \a computeid.
  4202. * \remarks Do not free returned pointer.
  4203. * \sa dbadata(), dbadlen(), dbaltlen(), dbalttype(), dbcolname(), dbgetrow(), dbnextrow().
  4204. */
  4205. BYTE *
  4206. dbbylist(DBPROCESS * dbproc, int computeid, int *size)
  4207. {
  4208. TDSSOCKET *tds;
  4209. TDSCOMPUTEINFO *info;
  4210. int i;
  4211. const TDS_SMALLINT byte_flag = -0x8000;
  4212. tdsdump_log(TDS_DBG_FUNC, "dbbylist(%p, %d, %p)\n", dbproc, computeid, size);
  4213. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  4214. tds = dbproc->tds_socket;
  4215. for (i = 0;; ++i) {
  4216. if (i >= tds->num_comp_info) {
  4217. if (size)
  4218. *size = 0;
  4219. return NULL;
  4220. }
  4221. info = tds->comp_info[i];
  4222. if (info->computeid == computeid)
  4223. break;
  4224. }
  4225. if (size)
  4226. *size = info->by_cols;
  4227. /*
  4228. * libtds stores this information using TDS_SMALLINT so we
  4229. * have to convert it. We can do this because libtds just
  4230. * stores these data.
  4231. */
  4232. if (info->by_cols > 0 && info->bycolumns[0] != byte_flag) {
  4233. int n;
  4234. TDS_TINYINT *p = (TDS_TINYINT*) malloc(sizeof(info->bycolumns[0]) + info->by_cols);
  4235. if (!p) {
  4236. dbperror(dbproc, SYBEMEM, errno);
  4237. return NULL;
  4238. }
  4239. for (n = 0; n < info->by_cols; ++n)
  4240. p[sizeof(info->bycolumns[0]) + n] = info->bycolumns[n] > 255 ? 255 : info->bycolumns[n];
  4241. *((TDS_SMALLINT *)p) = byte_flag;
  4242. free(info->bycolumns);
  4243. info->bycolumns = (TDS_SMALLINT *) p;
  4244. }
  4245. return (BYTE *) (&info->bycolumns[1]);
  4246. }
  4247. /** \internal
  4248. * \ingroup dblib_internal
  4249. * \brief Check if \a dbproc is an ex-parrot.
  4250. *
  4251. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4252. * \retval TRUE process has been marked \em dead.
  4253. * \retval FALSE process is OK.
  4254. * \remarks dbdead() does not communicate with the server.
  4255. * Unless a previously db-lib marked \a dbproc \em dead, dbdead() returns \c FALSE.
  4256. * \sa dberrhandle().
  4257. */
  4258. DBBOOL
  4259. dbdead(DBPROCESS * dbproc)
  4260. {
  4261. tdsdump_log(TDS_DBG_FUNC, "dbdead(%p) [%s]\n", dbproc, dbproc? IS_TDSDEAD(dbproc->tds_socket)? "dead":"alive" : "quite dead");
  4262. if( NULL == dbproc )
  4263. return TRUE;
  4264. if (IS_TDSDEAD(dbproc->tds_socket))
  4265. return TRUE;
  4266. else
  4267. return FALSE;
  4268. }
  4269. /** \internal
  4270. * \ingroup dblib_internal
  4271. * \brief default error handler for db-lib (handles library-generated errors)
  4272. *
  4273. * The default error handler doesn't print anything. If you want to see your messages printed,
  4274. * install an error handler. If you think that should be an optional compile- or run-time default,
  4275. * submit a patch. It could be done.
  4276. *
  4277. * \sa DBDEAD(), dberrhandle().
  4278. */
  4279. /* Thus saith Sybase:
  4280. * "If the user does not supply an error handler (or passes a NULL pointer to
  4281. * dberrhandle), DB-Library will exhibit its default error-handling
  4282. * behavior: It will abort the program if the error has made the affected
  4283. * DBPROCESS unusable (the user can call DBDEAD to determine whether
  4284. * or not a DBPROCESS has become unusable). If the error has not made the
  4285. * DBPROCESS unusable, DB-Library will simply return an error code to its caller."
  4286. *
  4287. * It is not the error handler, however, that aborts anything. It is db-lib, cf. dbperror().
  4288. */
  4289. static int
  4290. default_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
  4291. {
  4292. tdsdump_log(TDS_DBG_FUNC, "default_err_handler %p, %d, %d, %d, %p, %p", dbproc, severity, dberr, oserr, dberrstr, oserrstr);
  4293. if (DBDEAD(dbproc) && (!dbproc || !dbproc->msdblib)) {
  4294. return INT_EXIT;
  4295. }
  4296. if (!dbproc || !dbproc->msdblib) { /* i.e. Sybase behavior */
  4297. switch(dberr) {
  4298. case SYBETIME:
  4299. return INT_EXIT;
  4300. default:
  4301. break;
  4302. }
  4303. }
  4304. return INT_CANCEL;
  4305. }
  4306. /**
  4307. * \ingroup dblib_core
  4308. * \brief Set an error handler, for messages from db-lib.
  4309. *
  4310. * \param handler pointer to callback function that will handle errors.
  4311. * Pass NULL to restore the default handler.
  4312. * \return address of prior handler, or NULL if none was previously installed.
  4313. * \sa DBDEAD(), dbmsghandle().
  4314. */
  4315. EHANDLEFUNC
  4316. dberrhandle(EHANDLEFUNC handler)
  4317. {
  4318. EHANDLEFUNC old_handler = _dblib_err_handler;
  4319. tdsdump_log(TDS_DBG_FUNC, "dberrhandle(%p)\n", handler);
  4320. _dblib_err_handler = handler? handler : default_err_handler;
  4321. return (old_handler == default_err_handler)? NULL : old_handler;
  4322. }
  4323. /**
  4324. * \ingroup dblib_core
  4325. * \brief Set a message handler, for messages from the server.
  4326. *
  4327. * \param handler address of the function that will process the messages.
  4328. * \sa DBDEAD(), dberrhandle().
  4329. */
  4330. MHANDLEFUNC
  4331. dbmsghandle(MHANDLEFUNC handler)
  4332. {
  4333. MHANDLEFUNC retFun = _dblib_msg_handler;
  4334. tdsdump_log(TDS_DBG_FUNC, "dbmsghandle(%p)\n", handler);
  4335. _dblib_msg_handler = handler;
  4336. return retFun;
  4337. }
  4338. #if defined(DBLIB_UNIMPLEMENTED)
  4339. /**
  4340. * \ingroup dblib_money
  4341. * \brief Add two DBMONEY values.
  4342. *
  4343. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4344. * \param m1 first operand.
  4345. * \param m2 other operand.
  4346. * \param sum \em output: result of computation.
  4347. * \retval SUCCEED Always.
  4348. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4349. * \todo Unimplemented.
  4350. */
  4351. RETCODE
  4352. dbmnyadd(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2, DBMONEY * sum)
  4353. {
  4354. tdsdump_log(TDS_DBG_FUNC, "dbmnyadd(%p, %p, %p, %p)\n", dbproc, m1, m2, sum);
  4355. CHECK_CONN(FAIL);
  4356. CHECK_NULP(m1, "dbmnyadd", 2, FAIL);
  4357. CHECK_NULP(m2, "dbmnyadd", 3, FAIL);
  4358. CHECK_NULP(sum, "dbmnyadd", 4, FAIL);
  4359. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnyadd()\n");
  4360. return SUCCEED;
  4361. }
  4362. /**
  4363. * \ingroup dblib_money
  4364. * \brief Subtract two DBMONEY values.
  4365. *
  4366. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4367. * \param m1 first operand.
  4368. * \param m2 other operand, subtracted from \a m1.
  4369. * \param difference \em output: result of computation.
  4370. * \retval SUCCEED Always.
  4371. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4372. * \todo Unimplemented.
  4373. */
  4374. RETCODE
  4375. dbmnysub(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2, DBMONEY * difference)
  4376. {
  4377. tdsdump_log(TDS_DBG_FUNC, "dbmnysub(%p, %p, %p, %p)\n", dbproc, m1, m2, difference);
  4378. CHECK_CONN(FAIL);
  4379. CHECK_NULP(m1, "dbmnysub", 2, FAIL);
  4380. CHECK_NULP(m2, "dbmnysub", 3, FAIL);
  4381. CHECK_NULP(difference, "dbmnysub", 4, FAIL);
  4382. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnysyb()\n");
  4383. return SUCCEED;
  4384. }
  4385. /**
  4386. * \ingroup dblib_money
  4387. * \brief Multiply two DBMONEY values.
  4388. *
  4389. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4390. * \param m1 first operand.
  4391. * \param m2 other operand.
  4392. * \param prod \em output: result of computation.
  4393. * \retval SUCCEED Always.
  4394. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4395. * \todo Unimplemented.
  4396. */
  4397. RETCODE
  4398. dbmnymul(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2, DBMONEY * prod)
  4399. {
  4400. tdsdump_log(TDS_DBG_FUNC, "dbmnymul(%p, %p, %p, %p)\n", dbproc, m1, m2, prod);
  4401. CHECK_CONN(FAIL);
  4402. CHECK_NULP(m1, "dbmnymul", 2, FAIL);
  4403. CHECK_NULP(m2, "dbmnymul", 3, FAIL);
  4404. CHECK_NULP(prod, "dbmnymul", 4, FAIL);
  4405. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnymul()\n");
  4406. return SUCCEED;
  4407. }
  4408. /**
  4409. * \ingroup dblib_money
  4410. * \brief Divide two DBMONEY values.
  4411. *
  4412. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4413. * \param m1 dividend.
  4414. * \param m2 divisor.
  4415. * \param quotient \em output: result of computation.
  4416. * \retval SUCCEED Always.
  4417. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4418. * \todo Unimplemented.
  4419. */
  4420. RETCODE
  4421. dbmnydivide(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2, DBMONEY * quotient)
  4422. {
  4423. tdsdump_log(TDS_DBG_FUNC, "dbmnydivide(%p, %p, %p, %p)\n", dbproc, m1, m2, quotient);
  4424. CHECK_CONN(FAIL);
  4425. CHECK_NULP(m1, "dbmnydivide", 2, FAIL);
  4426. CHECK_NULP(m2, "dbmnydivide", 3, FAIL);
  4427. CHECK_NULP(quotient, "dbmnydivide", 4, FAIL);
  4428. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnydivide()\n");
  4429. return SUCCEED;
  4430. }
  4431. #endif
  4432. /**
  4433. * \ingroup dblib_money
  4434. * \brief Compare two DBMONEY values.
  4435. *
  4436. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4437. * \param m1 some money.
  4438. * \param m2 some other money.
  4439. * \retval 0 m1 == m2.
  4440. * \retval -1 m1 < m2.
  4441. * \retval 1 m1 > m2.
  4442. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4443. */
  4444. int
  4445. dbmnycmp(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2)
  4446. {
  4447. tdsdump_log(TDS_DBG_FUNC, "dbmnycmp(%p, %p, %p)\n", dbproc, m1, m2);
  4448. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  4449. CHECK_NULP(m1, "dbmnycmp", 2, 0);
  4450. CHECK_NULP(m2, "dbmnycmp", 3, 0);
  4451. if (m1->mnyhigh < m2->mnyhigh) {
  4452. return -1;
  4453. }
  4454. if (m1->mnyhigh > m2->mnyhigh) {
  4455. return 1;
  4456. }
  4457. if (m1->mnylow < m2->mnylow) {
  4458. return -1;
  4459. }
  4460. if (m1->mnylow > m2->mnylow) {
  4461. return 1;
  4462. }
  4463. return 0;
  4464. }
  4465. #if defined(DBLIB_UNIMPLEMENTED)
  4466. /**
  4467. * \ingroup dblib_money
  4468. * \brief Multiply a DBMONEY value by a positive integer, and add an amount.
  4469. *
  4470. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4471. * \param amount starting amount of money, also holds output.
  4472. * \param multiplier amount to multiply \a amount by.
  4473. * \param addend amount to add to \a amount, after multiplying by \a multiplier.
  4474. * \retval SUCCEED Always.
  4475. * \remarks This function is goofy.
  4476. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4477. * \todo Unimplemented.
  4478. */
  4479. RETCODE
  4480. dbmnyscale(DBPROCESS * dbproc, DBMONEY * amount, int multiplier, int addend)
  4481. {
  4482. tdsdump_log(TDS_DBG_FUNC, "dbmnyscale(%p, %p, %d, %d)\n", dbproc, amount, multiplier, addend);
  4483. CHECK_CONN(FAIL);
  4484. CHECK_NULP(amount, "dbmnyscale", 2, FAIL);
  4485. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnyscale()\n");
  4486. return SUCCEED;
  4487. }
  4488. #endif
  4489. /**
  4490. * \ingroup dblib_money
  4491. * \brief Set a DBMONEY value to zero.
  4492. *
  4493. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4494. * \param dest address of a DBMONEY structure.
  4495. * \retval SUCCEED unless \a amount is NULL.
  4496. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4497. */
  4498. RETCODE
  4499. dbmnyzero(DBPROCESS * dbproc, DBMONEY * dest)
  4500. {
  4501. tdsdump_log(TDS_DBG_FUNC, "dbmnyzero(%p, %p)\n", dbproc, dest);
  4502. CHECK_CONN(FAIL);
  4503. CHECK_NULP(dest, "dbmnyzero", 2, FAIL);
  4504. dest->mnylow = 0;
  4505. dest->mnyhigh = 0;
  4506. return SUCCEED;
  4507. }
  4508. /**
  4509. * \ingroup dblib_money
  4510. * \brief Get maximum positive DBMONEY value supported.
  4511. *
  4512. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4513. * \param amount address of a DBMONEY structure.
  4514. * \retval SUCCEED Always.
  4515. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4516. */
  4517. RETCODE
  4518. dbmnymaxpos(DBPROCESS * dbproc, DBMONEY * amount)
  4519. {
  4520. tdsdump_log(TDS_DBG_FUNC, "dbmnymaxpos(%p, %p)\n", dbproc, amount);
  4521. CHECK_CONN(FAIL);
  4522. CHECK_NULP(amount, "dbmnymaxpos", 2, FAIL);
  4523. amount->mnylow = 0xFFFFFFFFlu;
  4524. amount->mnyhigh = 0x7FFFFFFFl;
  4525. return SUCCEED;
  4526. }
  4527. /**
  4528. * \ingroup dblib_money
  4529. * \brief Get maximum negative DBMONEY value supported.
  4530. *
  4531. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4532. * \param amount address of a DBMONEY structure.
  4533. * \retval SUCCEED Always.
  4534. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4535. */
  4536. RETCODE
  4537. dbmnymaxneg(DBPROCESS * dbproc, DBMONEY * amount)
  4538. {
  4539. tdsdump_log(TDS_DBG_FUNC, "dbmnymaxneg(%p, %p)\n", dbproc, amount);
  4540. CHECK_CONN(FAIL);
  4541. CHECK_NULP(amount, "dbmnymaxneg", 2, FAIL);
  4542. amount->mnylow = 0;
  4543. amount->mnyhigh = -0x80000000l;
  4544. return SUCCEED;
  4545. }
  4546. #if defined(DBLIB_UNIMPLEMENTED)
  4547. /**
  4548. * \ingroup dblib_money
  4549. * \brief Get the least significant digit of a DBMONEY value, represented as a character.
  4550. *
  4551. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4552. * \param mnyptr \em input the money amount, \em and \em output: \a mnyptr divided by 10.
  4553. * \param digit the character value (between '0' and '9') of the rightmost digit in \a mnyptr.
  4554. * \param zero \em output: \c TRUE if \a mnyptr is zero on output, else \c FALSE.
  4555. * \retval SUCCEED Always.
  4556. * \sa dbconvert(), dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4557. * \remarks Unimplemented and likely to remain so. We'd be amused to learn anyone wants this function.
  4558. * \todo Unimplemented.
  4559. */
  4560. RETCODE
  4561. dbmnyndigit(DBPROCESS * dbproc, DBMONEY * mnyptr, DBCHAR * digit, DBBOOL * zero)
  4562. {
  4563. tdsdump_log(TDS_DBG_FUNC, "dbmnyndigit(%p, %p, %s, %p)\n", dbproc, mnyptr, digit, zero);
  4564. CHECK_CONN(FAIL);
  4565. CHECK_NULP(mnyptr, "dbmnyndigit", 2, FAIL);
  4566. CHECK_NULP(digit, "dbmnyndigit", 3, FAIL);
  4567. CHECK_NULP(zero, "dbmnyndigit", 4, FAIL);
  4568. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnyndigit()\n");
  4569. return SUCCEED;
  4570. }
  4571. /**
  4572. * \ingroup dblib_money
  4573. * \brief Prepare a DBMONEY value for use with dbmnyndigit().
  4574. *
  4575. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4576. * \param amount address of a DBMONEY structure.
  4577. * \param trim number of digits to trim from \a amount.
  4578. * \param negative \em output: \c TRUE if \a amount < 0.
  4579. * \retval SUCCEED Always.
  4580. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4581. * \todo Unimplemented.
  4582. */
  4583. RETCODE
  4584. dbmnyinit(DBPROCESS * dbproc, DBMONEY * amount, int trim, DBBOOL * negative)
  4585. {
  4586. tdsdump_log(TDS_DBG_FUNC, "dbmnyinit(%p, %p, %d, %p)\n", dbproc, amount, trim, negative);
  4587. CHECK_CONN(FAIL);
  4588. CHECK_NULP(amount, "dbmnyinit", 2, FAIL);
  4589. CHECK_NULP(negative, "dbmnyinit", 4, FAIL);
  4590. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnyinit()\n");
  4591. return SUCCEED;
  4592. }
  4593. /**
  4594. * \ingroup dblib_money
  4595. * \brief Divide a DBMONEY value by a positive integer.
  4596. *
  4597. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4598. * \param amount address of a DBMONEY structure.
  4599. * \param divisor of \a amount.
  4600. * \param remainder \em output: modulo of integer division.
  4601. * \retval SUCCEED Always.
  4602. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4603. * \todo Unimplemented.
  4604. */
  4605. RETCODE
  4606. dbmnydown(DBPROCESS * dbproc, DBMONEY * amount, int divisor, int *remainder)
  4607. {
  4608. tdsdump_log(TDS_DBG_FUNC, "dbmnydown(%p, %p, %d, %p)\n", dbproc, amount, divisor, remainder);
  4609. CHECK_CONN(FAIL);
  4610. CHECK_NULP(amount, "dbmnydown", 2, FAIL);
  4611. CHECK_NULP(remainder, "dbmnydown", 4, FAIL);
  4612. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnydown()\n");
  4613. return SUCCEED;
  4614. }
  4615. #endif
  4616. /**
  4617. * \ingroup dblib_money
  4618. * \brief Add $0.0001 to a DBMONEY value.
  4619. *
  4620. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4621. * \param amount address of a DBMONEY structure.
  4622. * \retval SUCCEED or FAIL if overflow or amount NULL.
  4623. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4624. */
  4625. RETCODE
  4626. dbmnyinc(DBPROCESS * dbproc, DBMONEY * amount)
  4627. {
  4628. tdsdump_log(TDS_DBG_FUNC, "dbmnyinc(%p, %p)\n", dbproc, amount);
  4629. CHECK_CONN(FAIL);
  4630. CHECK_NULP(amount, "dbmnyinc", 2, FAIL);
  4631. if (amount->mnylow != 0xFFFFFFFFlu) {
  4632. ++amount->mnylow;
  4633. return SUCCEED;
  4634. }
  4635. if (amount->mnyhigh == 0x7FFFFFFFl)
  4636. return FAIL;
  4637. amount->mnylow = 0;
  4638. ++amount->mnyhigh;
  4639. return SUCCEED;
  4640. }
  4641. /**
  4642. * \ingroup dblib_money
  4643. * \brief Subtract $0.0001 from a DBMONEY value.
  4644. *
  4645. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4646. * \param amount address of a DBMONEY structure.
  4647. * \retval SUCCEED or FAIL if overflow or amount NULL.
  4648. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4649. */
  4650. RETCODE
  4651. dbmnydec(DBPROCESS * dbproc, DBMONEY * amount)
  4652. {
  4653. tdsdump_log(TDS_DBG_FUNC, "dbmnydec(%p, %p)\n", dbproc, amount);
  4654. CHECK_CONN(FAIL);
  4655. CHECK_NULP(amount, "dbmnydec", 2, FAIL);
  4656. if (amount->mnylow != 0) {
  4657. --amount->mnylow;
  4658. return SUCCEED;
  4659. }
  4660. if (amount->mnyhigh == -0x80000000l)
  4661. return FAIL;
  4662. amount->mnylow = 0xFFFFFFFFlu;
  4663. --amount->mnyhigh;
  4664. return SUCCEED;
  4665. }
  4666. /**
  4667. * \ingroup dblib_money
  4668. * \brief Negate a DBMONEY value.
  4669. *
  4670. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4671. * \param src address of a DBMONEY structure.
  4672. * \param dest \em output: result of negation.
  4673. * \retval SUCCEED or FAIL if overflow or src/dest NULL.
  4674. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4675. */
  4676. RETCODE
  4677. dbmnyminus(DBPROCESS * dbproc, DBMONEY * src, DBMONEY * dest)
  4678. {
  4679. tdsdump_log(TDS_DBG_FUNC, "dbmnyminus(%p, %p, %p)\n", dbproc, src, dest);
  4680. CHECK_CONN(FAIL);
  4681. CHECK_NULP(src, "dbmnyminus", 2, FAIL);
  4682. CHECK_NULP(dest, "dbmnyminus", 3, FAIL);
  4683. if (src->mnyhigh == -0x80000000l && src->mnylow == 0)
  4684. return FAIL;
  4685. dest->mnyhigh = -src->mnyhigh;
  4686. dest->mnylow = (~src->mnylow) + 1u;
  4687. return SUCCEED;
  4688. }
  4689. /**
  4690. * \ingroup dblib_money
  4691. * \brief Negate a DBMONEY4 value.
  4692. *
  4693. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4694. * \param src address of a DBMONEY4 structure.
  4695. * \param dest \em output: result of negation.
  4696. * \retval SUCCEED usually.
  4697. * \retval FAIL on overflow.
  4698. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4699. */
  4700. RETCODE
  4701. dbmny4minus(DBPROCESS * dbproc, DBMONEY4 * src, DBMONEY4 * dest)
  4702. {
  4703. DBMONEY4 zero;
  4704. tdsdump_log(TDS_DBG_FUNC, "dbmny4minus(%p, %p, %p)\n", dbproc, src, dest);
  4705. CHECK_CONN(FAIL);
  4706. CHECK_NULP(src, "dbmny4minus", 2, FAIL);
  4707. CHECK_NULP(dest, "dbmny4minus", 3, FAIL);
  4708. dbmny4zero(dbproc, &zero);
  4709. return (dbmny4sub(dbproc, &zero, src, dest));
  4710. }
  4711. /**
  4712. * \ingroup dblib_money
  4713. * \brief Zero a DBMONEY4 value.
  4714. *
  4715. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4716. * \param dest address of a DBMONEY structure.
  4717. * \retval SUCCEED usually.
  4718. * \retval FAIL \a dest is NULL.
  4719. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4720. */
  4721. RETCODE
  4722. dbmny4zero(DBPROCESS * dbproc, DBMONEY4 * dest)
  4723. {
  4724. tdsdump_log(TDS_DBG_FUNC, "dbmny4zero(%p, %p)\n", dbproc, dest);
  4725. CHECK_CONN(FAIL);
  4726. CHECK_NULP(dest, "dbmny4zero", 2, FAIL);
  4727. dest->mny4 = 0;
  4728. return SUCCEED;
  4729. }
  4730. /**
  4731. * \ingroup dblib_money
  4732. * \brief Add two DBMONEY4 values.
  4733. *
  4734. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4735. * \param m1 first operand.
  4736. * \param m2 other operand.
  4737. * \param sum \em output: result of computation.
  4738. * \retval SUCCEED usually.
  4739. * \retval FAIL on overflow.
  4740. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4741. */
  4742. RETCODE
  4743. dbmny4add(DBPROCESS * dbproc, DBMONEY4 * m1, DBMONEY4 * m2, DBMONEY4 * sum)
  4744. {
  4745. tdsdump_log(TDS_DBG_FUNC, "dbmny4add(%p, %p, %p, %p)\n", dbproc, m1, m2, sum);
  4746. CHECK_CONN(FAIL);
  4747. CHECK_NULP(m1, "dbmny4add", 2, FAIL);
  4748. CHECK_NULP(m2, "dbmny4add", 3, FAIL);
  4749. CHECK_NULP(sum, "dbmny4add", 4, FAIL);
  4750. sum->mny4 = m1->mny4 + m2->mny4;
  4751. if (((m1->mny4 < 0) && (m2->mny4 < 0) && (sum->mny4 >= 0))
  4752. || ((m1->mny4 > 0) && (m2->mny4 > 0) && (sum->mny4 <= 0))) {
  4753. /* overflow */
  4754. sum->mny4 = 0;
  4755. return FAIL;
  4756. }
  4757. return SUCCEED;
  4758. }
  4759. /**
  4760. * \ingroup dblib_money
  4761. * \brief Subtract two DBMONEY4 values.
  4762. *
  4763. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4764. * \param m1 first operand.
  4765. * \param m2 other operand, subtracted from \a m1.
  4766. * \param diff \em output: result of computation.
  4767. * \retval SUCCEED usually.
  4768. * \retval FAIL on overflow.
  4769. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4770. */
  4771. RETCODE
  4772. dbmny4sub(DBPROCESS * dbproc, DBMONEY4 * m1, DBMONEY4 * m2, DBMONEY4 * diff)
  4773. {
  4774. tdsdump_log(TDS_DBG_FUNC, "dbmny4sub(%p, %p, %p, %p)\n", dbproc, m1, m2, diff);
  4775. CHECK_CONN(FAIL);
  4776. CHECK_NULP(m1, "dbmny4sub", 2, FAIL);
  4777. CHECK_NULP(m2, "dbmny4sub", 3, FAIL);
  4778. CHECK_NULP(diff, "dbmny4sub", 4, FAIL);
  4779. diff->mny4 = m1->mny4 - m2->mny4;
  4780. if (((m1->mny4 <= 0) && (m2->mny4 > 0) && (diff->mny4 > 0))
  4781. || ((m1->mny4 >= 0) && (m2->mny4 < 0) && (diff->mny4 < 0))) {
  4782. /* overflow */
  4783. diff->mny4 = 0;
  4784. return FAIL;
  4785. }
  4786. return SUCCEED;
  4787. }
  4788. #if defined(DBLIB_UNIMPLEMENTED)
  4789. /**
  4790. * \ingroup dblib_money
  4791. * \brief Multiply two DBMONEY4 values.
  4792. *
  4793. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4794. * \param m1 first operand.
  4795. * \param m2 other operand.
  4796. * \param prod \em output: result of computation.
  4797. * \retval SUCCEED usually.
  4798. * \retval FAIL a parameter is NULL.
  4799. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4800. * \todo Unimplemented.
  4801. */
  4802. RETCODE
  4803. dbmny4mul(DBPROCESS * dbproc, DBMONEY4 * m1, DBMONEY4 * m2, DBMONEY4 * prod)
  4804. {
  4805. tdsdump_log(TDS_DBG_FUNC, "dbmny4mul(%p, %p, %p, %p)\n", dbproc, m1, m2, prod);
  4806. CHECK_CONN(FAIL);
  4807. CHECK_NULP(m1, "dbmny4mul", 2, FAIL);
  4808. CHECK_NULP(m2, "dbmny4mul", 3, FAIL);
  4809. CHECK_NULP(prod, "dbmny4mul", 4, FAIL);
  4810. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmny4mul()\n");
  4811. return FAIL;
  4812. }
  4813. /**
  4814. * \ingroup dblib_money
  4815. * \brief Divide two DBMONEY4 values.
  4816. *
  4817. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4818. * \param m1 dividend.
  4819. * \param m2 divisor.
  4820. * \param quotient \em output: result of computation.
  4821. * \retval SUCCEED usually.
  4822. * \retval FAIL a parameter is NULL.
  4823. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4824. * \todo Unimplemented.
  4825. */
  4826. RETCODE
  4827. dbmny4divide(DBPROCESS * dbproc, DBMONEY4 * m1, DBMONEY4 * m2, DBMONEY4 * quotient)
  4828. {
  4829. tdsdump_log(TDS_DBG_FUNC, "dbmny4divide(%p, %p, %p, %p)\n", dbproc, m1, m2, quotient);
  4830. CHECK_CONN(FAIL);
  4831. CHECK_NULP(m1, "dbmny4divide", 2, FAIL);
  4832. CHECK_NULP(m2, "dbmny4divide", 3, FAIL);
  4833. CHECK_NULP(quotient, "dbmny4divide", 4, FAIL);
  4834. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmny4divide()\n");
  4835. return FAIL;
  4836. }
  4837. #endif
  4838. /**
  4839. * \ingroup dblib_money
  4840. * \brief Compare two DBMONEY4 values.
  4841. *
  4842. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4843. * \param m1 some money.
  4844. * \param m2 some other money.
  4845. * \retval 0 m1 == m2.
  4846. * \retval -1 m1 < m2.
  4847. * \retval 1 m1 > m2.
  4848. * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
  4849. */
  4850. int
  4851. dbmny4cmp(DBPROCESS * dbproc, DBMONEY4 * m1, DBMONEY4 * m2)
  4852. {
  4853. tdsdump_log(TDS_DBG_FUNC, "dbmny4cmp(%p, %p, %p)\n", dbproc, m1, m2);
  4854. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  4855. CHECK_NULP(m1, "dbmny4cmp", 2, 0);
  4856. CHECK_NULP(m2, "dbmny4cmp", 3, 0);
  4857. if (m1->mny4 < m2->mny4) {
  4858. return -1;
  4859. }
  4860. if (m1->mny4 > m2->mny4) {
  4861. return 1;
  4862. }
  4863. return 0;
  4864. }
  4865. /**
  4866. * \ingroup dblib_money
  4867. * \brief Copy a DBMONEY4 value.
  4868. *
  4869. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4870. * \param src address of a DBMONEY4 structure.
  4871. * \param dest \em output: new money.
  4872. * \retval SUCCEED or FAIL if src/dest NULL.
  4873. * \sa dbmnycopy(), dbmnyminus(), dbmny4minus().
  4874. */
  4875. RETCODE
  4876. dbmny4copy(DBPROCESS * dbproc, DBMONEY4 * src, DBMONEY4 * dest)
  4877. {
  4878. tdsdump_log(TDS_DBG_FUNC, "dbmny4copy(%p, %p, %p)\n", dbproc, src, dest);
  4879. CHECK_CONN(FAIL);
  4880. CHECK_NULP(src, "dbmny4copy", 2, FAIL);
  4881. CHECK_NULP(dest, "dbmny4copy", 3, FAIL);
  4882. dest->mny4 = src->mny4;
  4883. return SUCCEED;
  4884. }
  4885. /**
  4886. * \ingroup dblib_datetime
  4887. * \brief Compare DBDATETIME values, similar to strcmp(3).
  4888. *
  4889. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4890. * \param d1 a \c DBDATETIME structure address
  4891. * \param d2 another \c DBDATETIME structure address
  4892. * \retval 0 d1 = d2.
  4893. * \retval -1 d1 < d2.
  4894. * \retval 1 d1 > d2.
  4895. * \sa dbdate4cmp(), dbmnycmp(), dbmny4cmp().
  4896. */
  4897. int
  4898. dbdatecmp(DBPROCESS * dbproc, DBDATETIME * d1, DBDATETIME * d2)
  4899. {
  4900. tdsdump_log(TDS_DBG_FUNC, "dbdatecmp(%p, %p, %p)\n", dbproc, d1, d2);
  4901. CHECK_CONN(FAIL);
  4902. CHECK_NULP(d1, "dbdatecmp", 2, 0);
  4903. CHECK_NULP(d2, "dbdatecmp", 3, 0);
  4904. if (d1->dtdays == d2->dtdays) {
  4905. if (d1->dttime == d2->dttime)
  4906. return 0;
  4907. return d1->dttime > d2->dttime ? 1 : -1;
  4908. }
  4909. /* date 1 is before 1900 */
  4910. if (d1->dtdays > 2958463) {
  4911. if (d2->dtdays > 2958463) /* date 2 is before 1900 */
  4912. return d1->dtdays > d2->dtdays ? 1 : -1;
  4913. return -1;
  4914. }
  4915. /* date 1 is after 1900 */
  4916. if (d2->dtdays < 2958463) /* date 2 is after 1900 */
  4917. return d1->dtdays > d2->dtdays ? 1 : -1;
  4918. return 1;
  4919. }
  4920. /**
  4921. * \ingroup dblib_core
  4922. * \brief Break a DBDATETIME value into useful pieces.
  4923. *
  4924. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  4925. * \param di \em output: structure to contain the exploded parts of \a datetime.
  4926. * \param datetime \em input: \c DBDATETIME to be converted.
  4927. * \retval SUCCEED always.
  4928. * \remarks The members of \a di have different names, depending on whether \c --with-msdblib was configured.
  4929. *
  4930. * If DBPROCESS is NULL, dbdatecrack() uses the compiled in default
  4931. * value of MSDBLIB as of when libsybdb was compiled, irrespective of its value when the
  4932. * application is compiled. This can lead to incorrect results because Sybase and Microsoft use different
  4933. * ranges -- [0,11] vs. [1,12] -- for the month.
  4934. *
  4935. * \sa dbconvert(), dbdata(), dbdatechar(), dbdatename(), dbdatepart(), tdsdbopen().
  4936. */
  4937. RETCODE
  4938. dbdatecrack(DBPROCESS * dbproc, DBDATEREC * output, DBDATETIME * datetime)
  4939. {
  4940. #if MSDBLIB
  4941. const int msdblib = 1;
  4942. #else
  4943. const int msdblib = 0;
  4944. #endif
  4945. TDSDATEREC dr;
  4946. struct tds_sybase_dbdaterec *di = (struct tds_sybase_dbdaterec*) output;
  4947. tdsdump_log(TDS_DBG_FUNC, "dbdatecrack(%p, %p, %p)\n", dbproc, output, datetime);
  4948. CHECK_NULP(output, "dbdatecrack", 2, FAIL);
  4949. CHECK_PARAMETER(datetime, SYBENDTP, FAIL);
  4950. tds_datecrack(SYBDATETIME, datetime, &dr);
  4951. di->dateyear = dr.year;
  4952. di->quarter = dr.quarter;
  4953. di->datemonth = dr.month;
  4954. di->datedmonth = dr.day;
  4955. di->datedyear = dr.dayofyear;
  4956. di->datedweek = dr.weekday;
  4957. di->datehour = dr.hour;
  4958. di->dateminute = dr.minute;
  4959. di->datesecond = dr.second;
  4960. di->datemsecond = dr.decimicrosecond / 10000u;
  4961. /* Revert to compiled-in default if dbproc can't be used to find the runtime override. */
  4962. if (dbproc ? dbproc->msdblib : msdblib) {
  4963. ++di->quarter;
  4964. ++di->datemonth;
  4965. ++di->datedweek;
  4966. }
  4967. return SUCCEED;
  4968. }
  4969. #if defined(DBLIB_UNIMPLEMENTED)
  4970. /**
  4971. * \ingroup dblib_core
  4972. * \brief Clear remote passwords from the LOGINREC structure.
  4973. *
  4974. * \param login structure to pass to dbopen().
  4975. * \sa dblogin(), dbopen(), dbrpwset(), DBSETLAPP(), DBSETLHOST(), DBSETLPWD(), DBSETLUSER().
  4976. * \remarks Useful for remote stored procedure calls, but not in high demand from FreeTDS.
  4977. * \todo Unimplemented.
  4978. */
  4979. void
  4980. dbrpwclr(LOGINREC * login)
  4981. {
  4982. tdsdump_log(TDS_DBG_FUNC, "dbrpwclr(%p)\n", login);
  4983. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbrpwclr()\n");
  4984. }
  4985. /**
  4986. * \ingroup dblib_core
  4987. * \brief Add a remote password to the LOGINREC structure.
  4988. *
  4989. * \param login structure to pass to dbopen().
  4990. * \param srvname server for which \a password should be used.
  4991. * \param password you guessed it, let's hope no else does.
  4992. * \param pwlen count of \a password, in bytes.
  4993. * \remarks Useful for remote stored procedure calls, but not in high demand from FreeTDS.
  4994. * \sa dblogin(), dbopen(), dbrpwclr(), DBSETLAPP(), DBSETLHOST(), DBSETLPWD(), DBSETLUSER().
  4995. * \todo Unimplemented.
  4996. */
  4997. RETCODE
  4998. dbrpwset(LOGINREC * login, char *srvname, char *password, int pwlen)
  4999. {
  5000. tdsdump_log(TDS_DBG_FUNC, "dbrpwset(%p, %s, %s, %d)\n", login, srvname, password, pwlen);
  5001. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbrpwset()\n");
  5002. return SUCCEED;
  5003. }
  5004. #endif
  5005. /**
  5006. * \ingroup dblib_core
  5007. * \brief Get server process ID for a \c DBPROCESS.
  5008. *
  5009. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5010. * \return \em "spid", the server's process ID.
  5011. * \sa dbopen().
  5012. */
  5013. int
  5014. dbspid(DBPROCESS * dbproc)
  5015. {
  5016. TDSSOCKET *tds;
  5017. tdsdump_log(TDS_DBG_FUNC, "dbspid(%p)\n", dbproc);
  5018. CHECK_PARAMETER(dbproc, SYBESPID, -1);
  5019. tds = dbproc->tds_socket;
  5020. if (IS_TDSDEAD(tds))
  5021. return -1;
  5022. return tds->spid;
  5023. }
  5024. /**
  5025. * \ingroup dblib_core
  5026. * \brief Associate client-allocated (and defined) data with a \c DBPROCESS.
  5027. *
  5028. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5029. * \param ptr address of client-defined data.
  5030. * \remarks \a ptr is the location of user data that \c db-lib will associate with \a dbproc.
  5031. * The client allocates the buffer addressed by \a ptr. \c db-lib never examines or uses the information;
  5032. * it just stashes the pointer for later retrieval by the application with \c dbgetuserdata().
  5033. * \sa dbgetuserdata().
  5034. */
  5035. void
  5036. dbsetuserdata(DBPROCESS * dbproc, BYTE * ptr)
  5037. {
  5038. tdsdump_log(TDS_DBG_FUNC, "dbsetuserdata(%p, %p)\n", dbproc, ptr);
  5039. CHECK_PARAMETER(dbproc, SYBENULL, );
  5040. dbproc->user_data = ptr;
  5041. }
  5042. /**
  5043. * \ingroup dblib_core
  5044. * \brief Get address of user-allocated data from a \c DBPROCESS.
  5045. *
  5046. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5047. * \return address of user-defined data that \c db-lib associated with \a dbproc when the client called dbsetuserdata().
  5048. * \retval undefined (probably \c NULL) dbsetuserdata() was not previously called.
  5049. * \sa dbsetuserdata().
  5050. */
  5051. BYTE *
  5052. dbgetuserdata(DBPROCESS * dbproc)
  5053. {
  5054. tdsdump_log(TDS_DBG_FUNC, "dbgetuserdata(%p)\n", dbproc);
  5055. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5056. return dbproc->user_data;
  5057. }
  5058. /**
  5059. * \ingroup dblib_core
  5060. * \brief Specify a db-lib version level.
  5061. *
  5062. * \param version anything, really.
  5063. * \retval SUCCEED Always.
  5064. * \remarks No effect on behavior of \c db-lib in \c FreeTDS.
  5065. * \sa
  5066. */
  5067. RETCODE
  5068. dbsetversion(DBINT version)
  5069. {
  5070. tdsdump_log(TDS_DBG_FUNC, "dbsetversion(%d)\n", version);
  5071. switch (version ) {
  5072. case DBVERSION_42:
  5073. case DBVERSION_46:
  5074. case DBVERSION_100:
  5075. case DBVERSION_70:
  5076. case DBVERSION_71:
  5077. case DBVERSION_72:
  5078. case DBVERSION_73:
  5079. g_dblib_version = version;
  5080. return SUCCEED;
  5081. default:
  5082. break;
  5083. }
  5084. dbperror(NULL, SYBEIVERS, 0);
  5085. return FAIL;
  5086. }
  5087. /**
  5088. * \ingroup dblib_money
  5089. * \brief Copy a DBMONEY value.
  5090. *
  5091. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5092. * \param src address of a DBMONEY structure.
  5093. * \param dest \em output: new money.
  5094. * \retval SUCCEED always, unless \a src or \a dest is \c NULL.
  5095. * \sa
  5096. */
  5097. RETCODE
  5098. dbmnycopy(DBPROCESS * dbproc, DBMONEY * src, DBMONEY * dest)
  5099. {
  5100. tdsdump_log(TDS_DBG_FUNC, "dbmnycopy(%p, %p, %p)\n", dbproc, src, dest);
  5101. CHECK_CONN(FAIL);
  5102. CHECK_NULP(src, "dbmnycopy", 2, FAIL);
  5103. CHECK_NULP(dest, "dbmnycopy", 3, FAIL);
  5104. dest->mnylow = src->mnylow;
  5105. dest->mnyhigh = src->mnyhigh;
  5106. return SUCCEED;
  5107. }
  5108. /**
  5109. * \ingroup dblib_core
  5110. * \brief Cancel the query currently being retrieved, discarding all pending rows.
  5111. *
  5112. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5113. * \sa
  5114. */
  5115. RETCODE
  5116. dbcanquery(DBPROCESS * dbproc)
  5117. {
  5118. TDSRET rc;
  5119. TDS_INT result_type;
  5120. tdsdump_log(TDS_DBG_FUNC, "dbcanquery(%p)\n", dbproc);
  5121. CHECK_CONN(FAIL);
  5122. if (IS_TDSDEAD(dbproc->tds_socket))
  5123. return FAIL;
  5124. /* Just throw away all pending rows from the last query */
  5125. rc = tds_process_tokens(dbproc->tds_socket, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE);
  5126. if (TDS_FAILED(rc))
  5127. return FAIL;
  5128. return SUCCEED;
  5129. }
  5130. /**
  5131. * \ingroup dblib_core
  5132. * \brief Erase the command buffer, in case \c DBNOAUTOFREE was set with dbsetopt().
  5133. *
  5134. *
  5135. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5136. * \sa dbcmd(), dbfcmd(), dbgetchar(), dbsqlexec(), dbsqlsend(), dbsetopt(), dbstrcpy(), dbstrlen().
  5137. */
  5138. void
  5139. dbfreebuf(DBPROCESS * dbproc)
  5140. {
  5141. tdsdump_log(TDS_DBG_FUNC, "dbfreebuf(%p)\n", dbproc);
  5142. CHECK_PARAMETER(dbproc, SYBENULL, );
  5143. if (dbproc->dbbuf)
  5144. TDS_ZERO_FREE(dbproc->dbbuf);
  5145. dbproc->dbbufsz = 0;
  5146. }
  5147. /**
  5148. * \ingroup dblib_core
  5149. * \brief Reset an option.
  5150. *
  5151. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5152. * \param option to be turned off.
  5153. * \param param clearing some options requires a parameter, believe it or not.
  5154. * \retval SUCCEED \a option and \a parameter seem sane.
  5155. * \retval FAIL no such \a option.
  5156. * \remarks Only the following options are recognized:
  5157. - DBARITHABORT
  5158. - DBARITHIGNORE
  5159. - DBCHAINXACTS
  5160. - DBFIPSFLAG
  5161. - DBISOLATION
  5162. - DBNOCOUNT
  5163. - DBNOEXEC
  5164. - DBPARSEONLY
  5165. - DBSHOWPLAN
  5166. - DBSTORPROCID
  5167. - DBQUOTEDIDENT
  5168. * \sa dbisopt(), dbsetopt().
  5169. */
  5170. RETCODE
  5171. dbclropt(DBPROCESS * dbproc, int option, const char param[])
  5172. {
  5173. char *cmd;
  5174. tdsdump_log(TDS_DBG_FUNC, "dbclropt(%p, %d, %s)\n", dbproc, option, param);
  5175. CHECK_CONN(FAIL);
  5176. CHECK_NULP(param, "dbclropt", 3, FAIL);
  5177. if ((option < 0) || (option >= DBNUMOPTIONS)) {
  5178. return FAIL;
  5179. }
  5180. dbproc->dbopts[option].factive = 0;
  5181. switch (option) {
  5182. case DBARITHABORT:
  5183. case DBARITHIGNORE:
  5184. case DBCHAINXACTS:
  5185. case DBFIPSFLAG:
  5186. case DBISOLATION:
  5187. case DBNOCOUNT:
  5188. case DBNOEXEC:
  5189. case DBPARSEONLY:
  5190. case DBSHOWPLAN:
  5191. case DBSTORPROCID:
  5192. case DBQUOTEDIDENT:
  5193. /* server options (on/off) */
  5194. if (asprintf(&cmd, "set %s off\n", dbproc->dbopts[option].text) < 0) {
  5195. return FAIL;
  5196. }
  5197. dbstring_concat(&(dbproc->dboptcmd), cmd);
  5198. free(cmd);
  5199. break;
  5200. case DBBUFFER:
  5201. buffer_set_capacity(dbproc, 1); /* frees row_buf->rows */
  5202. return SUCCEED;
  5203. break;
  5204. default:
  5205. break;
  5206. }
  5207. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbclropt(option = %d)\n", option);
  5208. return FAIL;
  5209. }
  5210. /**
  5211. * \ingroup dblib_core
  5212. * \brief Get value of an option
  5213. *
  5214. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5215. * \param option the option
  5216. * \param param a parameter to \a option.
  5217. * \sa dbclropt(), dbsetopt().
  5218. */
  5219. DBBOOL
  5220. dbisopt(DBPROCESS * dbproc, int option, const char param[])
  5221. {
  5222. tdsdump_log(TDS_DBG_FUNC, "dbisopt(%p, %d, %s)\n", dbproc, option, param);
  5223. CHECK_PARAMETER(dbproc, SYBENULL, FALSE);
  5224. /* sometimes param can be NULL */
  5225. if ((option < 0) || (option >= DBNUMOPTIONS)) {
  5226. return FALSE;
  5227. }
  5228. return dbproc->dbopts[option].factive;
  5229. }
  5230. /** \internal
  5231. * \ingroup dblib_internal
  5232. * \brief Get number of the row currently being read.
  5233. *
  5234. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5235. * \return ostensibly the row number, or 0 if no rows have been read yet.
  5236. * \retval 0 Always.
  5237. * \sa DBCURROW(), dbclrbuf(), DBFIRSTROW(), dbgetrow(), DBLASTROW(), dbnextrow(), dbsetopt(),.
  5238. * \todo Unimplemented.
  5239. */
  5240. DBINT
  5241. dbcurrow(DBPROCESS * dbproc)
  5242. {
  5243. tdsdump_log(TDS_DBG_FUNC, "dbcurrow(%p)\n", dbproc);
  5244. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  5245. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbcurrow()\n");
  5246. return 0;
  5247. }
  5248. /** \internal
  5249. * \ingroup dblib_internal
  5250. * \brief Get returned row's type.
  5251. *
  5252. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5253. * \sa DBROWTYPE().
  5254. */
  5255. STATUS
  5256. dbrowtype(DBPROCESS * dbproc)
  5257. {
  5258. tdsdump_log(TDS_DBG_FUNC, "dbrowtype(%p)\n", dbproc);
  5259. CHECK_PARAMETER(dbproc, SYBENULL, NO_MORE_ROWS);
  5260. return dbproc->row_type;
  5261. }
  5262. /** \internal
  5263. * \ingroup dblib_internal
  5264. * \brief Get number of the row just returned.
  5265. *
  5266. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5267. * \sa DBCURROW().
  5268. * \todo Unimplemented.
  5269. */
  5270. int
  5271. dbcurcmd(DBPROCESS * dbproc)
  5272. {
  5273. tdsdump_log(TDS_DBG_FUNC, "dbcurcmd(%p)\n", dbproc);
  5274. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  5275. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbcurcmd()\n");
  5276. return 0;
  5277. }
  5278. /**
  5279. * \ingroup dblib_core
  5280. * \brief See if more commands are to be processed.
  5281. *
  5282. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5283. * \sa DBMORECMDS(). DBCMDROW(), dbresults(), DBROWS(), DBROWTYPE().
  5284. */
  5285. RETCODE
  5286. dbmorecmds(DBPROCESS * dbproc)
  5287. {
  5288. tdsdump_log(TDS_DBG_FUNC, "dbmorecmds(%p)\n", dbproc);
  5289. CHECK_CONN(FAIL);
  5290. if (dbproc->tds_socket->res_info == NULL) {
  5291. return FAIL;
  5292. }
  5293. if (dbproc->tds_socket->res_info->more_results == 0) {
  5294. tdsdump_log(TDS_DBG_FUNC, "more_results == 0; returns FAIL\n");
  5295. return FAIL;
  5296. }
  5297. assert(dbproc->tds_socket->res_info->more_results == 1);
  5298. tdsdump_log(TDS_DBG_FUNC, "more_results == 1; returns SUCCEED\n");
  5299. return SUCCEED;
  5300. }
  5301. /**
  5302. * \ingroup dblib_rpc
  5303. * \brief Get datatype of a stored procedure's return parameter.
  5304. *
  5305. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5306. * \param retnum Nth return parameter, between 1 and \c dbnumrets().
  5307. * \return SYB* datatype token, or -1 if \a retnum is out of range.
  5308. * \sa dbnextrow(), dbnumrets(), dbprtype(), dbresults(), dbretdata(), dbretlen(), dbretname(), dbrpcinit(), dbrpcparam().
  5309. */
  5310. int
  5311. dbrettype(DBPROCESS * dbproc, int retnum)
  5312. {
  5313. TDSCOLUMN *colinfo;
  5314. tdsdump_log(TDS_DBG_FUNC, "dbrettype(%p, %d)\n", dbproc, retnum);
  5315. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  5316. assert(dbproc->tds_socket);
  5317. assert(dbproc->tds_socket->param_info);
  5318. if (retnum < 1 || retnum > dbproc->tds_socket->param_info->num_cols)
  5319. return -1;
  5320. colinfo = dbproc->tds_socket->param_info->columns[retnum - 1];
  5321. return tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  5322. }
  5323. /**
  5324. * \ingroup dblib_core
  5325. * \brief Get size of the command buffer, in bytes.
  5326. *
  5327. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5328. * \sa dbcmd(), dbfcmd(), dbfreebuf(), dbgetchar(), dbstrcpy().
  5329. */
  5330. int
  5331. dbstrlen(DBPROCESS * dbproc)
  5332. {
  5333. tdsdump_log(TDS_DBG_FUNC, "dbstrlen(%p)\n", dbproc);
  5334. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  5335. return dbproc->dbbufsz;
  5336. }
  5337. /**
  5338. * \ingroup dblib_core
  5339. * \brief Get address of a position in the command buffer.
  5340. *
  5341. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5342. * \param pos offset within the command buffer, starting at \em 0.
  5343. * \remarks A bit overspecialized, this one.
  5344. * \sa dbcmd(), dbfcmd(), dbfreebuf(), dbstrcpy(), dbstrlen(),
  5345. */
  5346. char *
  5347. dbgetchar(DBPROCESS * dbproc, int pos)
  5348. {
  5349. tdsdump_log(TDS_DBG_FUNC, "dbgetchar(%p, %d)\n", dbproc, pos);
  5350. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5351. tdsdump_log(TDS_DBG_FUNC, "dbgetchar() bufsz = %d, pos = %d\n", dbproc->dbbufsz, pos);
  5352. if (dbproc->dbbufsz > 0) {
  5353. if (pos >= 0 && pos < (dbproc->dbbufsz - 1))
  5354. return (char *) &dbproc->dbbuf[pos];
  5355. else
  5356. return NULL;
  5357. } else
  5358. return NULL;
  5359. }
  5360. /**
  5361. * \ingroup dblib_core
  5362. * \brief Get a copy of a chunk of the command buffer.
  5363. *
  5364. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5365. * \param start position in the command buffer to start copying from, starting from \em 0.
  5366. * If start is past the end of the command buffer, dbstrcpy() inserts a null terminator at dest[0].
  5367. * \param numbytes number of bytes to copy.
  5368. - If -1, dbstrcpy() copies the whole command buffer.
  5369. - If 0 dbstrcpy() writes a \c NULL to dest[0].
  5370. - If the command buffer contains fewer than \a numbytes (taking \a start into account) dbstrcpy()
  5371. copies the rest of it.
  5372. * \param dest \em output: the buffer to write to. Make sure it's big enough.
  5373. * \retval SUCCEED the inputs were valid and \a dest was affected.
  5374. * \retval FAIL \a start < 0 or \a numbytes < -1.
  5375. * \sa dbcmd(), dbfcmd(), dbfreebuf(), dbgetchar(), dbstrlen().
  5376. */
  5377. RETCODE
  5378. dbstrcpy(DBPROCESS * dbproc, int start, int numbytes, char *dest)
  5379. {
  5380. tdsdump_log(TDS_DBG_FUNC, "dbstrcpy(%p, %d, %d, %s)\n", dbproc, start, numbytes, dest);
  5381. CHECK_CONN(FAIL);
  5382. CHECK_NULP(dest, "dbstrcpy", 4, FAIL);
  5383. if (start < 0) {
  5384. dbperror(dbproc, SYBENSIP, 0);
  5385. return FAIL;
  5386. }
  5387. if (numbytes < -1) {
  5388. dbperror(dbproc, SYBEBNUM, 0);
  5389. return FAIL;
  5390. }
  5391. dest[0] = 0; /* start with empty string being returned */
  5392. if (dbproc->dbbufsz > 0 && start < dbproc->dbbufsz) {
  5393. if (numbytes == -1)
  5394. numbytes = dbproc->dbbufsz - start;
  5395. if (start + numbytes > dbproc->dbbufsz)
  5396. numbytes = dbproc->dbbufsz - start;
  5397. memcpy(dest, (char *) &dbproc->dbbuf[start], numbytes);
  5398. dest[numbytes] = '\0';
  5399. }
  5400. return SUCCEED;
  5401. }
  5402. /**
  5403. * \ingroup dblib_core
  5404. * \brief safely quotes character values in SQL text.
  5405. *
  5406. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5407. * \param src input string.
  5408. * \param srclen length of \a src in bytes, or -1 to indicate it's null-terminated.
  5409. * \param dest \em output: client-provided output buffer.
  5410. * \param destlen size of \a dest in bytes, or -1 to indicate it's "big enough" and the data should be null-terminated.
  5411. * \param quotetype
  5412. - \c DBSINGLE Doubles all single quotes (').
  5413. - \c DBDOUBLE Doubles all double quotes (").
  5414. - \c DBBOTH Doubles all single and double quotes.
  5415. * \retval SUCCEED everything worked.
  5416. * \retval FAIL no such \a quotetype, or insufficient room in \a dest.
  5417. * \sa dbcmd(), dbfcmd().
  5418. */
  5419. RETCODE
  5420. dbsafestr(DBPROCESS * dbproc, const char *src, DBINT srclen, char *dest, DBINT destlen, int quotetype)
  5421. {
  5422. int i, j = 0;
  5423. int squote = FALSE, dquote = FALSE;
  5424. tdsdump_log(TDS_DBG_FUNC, "dbsafestr(%p, %s, %d, %s, %d, %d)\n", dbproc, src, srclen, dest, destlen, quotetype);
  5425. CHECK_NULP(src, "dbsafestr", 2, FAIL);
  5426. CHECK_NULP(dest, "dbsafestr", 4, FAIL);
  5427. /* check parameters */
  5428. if (srclen < -1 || destlen < -1)
  5429. return FAIL;
  5430. if (srclen == -1)
  5431. srclen = (int)strlen(src);
  5432. if (quotetype == DBSINGLE || quotetype == DBBOTH)
  5433. squote = TRUE;
  5434. if (quotetype == DBDOUBLE || quotetype == DBBOTH)
  5435. dquote = TRUE;
  5436. /* return FAIL if invalid quotetype */
  5437. if (!dquote && !squote)
  5438. return FAIL;
  5439. for (i = 0; i < srclen; i++) {
  5440. /* dbsafestr returns fail if the deststr is not big enough */
  5441. /* need one char + one for terminator */
  5442. if (destlen >= 0 && j >= destlen)
  5443. return FAIL;
  5444. if (squote && src[i] == '\'')
  5445. dest[j++] = '\'';
  5446. else if (dquote && src[i] == '\"')
  5447. dest[j++] = '\"';
  5448. if (destlen >= 0 && j >= destlen)
  5449. return FAIL;
  5450. dest[j++] = src[i];
  5451. }
  5452. if (destlen >= 0 && j >= destlen)
  5453. return FAIL;
  5454. dest[j] = '\0';
  5455. return SUCCEED;
  5456. }
  5457. /**
  5458. * \ingroup dblib_core
  5459. * \brief Print a token value's name to a buffer
  5460. *
  5461. * \param token server SYB* value, e.g. SYBINT.
  5462. * \return ASCII null-terminated string.
  5463. * \sa dbaltop(), dbalttype(), dbcoltype(), dbrettype().
  5464. */
  5465. const char *
  5466. dbprtype(int token)
  5467. {
  5468. tdsdump_log(TDS_DBG_FUNC, "dbprtype(%d)\n", token);
  5469. return tds_prtype(token);
  5470. }
  5471. /**
  5472. * \ingroup dblib_core
  5473. * \brief describe table column attributes with a single call (Freetds-only API function modelled on dbcolinfo)
  5474. *
  5475. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5476. * \param column Nth in the result set, starting from 1.
  5477. * \param pdbcol address of structure to be populated by this function.
  5478. * \return SUCCEED or FAIL.
  5479. * \sa dbcolinfo().
  5480. */
  5481. RETCODE
  5482. dbtablecolinfo (DBPROCESS *dbproc, DBINT column, DBCOL *pdbcol )
  5483. {
  5484. TDSCOLUMN *colinfo;
  5485. tdsdump_log(TDS_DBG_FUNC, "dbtablecolinfo(%p, %d, %p)\n", dbproc, column, pdbcol);
  5486. CHECK_CONN(FAIL);
  5487. CHECK_NULP(pdbcol, "dbtablecolinfo", 3, FAIL);
  5488. DBPERROR_RETURN(pdbcol->SizeOfStruct != sizeof(DBCOL)
  5489. && pdbcol->SizeOfStruct != sizeof(DBCOL2), SYBECOLSIZE);
  5490. colinfo = dbcolptr(dbproc, column);
  5491. if (!colinfo)
  5492. return FAIL;
  5493. tds_strlcpy(pdbcol->Name, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->Name));
  5494. tds_strlcpy(pdbcol->ActualName, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->ActualName));
  5495. pdbcol->Type = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
  5496. pdbcol->UserType = colinfo->column_usertype;
  5497. pdbcol->MaxLength = colinfo->column_size;
  5498. if (colinfo->column_nullable)
  5499. pdbcol->Null = TRUE;
  5500. else
  5501. pdbcol->Null = FALSE;
  5502. pdbcol->VarLength = FALSE;
  5503. if (colinfo->column_nullable
  5504. || is_nullable_type(colinfo->column_type))
  5505. pdbcol->VarLength = TRUE;
  5506. pdbcol->Precision = colinfo->column_prec;
  5507. pdbcol->Scale = colinfo->column_scale;
  5508. pdbcol->Updatable = colinfo->column_writeable ? TRUE : FALSE;
  5509. pdbcol->Identity = colinfo->column_identity ? TRUE : FALSE;
  5510. if (pdbcol->SizeOfStruct >= sizeof(DBCOL2)) {
  5511. DBCOL2 *col = (DBCOL2 *) pdbcol;
  5512. TDSRET rc;
  5513. col->ServerType = colinfo->on_server.column_type;
  5514. col->ServerMaxLength = colinfo->on_server.column_size;
  5515. rc = tds_get_column_declaration(dbproc->tds_socket, colinfo, col->ServerTypeDeclaration);
  5516. if (TDS_FAILED(rc))
  5517. return FAIL;
  5518. }
  5519. return SUCCEED;
  5520. }
  5521. /**
  5522. * \ingroup dblib_core
  5523. * \brief Get text timestamp for a column in the current row.
  5524. *
  5525. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5526. * \param column number of the column in the \c SELECT statement, starting at 1.
  5527. * \return timestamp for \a column, may be NULL.
  5528. * \sa dbtxptr(), dbwritetext().
  5529. */
  5530. DBBINARY *
  5531. dbtxtimestamp(DBPROCESS * dbproc, int column)
  5532. {
  5533. TDSCOLUMN *colinfo;
  5534. TDSBLOB *blob;
  5535. tdsdump_log(TDS_DBG_FUNC, "dbtxtimestamp(%p, %d)\n", dbproc, column);
  5536. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  5537. colinfo = dbcolptr(dbproc, column);
  5538. if (!colinfo || !is_blob_col(colinfo))
  5539. return NULL;
  5540. blob = (TDSBLOB *) colinfo->column_data;
  5541. /* test if valid */
  5542. if (!blob->valid_ptr)
  5543. return NULL;
  5544. return (DBBINARY *) blob->timestamp;
  5545. }
  5546. /**
  5547. * \ingroup dblib_core
  5548. * \brief Get text pointer for a column in the current row.
  5549. *
  5550. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5551. * \param column number of the column in the \c SELECT statement, starting at 1.
  5552. * \return text pointer for \a column, may be NULL.
  5553. * \sa dbtxtimestamp(), dbwritetext().
  5554. */
  5555. DBBINARY *
  5556. dbtxptr(DBPROCESS * dbproc, int column)
  5557. {
  5558. TDSCOLUMN *colinfo;
  5559. TDSBLOB *blob;
  5560. tdsdump_log(TDS_DBG_FUNC, "dbtxptr(%p, %d)\n", dbproc, column);
  5561. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  5562. colinfo = dbcolptr(dbproc, column);
  5563. if (!colinfo || !is_blob_col(colinfo))
  5564. return NULL;
  5565. blob = (TDSBLOB *) colinfo->column_data;
  5566. /* test if valid */
  5567. if (!blob->valid_ptr)
  5568. return NULL;
  5569. return (DBBINARY *) blob->textptr;
  5570. }
  5571. /**
  5572. * \ingroup dblib_core
  5573. * \brief Send text or image data to the server.
  5574. *
  5575. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5576. * \param objname table name
  5577. * \param textptr text pointer to be modified, obtained from dbtxptr().
  5578. * \param textptrlen \em Ignored. Supposed to be \c DBTXPLEN.
  5579. * \param timestamp text timestamp to be modified, obtained from dbtxtimestamp() or dbtxtsnewval(), may be \c NULL.
  5580. * \param log \c TRUE if the operation is to be recorded in the transaction log.
  5581. * \param size overall size of the data (in total, not just for this call), in bytes. A guideline, must not overstate the case.
  5582. * \param text the chunk of data to write.
  5583. * \retval SUCCEED everything worked.
  5584. * \retval FAIL not sent, possibly because \a timestamp is invalid or was changed in the database since it was fetched.
  5585. * \sa dbmoretext(), dbtxptr(), dbtxtimestamp(), dbwritetext(), dbtxtsput().
  5586. */
  5587. RETCODE
  5588. dbwritetext(DBPROCESS * dbproc, char *objname, DBBINARY * textptr, DBTINYINT textptrlen, DBBINARY * timestamp, DBBOOL log,
  5589. DBINT size, BYTE * text)
  5590. {
  5591. char textptr_string[35]; /* 16 * 2 + 2 (0x) + 1 */
  5592. char timestamp_string[19]; /* 8 * 2 + 2 (0x) + 1 */
  5593. TDS_INT result_type;
  5594. tdsdump_log(TDS_DBG_FUNC, "dbwritetext(%p, %s, %p, %d, %p, %d)\n",
  5595. dbproc, objname, textptr, textptrlen, timestamp, log);
  5596. CHECK_CONN(FAIL);
  5597. CHECK_NULP(objname, "dbwritetext", 2, FAIL);
  5598. CHECK_NULP(textptr, "dbwritetext", 3, FAIL);
  5599. CHECK_NULP(timestamp, "dbwritetext", 5, FAIL);
  5600. CHECK_PARAMETER(size, SYBEZTXT, FAIL);
  5601. if (IS_TDSDEAD(dbproc->tds_socket))
  5602. return FAIL;
  5603. if (textptrlen > DBTXPLEN)
  5604. return FAIL;
  5605. dbconvert(dbproc, SYBBINARY, (BYTE *) textptr, textptrlen, SYBCHAR, (BYTE *) textptr_string, -1);
  5606. dbconvert(dbproc, SYBBINARY, (BYTE *) timestamp, 8, SYBCHAR, (BYTE *) timestamp_string, -1);
  5607. dbproc->dbresults_state = _DB_RES_INIT;
  5608. if (dbproc->tds_socket->state == TDS_PENDING) {
  5609. const TDSRET ret = tds_process_tokens(dbproc->tds_socket, &result_type, NULL, TDS_TOKEN_TRAILING);
  5610. if (ret != TDS_NO_MORE_RESULTS) {
  5611. dbperror(dbproc, SYBERPND, 0);
  5612. dbproc->command_state = DBCMDSENT;
  5613. return FAIL;
  5614. }
  5615. }
  5616. if (TDS_FAILED(tds_writetext_start(dbproc->tds_socket, objname,
  5617. textptr_string, timestamp_string, (log == TRUE), size)))
  5618. return FAIL;
  5619. if (!text) {
  5620. dbproc->text_size = size;
  5621. dbproc->text_sent = 0;
  5622. return SUCCEED;
  5623. }
  5624. tds_writetext_continue(dbproc->tds_socket, text, size);
  5625. tds_writetext_end(dbproc->tds_socket);
  5626. dbproc->text_sent = 0;
  5627. if (dbsqlok(dbproc) == SUCCEED && dbresults(dbproc) == SUCCEED)
  5628. return SUCCEED;
  5629. return FAIL;
  5630. }
  5631. /**
  5632. * \ingroup dblib_core
  5633. * \brief Fetch part of a text or image value from the server.
  5634. *
  5635. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5636. * \param buf \em output: buffer into which text will be placed.
  5637. * \param bufsize size of \a buf, in bytes.
  5638. * \return
  5639. - \c >0 count of bytes placed in \a buf.
  5640. - \c 0 end of row.
  5641. - \c -1 \em error, no result set ready for \a dbproc.
  5642. - \c NO_MORE_ROWS all rows read, no further data.
  5643. * \sa dbmoretext(), dbnextrow(), dbwritetext().
  5644. */
  5645. STATUS
  5646. dbreadtext(DBPROCESS * dbproc, void *buf, DBINT bufsize)
  5647. {
  5648. TDSSOCKET *tds;
  5649. TDSCOLUMN *curcol;
  5650. int cpbytes, bytes_avail;
  5651. TDS_INT result_type;
  5652. TDSRESULTINFO *resinfo;
  5653. tdsdump_log(TDS_DBG_FUNC, "dbreadtext(%p, %p, %d)\n", dbproc, buf, bufsize);
  5654. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  5655. CHECK_NULP(buf, "dbreadtext", 2, -1);
  5656. tds = dbproc->tds_socket;
  5657. if (!tds || !tds->res_info || !tds->res_info->columns[0])
  5658. return -1;
  5659. resinfo = tds->res_info;
  5660. curcol = resinfo->columns[0];
  5661. /*
  5662. * if the current position is beyond the end of the text
  5663. * set pos to 0 and return 0 to denote the end of the
  5664. * text
  5665. */
  5666. if (curcol->column_textpos && curcol->column_textpos >= curcol->column_cur_size) {
  5667. curcol->column_textpos = 0;
  5668. return 0;
  5669. }
  5670. /*
  5671. * if pos is 0 (first time through or last call exhausted the text)
  5672. * then read another row
  5673. */
  5674. if (curcol->column_textpos == 0) {
  5675. const int mask = TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE;
  5676. buffer_save_row(dbproc);
  5677. switch (tds_process_tokens(dbproc->tds_socket, &result_type, NULL, mask)) {
  5678. case TDS_SUCCESS:
  5679. if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT)
  5680. break;
  5681. case TDS_NO_MORE_RESULTS:
  5682. return NO_MORE_ROWS;
  5683. default:
  5684. return -1;
  5685. }
  5686. }
  5687. /* find the number of bytes to return */
  5688. bytes_avail = curcol->column_cur_size - curcol->column_textpos;
  5689. cpbytes = bytes_avail > bufsize ? bufsize : bytes_avail;
  5690. memcpy(buf, &((TDSBLOB *) curcol->column_data)->textvalue[curcol->column_textpos], cpbytes);
  5691. curcol->column_textpos += cpbytes;
  5692. return cpbytes;
  5693. }
  5694. /**
  5695. * \ingroup dblib_core
  5696. * \brief Send chunk of a text/image value to the server.
  5697. *
  5698. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5699. * \param size count of bytes to send.
  5700. * \param text textpointer, obtained from dbtxptr.
  5701. * \retval SUCCEED always.
  5702. * \sa dbtxptr(), dbtxtimestamp(), dbwritetext().
  5703. * \todo Check return value of called functions and return \c FAIL if appropriate.
  5704. */
  5705. RETCODE
  5706. dbmoretext(DBPROCESS * dbproc, DBINT size, const BYTE text[])
  5707. {
  5708. tdsdump_log(TDS_DBG_FUNC, "dbmoretext(%p, %d, %p)\n", dbproc, size, text);
  5709. CHECK_CONN(FAIL);
  5710. CHECK_NULP(text, "dbmoretext", 3, FAIL);
  5711. assert(dbproc->text_size >= dbproc->text_sent);
  5712. /* TODO this test should be inside tds_writetext_continue, currently not */
  5713. if (size < 0 || size > dbproc->text_size - dbproc->text_sent)
  5714. return FAIL;
  5715. if (size) {
  5716. if (TDS_FAILED(tds_writetext_continue(dbproc->tds_socket, text, size)))
  5717. return FAIL;
  5718. dbproc->text_sent += size;
  5719. if (dbproc->text_sent == dbproc->text_size) {
  5720. tds_writetext_end(dbproc->tds_socket);
  5721. dbproc->text_sent = 0;
  5722. }
  5723. }
  5724. return SUCCEED;
  5725. }
  5726. /**
  5727. * \ingroup dblib_core
  5728. * \brief Record to a file all SQL commands sent to the server
  5729. *
  5730. * \param filename name of file to write to.
  5731. * \remarks Files are named \em filename.n, where n is an integer, starting with 0, and incremented with each callto dbopen().
  5732. * \sa dbopen(), TDSDUMP environment variable().
  5733. */
  5734. void
  5735. dbrecftos(const char filename[])
  5736. {
  5737. char *f;
  5738. tdsdump_log(TDS_DBG_FUNC, "dbrecftos(%s)\n", filename);
  5739. if (filename == NULL) {
  5740. dbperror(NULL, SYBENULP, 0);
  5741. return;
  5742. }
  5743. f = strdup(filename);
  5744. if (!f) {
  5745. dbperror(NULL, SYBEMEM, 0);
  5746. return;
  5747. }
  5748. tds_mutex_lock(&dblib_mutex);
  5749. free(g_dblib_ctx.recftos_filename);
  5750. g_dblib_ctx.recftos_filename = f;
  5751. g_dblib_ctx.recftos_filenum = 0;
  5752. tds_mutex_unlock(&dblib_mutex);
  5753. }
  5754. /** \internal
  5755. * \ingroup dblib_internal
  5756. * \brief Get the TDS version in use for \a dbproc.
  5757. *
  5758. *
  5759. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5760. * \return a \c DBTDS* token.
  5761. * \remarks The integer values of the constants are counterintuitive.
  5762. * \sa DBTDS().
  5763. */
  5764. int
  5765. dbtds(DBPROCESS * dbproc)
  5766. {
  5767. tdsdump_log(TDS_DBG_FUNC, "dbtds(%p)\n", dbproc);
  5768. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  5769. if (dbproc->tds_socket) {
  5770. switch (dbproc->tds_socket->conn->tds_version) {
  5771. case 0x402:
  5772. return DBTDS_4_2;
  5773. case 0x406:
  5774. return DBTDS_4_6;
  5775. case 0x500:
  5776. return DBTDS_5_0;
  5777. case 0x700:
  5778. return DBTDS_7_0;
  5779. case 0x701:
  5780. return DBTDS_7_1;
  5781. case 0x702:
  5782. return DBTDS_7_2;
  5783. case 0x703:
  5784. return DBTDS_7_3;
  5785. default:
  5786. return DBTDS_UNKNOWN;
  5787. }
  5788. }
  5789. return -1;
  5790. }
  5791. /**
  5792. * \ingroup dblib_core
  5793. * \brief See which version of db-lib is in use.
  5794. *
  5795. * \return null-terminated ASCII string representing the version of db-lib.
  5796. * \remarks FreeTDS returns the CVS version string of dblib.c.
  5797. * \sa
  5798. */
  5799. const char *
  5800. dbversion()
  5801. {
  5802. tdsdump_log(TDS_DBG_FUNC, "dbversion(void)\n");
  5803. return TDS_VERSION_NO;
  5804. }
  5805. #if defined(DBLIB_UNIMPLEMENTED)
  5806. /**
  5807. * \ingroup dblib_core
  5808. * \brief Set the default character set.
  5809. *
  5810. * \param charset null-terminated ASCII string, matching a row in master..syscharsets.
  5811. * \sa dbsetdeflang(), dbsetdefcharset(), dblogin(), dbopen().
  5812. * \todo Unimplemented.
  5813. */
  5814. RETCODE
  5815. dbsetdefcharset(char *charset)
  5816. {
  5817. tdsdump_log(TDS_DBG_FUNC, "dbsetdefcharset(%s)\n", charset);
  5818. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetdefcharset()\n");
  5819. return SUCCEED;
  5820. }
  5821. /**
  5822. * \ingroup dblib_core
  5823. * \brief Ready execution of a registered procedure.
  5824. *
  5825. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5826. * \param procedure_name to call.
  5827. * \param namelen size of \a procedure_name, in bytes.
  5828. * \sa dbregparam(), dbregexec(), dbregwatch(), dbreglist(), dbregwatchlist
  5829. * \todo Unimplemented.
  5830. */
  5831. RETCODE
  5832. dbreginit(DBPROCESS * dbproc, DBCHAR * procedure_name, DBSMALLINT namelen)
  5833. {
  5834. tdsdump_log(TDS_DBG_FUNC, "dbreginit(%p, %s, %d)\n", dbproc, procedure_name, namelen);
  5835. CHECK_CONN(FAIL);
  5836. CHECK_NULP(procedure_name, "dbreginit", 2, FAIL);
  5837. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbreginit()\n");
  5838. return SUCCEED;
  5839. }
  5840. /**
  5841. * \ingroup dblib_core
  5842. * \brief Get names of Open Server registered procedures.
  5843. *
  5844. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5845. * \sa dbregparam(), dbregexec(), dbregwatch(), dbreglist(), dbregwatchlist().
  5846. * \todo Unimplemented.
  5847. */
  5848. RETCODE
  5849. dbreglist(DBPROCESS * dbproc)
  5850. {
  5851. tdsdump_log(TDS_DBG_FUNC, "dbreglist(%p)\n", dbproc);
  5852. CHECK_CONN(FAIL);
  5853. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbreglist()\n");
  5854. return SUCCEED;
  5855. }
  5856. /**
  5857. * \ingroup dblib_core
  5858. * \brief Describe parameter of registered procedure .
  5859. *
  5860. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5861. * \param param_name
  5862. * \param type \c SYB* datatype.
  5863. * \param datalen size of \a data.
  5864. * \param data address of buffer holding value for the parameter.
  5865. * \sa dbreginit(), dbregexec(), dbnpdefine(), dbnpcreate(), dbregwatch().
  5866. * \todo Unimplemented.
  5867. */
  5868. RETCODE
  5869. dbregparam(DBPROCESS * dbproc, char *param_name, int type, DBINT datalen, BYTE * data)
  5870. {
  5871. tdsdump_log(TDS_DBG_FUNC, "dbregparam(%p, %s, %d, %d, %p)\n", dbproc, param_name, type, datalen, data);
  5872. CHECK_CONN(FAIL);
  5873. CHECK_NULP(param_name, "dbregparam", 2, FAIL);
  5874. CHECK_NULP(data, "dbregparam", 5, FAIL);
  5875. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbregparam()\n");
  5876. return SUCCEED;
  5877. }
  5878. /**
  5879. * \ingroup dblib_core
  5880. * \brief Execute a registered procedure.
  5881. *
  5882. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5883. * \param options
  5884. * \sa dbreginit(), dbregparam(), dbregwatch(), dbregnowatch
  5885. * \todo Unimplemented.
  5886. */
  5887. RETCODE
  5888. dbregexec(DBPROCESS * dbproc, DBUSMALLINT options)
  5889. {
  5890. tdsdump_log(TDS_DBG_FUNC, "dbregexec(%p, %d)\n", dbproc, options);
  5891. CHECK_CONN(FAIL);
  5892. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbregexec()\n");
  5893. return SUCCEED;
  5894. }
  5895. #endif
  5896. /**
  5897. * \ingroup dblib_datetime
  5898. * \brief Get name of a month, in some human language.
  5899. *
  5900. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5901. * \param language \em ignored.
  5902. * \param monthnum number of the month, starting with 1.
  5903. * \param shortform set to \c TRUE for a three letter output ("Jan" - "Dec"), else zero.
  5904. * \return address of null-terminated ASCII string, or \c NULL on error.
  5905. * \sa db12hour(), dbdateorder(), dbdayname(), DBSETLNATLANG(), dbsetopt().
  5906. */
  5907. const char *
  5908. dbmonthname(DBPROCESS * dbproc, char *language, int monthnum, DBBOOL shortform)
  5909. {
  5910. static const char shortmon[][4] = {
  5911. "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  5912. };
  5913. static const char longmon[][12] = {
  5914. "January", "February", "March", "April", "May", "June",
  5915. "July", "August", "September", "October", "November", "December"
  5916. };
  5917. tdsdump_log(TDS_DBG_FUNC, "dbmonthname(%p, %s, %d, %d)\n", dbproc, language, monthnum, shortform);
  5918. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5919. CHECK_NULP(language, "dbmonthname", 2, NULL);
  5920. if (monthnum < 1 || monthnum > 12)
  5921. return NULL;
  5922. return (shortform) ? shortmon[monthnum - 1] : longmon[monthnum - 1];
  5923. }
  5924. /**
  5925. * \ingroup dblib_core
  5926. * \brief See if a command caused the current database to change.
  5927. *
  5928. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5929. * \return name of new database, if changed, as a null-terminated ASCII string, else \c NULL.
  5930. * \sa dbname(), dbresults(), dbsqlexec(), dbsqlsend(), dbuse().
  5931. */
  5932. char *
  5933. dbchange(DBPROCESS * dbproc)
  5934. {
  5935. tdsdump_log(TDS_DBG_FUNC, "dbchange(%p)\n", dbproc);
  5936. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5937. if (dbproc->envchange_rcv & (1 << (TDS_ENV_DATABASE - 1))) {
  5938. return dbproc->dbcurdb;
  5939. }
  5940. return NULL;
  5941. }
  5942. /**
  5943. * \ingroup dblib_core
  5944. * \brief Get name of current database.
  5945. *
  5946. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5947. * \return current database name, as null-terminated ASCII string.
  5948. * \sa dbchange(), dbuse().
  5949. */
  5950. char *
  5951. dbname(DBPROCESS * dbproc)
  5952. {
  5953. tdsdump_log(TDS_DBG_FUNC, "dbname(%p)\n", dbproc);
  5954. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5955. return dbproc->dbcurdb;
  5956. }
  5957. /**
  5958. * \ingroup dblib_core
  5959. * \brief Get \c syscharset name of the server character set.
  5960. *
  5961. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5962. * \return name of server's charset, as null-terminated ASCII string.
  5963. * \sa dbcharsetconv(), dbgetcharset(), DBSETLCHARSET().
  5964. */
  5965. char *
  5966. dbservcharset(DBPROCESS * dbproc)
  5967. {
  5968. tdsdump_log(TDS_DBG_FUNC, "dbservcharset(%p)\n", dbproc);
  5969. CHECK_PARAMETER(dbproc, SYBENULL, NULL);
  5970. return dbproc->servcharset;
  5971. }
  5972. /**
  5973. * \ingroup dblib_core
  5974. * \brief Transmit the command buffer to the server. \em Non-blocking, does not wait for a response.
  5975. *
  5976. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  5977. * \retval SUCCEED SQL sent.
  5978. * \retval FAIL protocol problem, unless dbsqlsend() when it's not supposed to be (in which case a db-lib error
  5979. message will be emitted).
  5980. * \sa dbcmd(), dbfcmd(), DBIORDESC(), DBIOWDESC(), dbnextrow(), dbpoll(), dbresults(), dbsettime(), dbsqlexec(), dbsqlok().
  5981. */
  5982. RETCODE
  5983. dbsqlsend(DBPROCESS * dbproc)
  5984. {
  5985. TDSSOCKET *tds;
  5986. char *cmdstr;
  5987. TDSRET rc;
  5988. TDS_INT result_type;
  5989. char timestr[256];
  5990. tdsdump_log(TDS_DBG_FUNC, "dbsqlsend(%p)\n", dbproc);
  5991. CHECK_CONN(FAIL);
  5992. tds = dbproc->tds_socket;
  5993. if (tds->state == TDS_PENDING) {
  5994. if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING) != TDS_NO_MORE_RESULTS) {
  5995. dbperror(dbproc, SYBERPND, 0);
  5996. dbproc->command_state = DBCMDSENT;
  5997. return FAIL;
  5998. }
  5999. }
  6000. if (dbproc->dboptcmd) {
  6001. if ((cmdstr = dbstring_get(dbproc->dboptcmd)) == NULL) {
  6002. dbperror(dbproc, SYBEASEC, 0); /* Attempt to send an empty command buffer to the server */
  6003. return FAIL;
  6004. }
  6005. rc = tds_submit_query(dbproc->tds_socket, cmdstr);
  6006. free(cmdstr);
  6007. dbstring_free(&(dbproc->dboptcmd));
  6008. if (TDS_FAILED(rc)) {
  6009. return FAIL;
  6010. }
  6011. dbproc->avail_flag = FALSE;
  6012. dbproc->envchange_rcv = 0;
  6013. dbproc->dbresults_state = _DB_RES_INIT;
  6014. while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS))
  6015. == TDS_SUCCESS);
  6016. if (rc != TDS_NO_MORE_RESULTS) {
  6017. return FAIL;
  6018. }
  6019. }
  6020. dbproc->more_results = TRUE;
  6021. if (dbproc->ftos != NULL) {
  6022. fprintf(dbproc->ftos, "%s\n", dbproc->dbbuf);
  6023. fprintf(dbproc->ftos, "go /* %s */\n", _dbprdate(timestr));
  6024. fflush(dbproc->ftos);
  6025. }
  6026. if (TDS_FAILED(tds_submit_query(dbproc->tds_socket, (char *) dbproc->dbbuf))) {
  6027. return FAIL;
  6028. }
  6029. dbproc->avail_flag = FALSE;
  6030. dbproc->envchange_rcv = 0;
  6031. dbproc->dbresults_state = _DB_RES_INIT;
  6032. dbproc->command_state = DBCMDSENT;
  6033. return SUCCEED;
  6034. }
  6035. /**
  6036. * \ingroup dblib_core
  6037. * \brief Get user-defined datatype of a compute column.
  6038. *
  6039. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6040. * \param computeid of \c COMPUTE clause to which we're referring.
  6041. * \param column Nth column in \a computeid, starting from 1.
  6042. * \returns user-defined datatype of compute column, else -1.
  6043. * \sa dbalttype(), dbcolutype().
  6044. */
  6045. DBINT
  6046. dbaltutype(DBPROCESS * dbproc, int computeid, int column)
  6047. {
  6048. TDSCOLUMN *colinfo;
  6049. tdsdump_log(TDS_DBG_FUNC, "dbaltutype(%p, %d, %d)\n", dbproc, computeid, column);
  6050. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  6051. colinfo = dbacolptr(dbproc, computeid, column, 0);
  6052. if (!colinfo)
  6053. return -1;
  6054. return colinfo->column_usertype;
  6055. }
  6056. /**
  6057. * \ingroup dblib_core
  6058. * \brief Get size of data in compute column.
  6059. *
  6060. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6061. * \param computeid of \c COMPUTE clause to which we're referring.
  6062. * \param column Nth column in \a computeid, starting from 1.
  6063. * \sa dbadata(), dbadlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumalts().
  6064. */
  6065. DBINT
  6066. dbaltlen(DBPROCESS * dbproc, int computeid, int column)
  6067. {
  6068. TDSCOLUMN *colinfo;
  6069. tdsdump_log(TDS_DBG_FUNC, "dbaltlen(%p, %d, %d)\n", dbproc, computeid, column);
  6070. colinfo = dbacolptr(dbproc, computeid, column, 0);
  6071. if (!colinfo)
  6072. return -1;
  6073. return colinfo->column_size;
  6074. }
  6075. /**
  6076. * \ingroup dblib_core
  6077. * \brief See if a server response has arrived.
  6078. *
  6079. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6080. * \param milliseconds how long to wait for the server before returning:
  6081. - \c 0 return immediately.
  6082. - \c -1 do not return until the server responds or a system interrupt occurs.
  6083. * \param ready_dbproc \em output: DBPROCESS for which a response arrived, of \c NULL.
  6084. * \param return_reason \em output:
  6085. - \c DBRESULT server responded.
  6086. - \c DBNOTIFICATION registered procedure notification has arrived. dbpoll() the registered handler, if
  6087. any, before it returns.
  6088. - \c DBTIMEOUT \a milliseconds elapsed before the server responded.
  6089. - \c DBINTERRUPT operating-system interrupt occurred before the server responded.
  6090. * \retval SUCCEED everything worked.
  6091. * \retval FAIL a server connection died.
  6092. * \sa DBIORDESC(), DBRBUF(), dbresults(), dbreghandle(), dbsqlok().
  6093. * \todo Unimplemented.
  6094. */
  6095. #if defined(DBLIB_UNIMPLEMENTED)
  6096. RETCODE
  6097. dbpoll(DBPROCESS * dbproc, long milliseconds, DBPROCESS ** ready_dbproc, int *return_reason)
  6098. {
  6099. tdsdump_log(TDS_DBG_FUNC, "dbpoll(%p, %ld, %p, %p)\n", dbproc, milliseconds, ready_dbproc, return_reason);
  6100. CHECK_CONN(FAIL);
  6101. CHECK_NULP(ready_dbproc, "dbpoll", 3, FAIL);
  6102. CHECK_NULP(return_reason, "dbpoll", 4, FAIL);
  6103. tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbpoll()\n");
  6104. return SUCCEED;
  6105. }
  6106. #endif
  6107. /** \internal
  6108. * \ingroup dblib_internal
  6109. * \brief Get number of the first row in the row buffer.
  6110. *
  6111. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6112. * \sa DBFIRSTROW(), dbclrbuf(), DBCURROW(), dbgetrow(), DBLASTROW(), dbnextrow(), dbsetopt().
  6113. */
  6114. DBINT
  6115. dbfirstrow(DBPROCESS * dbproc)
  6116. {
  6117. tdsdump_log(TDS_DBG_FUNC, "dbfirstrow(%p)\n", dbproc);
  6118. CHECK_CONN(0);
  6119. return buffer_idx2row(&dbproc->row_buf, dbproc->row_buf.tail);
  6120. }
  6121. /** \internal
  6122. * \ingroup dblib_internal
  6123. * \brief Get number of the last row in the row buffer.
  6124. *
  6125. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6126. * \sa DBLASTROW(), dbclrbuf(), DBCURROW(), DBFIRSTROW(), dbgetrow(), dbnextrow(), dbsetopt().
  6127. */
  6128. DBINT
  6129. dblastrow(DBPROCESS * dbproc)
  6130. {
  6131. int idx;
  6132. tdsdump_log(TDS_DBG_FUNC, "dblastrow(%p)\n", dbproc);
  6133. CHECK_PARAMETER(dbproc, SYBENULL, 0);
  6134. idx = dbproc->row_buf.head;
  6135. if (dbproc->row_buf.head != dbproc->row_buf.tail) {
  6136. if (--idx < 0)
  6137. idx = dbproc->row_buf.capacity - 1;
  6138. }
  6139. assert(idx >= 0);
  6140. return buffer_idx2row(&dbproc->row_buf, idx);
  6141. }
  6142. /** \internal
  6143. * \ingroup dblib_internal
  6144. * \brief Get file descriptor of the socket used by a \c DBPROCESS to read data coming from the server. (!)
  6145. *
  6146. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6147. * \sa dbcmd(), DBIORDESC(), DBIOWDESC(), dbnextrow(), dbpoll(), DBRBUF(), dbresults(), dbsqlok(), dbsqlsend().
  6148. */
  6149. int
  6150. dbiordesc(DBPROCESS * dbproc)
  6151. {
  6152. tdsdump_log(TDS_DBG_FUNC, "dbiordesc(%p)\n", dbproc);
  6153. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  6154. return (int) tds_get_s(dbproc->tds_socket);
  6155. }
  6156. /** \internal
  6157. * \ingroup dblib_internal
  6158. * \brief Get file descriptor of the socket used by a \c DBPROCESS to write data coming to the server. (!)
  6159. *
  6160. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6161. * \sa dbcmd(), DBIORDESC(), DBIOWDESC(), dbnextrow(), dbpoll(), DBRBUF(), dbresults(), dbsqlok(), dbsqlsend().
  6162. */
  6163. int
  6164. dbiowdesc(DBPROCESS * dbproc)
  6165. {
  6166. tdsdump_log(TDS_DBG_FUNC, "dbiowdesc(%p)\n", dbproc);
  6167. CHECK_PARAMETER(dbproc, SYBENULL, -1);
  6168. return (int) tds_get_s(dbproc->tds_socket);
  6169. }
  6170. DBBOOL
  6171. dbisavail(DBPROCESS * dbproc)
  6172. {
  6173. tdsdump_log(TDS_DBG_FUNC, "dbisavail(%p)\n", dbproc);
  6174. CHECK_PARAMETER(dbproc, SYBENULL, FALSE);
  6175. return dbproc->avail_flag;
  6176. }
  6177. /** \internal
  6178. * \ingroup dblib_internal
  6179. * \brief Mark a \c DBPROCESS as "available".
  6180. *
  6181. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6182. * \remarks Basically bogus. \c FreeTDS behaves the way Sybase's implementation does, but so what?
  6183. Many \c db-lib functions set the \c DBPROCESS to "not available", but only
  6184. dbsetavail() resets it to "available".
  6185. * \sa DBISAVAIL(). DBSETAVAIL().
  6186. */
  6187. void
  6188. dbsetavail(DBPROCESS * dbproc)
  6189. {
  6190. tdsdump_log(TDS_DBG_FUNC, "dbsetavail(%p)\n", dbproc);
  6191. CHECK_PARAMETER(dbproc, SYBENULL, );
  6192. dbproc->avail_flag = TRUE;
  6193. }
  6194. /**
  6195. * \ingroup dblib_core
  6196. * \brief Build a printable string from text containing placeholders for variables.
  6197. *
  6198. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6199. * \param charbuf \em output: buffer that will contain the ASCII null-terminated string built by \c dbstrbuild().
  6200. * \param bufsize size of \a charbuf, in bytes.
  6201. * \param text null-terminated ASCII string, with \em placeholders for variables. \em A Placeholder is a
  6202. * three-byte string, made up of:
  6203. - '%' a percent sign
  6204. - 0-9 an integer (designates the argument number to use, starting with 1.)
  6205. - '!' an exclamation point
  6206. * \param formats null-terminated ASCII sprintf-style string. Has one format specifier for each placeholder in \a text.
  6207. * \remarks Following \a formats are the arguments, the values to substitute for the placeholders.
  6208. * \sa dbconvert(), dbdatename(), dbdatepart().
  6209. */
  6210. RETCODE
  6211. dbstrbuild(DBPROCESS * dbproc, char *charbuf, int bufsize, char *text, char *formats, ...)
  6212. {
  6213. va_list ap;
  6214. TDSRET rc;
  6215. int resultlen;
  6216. tdsdump_log(TDS_DBG_FUNC, "dbstrbuild(%p, %s, %d, %s, %s, ...)\n", dbproc, charbuf, bufsize, text, formats);
  6217. CHECK_NULP(charbuf, "dbstrbuild", 2, FAIL);
  6218. CHECK_NULP(text, "dbstrbuild", 4, FAIL);
  6219. CHECK_NULP(formats, "dbstrbuild", 5, FAIL);
  6220. va_start(ap, formats);
  6221. rc = tds_vstrbuild(charbuf, bufsize, &resultlen, text, TDS_NULLTERM, formats, TDS_NULLTERM, ap);
  6222. charbuf[resultlen] = '\0';
  6223. va_end(ap);
  6224. return TDS_SUCCEED(rc) ? SUCCEED : FAIL;
  6225. }
  6226. static char *
  6227. _dbprdate(char *timestr)
  6228. {
  6229. time_t currtime = time(NULL);
  6230. assert(timestr);
  6231. strcpy(timestr, asctime(gmtime(&currtime)));
  6232. timestr[strlen(timestr) - 1] = '\0'; /* remove newline */
  6233. return timestr;
  6234. }
  6235. static DBINT
  6236. _dbnullable(DBPROCESS * dbproc, int column)
  6237. {
  6238. TDSCOLUMN *colinfo;
  6239. TDSRESULTINFO *resinfo;
  6240. assert(dbproc && dbproc->tds_socket);
  6241. resinfo = dbproc->tds_socket->res_info;
  6242. if (!resinfo || column < 1 || column > resinfo->num_cols)
  6243. return FALSE;
  6244. colinfo = resinfo->columns[column - 1];
  6245. if (colinfo->column_nullable)
  6246. return TRUE;
  6247. return FALSE;
  6248. }
  6249. static const char *
  6250. tds_prdatatype(TDS_SERVER_TYPE datatype_token)
  6251. {
  6252. switch (datatype_token) {
  6253. case SYBCHAR: return "SYBCHAR";
  6254. case SYBVARCHAR: return "SYBVARCHAR";
  6255. case SYBINTN: return "SYBINTN";
  6256. case SYBINT1: return "SYBINT1";
  6257. case SYBINT2: return "SYBINT2";
  6258. case SYBINT4: return "SYBINT4";
  6259. case SYBINT8: return "SYBINT8";
  6260. case SYBFLT8: return "SYBFLT8";
  6261. case SYBDATETIME: return "SYBDATETIME";
  6262. case SYBBIT: return "SYBBIT";
  6263. case SYBTEXT: return "SYBTEXT";
  6264. case SYBNTEXT: return "SYBNTEXT";
  6265. case SYBIMAGE: return "SYBIMAGE";
  6266. case SYBMONEY4: return "SYBMONEY4";
  6267. case SYBMONEY: return "SYBMONEY";
  6268. case SYBDATETIME4: return "SYBDATETIME4";
  6269. case SYBREAL: return "SYBREAL";
  6270. case SYBBINARY: return "SYBBINARY";
  6271. case SYBVOID: return "SYBVOID";
  6272. case SYBVARBINARY: return "SYBVARBINARY";
  6273. case SYBNVARCHAR: return "SYBNVARCHAR";
  6274. case SYBBITN: return "SYBBITN";
  6275. case SYBNUMERIC: return "SYBNUMERIC";
  6276. case SYBDECIMAL: return "SYBDECIMAL";
  6277. case SYBFLTN: return "SYBFLTN";
  6278. case SYBMONEYN: return "SYBMONEYN";
  6279. case SYBDATETIMN: return "SYBDATETIMN";
  6280. case XSYBCHAR: return "XSYBCHAR";
  6281. case XSYBVARCHAR: return "XSYBVARCHAR";
  6282. case XSYBNVARCHAR: return "XSYBNVARCHAR";
  6283. case XSYBNCHAR: return "XSYBNCHAR";
  6284. case XSYBVARBINARY: return "XSYBVARBINARY";
  6285. case XSYBBINARY: return "XSYBBINARY";
  6286. case SYBLONGBINARY: return "SYBLONGBINARY";
  6287. case SYBSINT1: return "SYBSINT1";
  6288. case SYBUINT2: return "SYBUINT2";
  6289. case SYBUINT4: return "SYBUINT4";
  6290. case SYBUINT8: return "SYBUINT8";
  6291. case SYBUNIQUE: return "SYBUNIQUE";
  6292. case SYBVARIANT: return "SYBVARIANT";
  6293. case SYBMSXML: return "SYBMSXML";
  6294. case SYBMSDATE: return "SYBMSDATE";
  6295. case SYBMSTIME: return "SYBMSTIME";
  6296. case SYBMSDATETIME2: return "SYBMSDATETIME2";
  6297. case SYBMSDATETIMEOFFSET: return "SYBMSDATETIMEOFFSET";
  6298. default: break;
  6299. }
  6300. return "(unknown)";
  6301. }
  6302. #if 1
  6303. void
  6304. copy_data_to_host_var(DBPROCESS * dbproc, int srctype, const BYTE * src, DBINT srclen,
  6305. BYTE * dest, DBINT destlen,
  6306. int bindtype, DBINT *indicator)
  6307. {
  6308. CONV_RESULT dres;
  6309. DBINT ret;
  6310. int i, len;
  6311. DBINT indicator_value = 0;
  6312. int limited_dest_space = 0;
  6313. int desttype = dblib_bound_type(bindtype);
  6314. tdsdump_log(TDS_DBG_FUNC, "copy_data_to_host_var(%d [%s] len %d => %d [%s] len %d)\n",
  6315. srctype, tds_prdatatype(srctype), srclen, desttype, tds_prdatatype(desttype), destlen);
  6316. CHECK_NULP(src, "copy_data_to_host_var", 3, );
  6317. CHECK_NULP(dest, "copy_data_to_host_var", 6, );
  6318. /* indicator can be NULL */
  6319. assert(srclen >= 0);
  6320. if (destlen > 0) {
  6321. limited_dest_space = 1;
  6322. }
  6323. /* oft times we are asked to convert a data type to itself */
  6324. if (desttype == SYBNUMERIC) {
  6325. DBNUMERIC *num = NULL; /* num->scale is unsigned */
  6326. /* only MS, use always source */
  6327. if (bindtype == SRCNUMERICBIND || bindtype == SRCDECIMALBIND) {
  6328. if (is_numeric_type(srctype))
  6329. num = (DBNUMERIC*) src;
  6330. else
  6331. num = (DBNUMERIC*) dest;
  6332. } else if (dbproc->msdblib) {
  6333. /* MS by default use only destination informations */
  6334. num = (DBNUMERIC*) dest;
  6335. } else {
  6336. /* Sybase, dbbind means source or default */
  6337. /* TODO if dbbind_ps is used is more complicated */
  6338. if (is_numeric_type(srctype))
  6339. num = (DBNUMERIC*) src;
  6340. }
  6341. if (!num) {
  6342. dres.n.precision = 18;
  6343. dres.n.scale = 0;
  6344. } else {
  6345. dres.n.precision = num->precision;
  6346. dres.n.scale = num->scale;
  6347. }
  6348. } else if ((srctype == desttype) ||
  6349. (is_similar_type(srctype, desttype))) {
  6350. tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var() srctype == desttype\n");
  6351. switch (desttype) {
  6352. case SYBBINARY:
  6353. case SYBIMAGE:
  6354. if (srclen > destlen && destlen >= 0) {
  6355. dbperror(dbproc, SYBECOFL, 0);
  6356. } else {
  6357. memcpy(dest, src, srclen);
  6358. if (srclen < destlen)
  6359. memset(dest + srclen, 0, destlen - srclen);
  6360. }
  6361. break;
  6362. case SYBCHAR:
  6363. case SYBVARCHAR:
  6364. case SYBTEXT:
  6365. switch (bindtype) {
  6366. case NTBSTRINGBIND: /* strip trailing blanks, null term */
  6367. while (srclen && src[srclen - 1] == ' ') {
  6368. --srclen;
  6369. }
  6370. if (limited_dest_space) {
  6371. if (srclen + 1 > destlen) {
  6372. dbperror(dbproc, SYBECOFL, 0);
  6373. indicator_value = srclen + 1;
  6374. srclen = destlen - 1;
  6375. }
  6376. }
  6377. memcpy(dest, src, srclen);
  6378. dest[srclen] = '\0';
  6379. break;
  6380. case STRINGBIND: /* pad with blanks, null term */
  6381. if (limited_dest_space) {
  6382. if (srclen + 1 > destlen) {
  6383. dbperror(dbproc, SYBECOFL, 0);
  6384. indicator_value = srclen + 1;
  6385. srclen = destlen - 1;
  6386. }
  6387. } else {
  6388. destlen = srclen;
  6389. }
  6390. memcpy(dest, src, srclen);
  6391. for (i = srclen; i < destlen - 1; i++)
  6392. dest[i] = ' ';
  6393. dest[i] = '\0';
  6394. break;
  6395. case CHARBIND: /* pad with blanks, NO null term */
  6396. if (limited_dest_space) {
  6397. if (srclen > destlen) {
  6398. dbperror(dbproc, SYBECOFL, 0);
  6399. indicator_value = srclen;
  6400. srclen = destlen;
  6401. }
  6402. } else {
  6403. destlen = srclen;
  6404. }
  6405. memcpy(dest, src, srclen);
  6406. for (i = srclen; i < destlen; i++)
  6407. dest[i] = ' ';
  6408. break;
  6409. case VARYCHARBIND: /* strip trailing blanks, NO null term */
  6410. if (limited_dest_space) {
  6411. if (srclen > destlen) {
  6412. dbperror(dbproc, SYBECOFL, 0);
  6413. indicator_value = srclen;
  6414. srclen = destlen;
  6415. }
  6416. }
  6417. memcpy(((DBVARYCHAR *)dest)->str, src, srclen);
  6418. ((DBVARYCHAR *)dest)->len = srclen;
  6419. break;
  6420. }
  6421. break;
  6422. case SYBINT1:
  6423. case SYBINT2:
  6424. case SYBINT4:
  6425. case SYBINT8:
  6426. case SYBFLT8:
  6427. case SYBREAL:
  6428. case SYBBIT:
  6429. case SYBBITN:
  6430. case SYBMONEY:
  6431. case SYBMONEY4:
  6432. case SYBDATETIME:
  6433. case SYBDATETIME4:
  6434. case SYBUNIQUE:
  6435. ret = tds_get_size_by_type(desttype);
  6436. memcpy(dest, src, ret);
  6437. break;
  6438. case SYBMSDATE:
  6439. case SYBMSTIME:
  6440. case SYBMSDATETIME2:
  6441. case SYBMSDATETIMEOFFSET:
  6442. ret = sizeof(TDS_DATETIMEALL);
  6443. memcpy(dest, src, ret);
  6444. break;
  6445. default:
  6446. break;
  6447. }
  6448. if (indicator)
  6449. *indicator = indicator_value;
  6450. return;
  6451. } /* end srctype == desttype */
  6452. len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *) src, srclen, desttype, &dres);
  6453. tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var(): tds_convert returned %d\n", len);
  6454. switch (len) {
  6455. case TDS_CONVERT_NOAVAIL:
  6456. dbperror(dbproc, SYBERDCN, 0);
  6457. return;
  6458. break;
  6459. case TDS_CONVERT_SYNTAX:
  6460. dbperror(dbproc, SYBECSYN, 0);
  6461. return;
  6462. break;
  6463. case TDS_CONVERT_NOMEM:
  6464. dbperror(dbproc, SYBEMEM, ENOMEM);
  6465. return;
  6466. break;
  6467. case TDS_CONVERT_OVERFLOW:
  6468. dbperror(dbproc, SYBECOFL, 0);
  6469. return;
  6470. break;
  6471. case TDS_CONVERT_FAIL:
  6472. return;
  6473. break;
  6474. default:
  6475. if (len < 0) {
  6476. return;
  6477. }
  6478. break;
  6479. }
  6480. switch (desttype) {
  6481. case SYBVARBINARY:
  6482. case SYBBINARY:
  6483. case SYBIMAGE:
  6484. if (bindtype == VARYBINBIND) {
  6485. if (limited_dest_space) {
  6486. if (len > sizeof(((DBVARYBIN *)dest)->array)) {
  6487. dbperror(dbproc, SYBECOFL, 0);
  6488. indicator_value = len;
  6489. len = sizeof(((DBVARYBIN *)dest)->array);
  6490. }
  6491. }
  6492. memcpy(((DBVARYBIN *)dest)->array, dres.c, len);
  6493. ((DBVARYBIN *)dest)->len = len;
  6494. } else {
  6495. if (len > destlen && destlen >= 0) {
  6496. dbperror(dbproc, SYBECOFL, 0);
  6497. } else {
  6498. memcpy(dest, dres.ib, len);
  6499. if (len < destlen)
  6500. memset(dest + len, 0, destlen - len);
  6501. }
  6502. }
  6503. TDS_ZERO_FREE(dres.ib);
  6504. break;
  6505. case SYBINT1:
  6506. memcpy(dest, &(dres.ti), 1);
  6507. break;
  6508. case SYBINT2:
  6509. memcpy(dest, &(dres.si), 2);
  6510. break;
  6511. case SYBINT4:
  6512. memcpy(dest, &(dres.i), 4);
  6513. break;
  6514. case SYBINT8:
  6515. memcpy(dest, &(dres.bi), 8);
  6516. break;
  6517. case SYBFLT8:
  6518. memcpy(dest, &(dres.f), 8);
  6519. break;
  6520. case SYBREAL:
  6521. memcpy(dest, &(dres.r), 4);
  6522. break;
  6523. case SYBBIT:
  6524. case SYBBITN:
  6525. memcpy(dest, &(dres.ti), 1);
  6526. break;
  6527. case SYBMONEY:
  6528. memcpy(dest, &(dres.m), sizeof(TDS_MONEY));
  6529. break;
  6530. case SYBMONEY4:
  6531. memcpy(dest, &(dres.m4), sizeof(TDS_MONEY4));
  6532. break;
  6533. case SYBDATETIME:
  6534. memcpy(dest, &(dres.dt), sizeof(TDS_DATETIME));
  6535. break;
  6536. case SYBDATETIME4:
  6537. memcpy(dest, &(dres.dt4), sizeof(TDS_DATETIME4));
  6538. break;
  6539. case SYBNUMERIC:
  6540. case SYBDECIMAL:
  6541. memcpy(dest, &(dres.n), sizeof(TDS_NUMERIC));
  6542. break;
  6543. case SYBUNIQUE:
  6544. memcpy(dest, &(dres.u), sizeof(TDS_UNIQUE));
  6545. break;
  6546. case SYBMSDATE:
  6547. case SYBMSTIME:
  6548. case SYBMSDATETIME2:
  6549. case SYBMSDATETIMEOFFSET:
  6550. memcpy(dest, &(dres.dta), sizeof(TDS_DATETIMEALL));
  6551. break;
  6552. case SYBCHAR:
  6553. case SYBVARCHAR:
  6554. case SYBTEXT:
  6555. tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var() outputs %d bytes char data destlen = %d \n", len, destlen);
  6556. switch (bindtype) {
  6557. case NTBSTRINGBIND: /* strip trailing blanks, null term */
  6558. while (len && dres.c[len - 1] == ' ') {
  6559. --len;
  6560. }
  6561. if (limited_dest_space) {
  6562. if (len + 1 > destlen) {
  6563. dbperror(dbproc, SYBECOFL, 0);
  6564. len = destlen - 1;
  6565. }
  6566. }
  6567. memcpy(dest, dres.c, len);
  6568. dest[len] = '\0';
  6569. break;
  6570. case STRINGBIND: /* pad with blanks, null term */
  6571. if (limited_dest_space) {
  6572. if (len + 1 > destlen) {
  6573. dbperror(dbproc, SYBECOFL, 0);
  6574. len = destlen - 1;
  6575. }
  6576. } else {
  6577. destlen = len;
  6578. }
  6579. memcpy(dest, dres.c, len);
  6580. for (i = len; i < destlen - 1; i++)
  6581. dest[i] = ' ';
  6582. dest[i] = '\0';
  6583. break;
  6584. case CHARBIND: /* pad with blanks, NO null term */
  6585. if (limited_dest_space) {
  6586. if (len > destlen) {
  6587. dbperror(dbproc, SYBECOFL, 0);
  6588. indicator_value = len;
  6589. len = destlen;
  6590. }
  6591. } else {
  6592. destlen = len;
  6593. }
  6594. memcpy(dest, dres.c, len);
  6595. for (i = len; i < destlen; i++)
  6596. dest[i] = ' ';
  6597. break;
  6598. case VARYCHARBIND: /* strip trailing blanks, NO null term */
  6599. if (limited_dest_space) {
  6600. if (len > sizeof(((DBVARYCHAR *)dest)->str)) {
  6601. dbperror(dbproc, SYBECOFL, 0);
  6602. indicator_value = len;
  6603. len = sizeof(((DBVARYCHAR *)dest)->str);
  6604. }
  6605. }
  6606. memcpy(((DBVARYCHAR *)dest)->str, dres.c, len);
  6607. ((DBVARYCHAR *)dest)->len = len;
  6608. break;
  6609. }
  6610. free(dres.c);
  6611. break;
  6612. default:
  6613. tdsdump_log(TDS_DBG_INFO1, "error: copy_data_to_host_var(): unrecognized desttype %d \n", desttype);
  6614. break;
  6615. }
  6616. if (indicator)
  6617. *indicator = indicator_value;
  6618. return;
  6619. }
  6620. #endif
  6621. /** \internal
  6622. * \ingroup dblib_internal
  6623. * \remarks member msgno Vendor-defined message number
  6624. * \remarks member severity Is passed to the error handler
  6625. * \remarks member msgtext Text of message
  6626. */
  6627. typedef struct _dblib_error_message
  6628. {
  6629. DBINT msgno;
  6630. int severity;
  6631. const char *msgtext;
  6632. } DBLIB_ERROR_MESSAGE;
  6633. /*
  6634. * The msgtext member holds up to two strings. The first one is the message text, which may contain placeholders.
  6635. * The second one, if it exists, is the format string for dbstrbuild(). Messages containing no placeholders still need
  6636. * an extra NULL to indicate a zero-length format string.
  6637. */
  6638. static const DBLIB_ERROR_MESSAGE dblib_error_messages[] =
  6639. { { SYBEVERDOWN, EXINFO, "TDS version downgraded to 7.1!\0" }
  6640. , { SYBEICONVIU, EXCONVERSION, "Some character(s) could not be converted into client's character set\0" }
  6641. , { SYBEICONVAVAIL, EXCONVERSION, "Character set conversion is not available between client character set '%1!' and "
  6642. "server character set '%2!'\0%s %s" }
  6643. , { SYBEICONVO, EXCONVERSION, "Error converting characters into server's character set. Some character(s) could "
  6644. "not be converted\0" }
  6645. , { SYBEICONVI, EXCONVERSION, "Some character(s) could not be converted into client's character set. Unconverted "
  6646. "bytes were changed to question marks ('?')\0" }
  6647. , { SYBEICONV2BIG, EXCONVERSION, "Buffer overflow converting characters from client into server's character set\0" }
  6648. , { SYBEPORT, EXUSER, "Both port and instance specified\0" }
  6649. , { SYBETDSVER, EXUSER, "Cannot bcp with TDSVER < 5.0\0" }
  6650. , { SYBEAAMT, EXPROGRAM, "User attempted a dbaltbind with mismatched column and variable types\0" }
  6651. , { SYBEABMT, EXPROGRAM, "User attempted a dbbind with mismatched column and variable types\0" }
  6652. , { SYBEABNC, EXPROGRAM, "Attempt to bind to a non-existent column\0" }
  6653. , { SYBEABNP, EXPROGRAM, "Attempt to bind using NULL pointers\0" }
  6654. , { SYBEABNV, EXPROGRAM, "Attempt to bind to a NULL program variable\0" }
  6655. , { SYBEACNV, EXCONVERSION, "Attempt to do data-conversion with NULL destination variable.\0" }
  6656. , { SYBEADST, EXCONSISTENCY, "International Release: Error in attempting to determine the size of a pair of "
  6657. "translation tables\0" }
  6658. , { SYBEAICF, EXCONSISTENCY, "International Release: Error in attempting to install custom format\0" }
  6659. , { SYBEALTT, EXCONSISTENCY, "International Release: Error in attempting to load a pair of translation tables\0" }
  6660. , { SYBEAOLF, EXRESOURCE, "International Release: Error in attempting to open a localization file\0" }
  6661. , { SYBEAPCT, EXCONSISTENCY, "International Release: Error in attempting to perform a character set translation\0" }
  6662. , { SYBEAPUT, EXPROGRAM, "Attempt to print unknown token\0" }
  6663. , { SYBEARDI, EXRESOURCE, "International Release: Error in attempting to read datetime information from a "
  6664. "localization file\0" }
  6665. , { SYBEARDL, EXRESOURCE, "International Release: Error in attempting to read the dblib.loc localization file\0" }
  6666. , { SYBEASEC, EXPROGRAM, "Attempt to send an empty command buffer to the server\0" }
  6667. , { SYBEASNL, EXPROGRAM, "Attempt to set fields in a null LOGINREC\0" }
  6668. , { SYBEASTL, EXPROGRAM, "Synchronous I/O attempted at AST level\0" }
  6669. , { SYBEASUL, EXPROGRAM, "Attempt to set unknown LOGINREC field\0" }
  6670. , { SYBEAUTN, EXPROGRAM, "Attempt to update the timestamp of a table that has no timestamp column\0" }
  6671. , { SYBEBADPK, EXINFO, "Packet size of %1! not supported -- size of %2! used instead!\0%d %d" }
  6672. , { SYBEBBCI, EXINFO, "Batch successfully bulk copied to the server\0" }
  6673. , { SYBEBBL, EXPROGRAM, "Bad bindlen parameter passed to dbsetnull\0" }
  6674. , { SYBEBCBC, EXPROGRAM, "bcp_columns must be called before bcp_colfmt and bcp_colfmt_ps\0" }
  6675. , { SYBEBCBNPR, EXPROGRAM, "bcp_bind: if varaddr is NULL, prefixlen must be 0 "
  6676. "and no terminator should be specified\0" }
  6677. , { SYBEBCBNTYP, EXPROGRAM, "bcp_bind: if varaddr is NULL and varlen greater than 0, the table column type "
  6678. "must be SYBTEXT or SYBIMAGE and the program variable type must be SYBTEXT, SYBCHAR, "
  6679. "SYBIMAGE or SYBBINARY\0" }
  6680. , { SYBEBCBPREF, EXPROGRAM, "Illegal prefix length. Legal values are 0, 1, 2 or 4\0" }
  6681. , { SYBEBCFO, EXUSER, "bcp host files must contain at least one column\0" }
  6682. , { SYBEBCHLEN, EXPROGRAM, "host_collen should be greater than or equal to -1\0" }
  6683. , { SYBEBCIS, EXCONSISTENCY, "Attempt to bulk copy an illegally-sized column value to the server\0" }
  6684. , { SYBEBCIT, EXPROGRAM, "It is illegal to use BCP terminators with program variables other than SYBCHAR, "
  6685. "SYBBINARY, SYBTEXT, or SYBIMAGE\0" }
  6686. , { SYBEBCITBLEN, EXPROGRAM, "bcp_init: tblname parameter is too long\0" }
  6687. , { SYBEBCITBNM, EXPROGRAM, "bcp_init: tblname parameter cannot be NULL\0" }
  6688. , { SYBEBCMTXT, EXPROGRAM, "bcp_moretext may be used only when there is at least one text or image column in "
  6689. "the server table\0" }
  6690. , { SYBEBCNL, EXNONFATAL, "Negative length-prefix found in BCP data-file\0" }
  6691. , { SYBEBCNN, EXUSER, "Attempt to bulk copy a NULL value into a Server column "
  6692. "which does not accept null values\0" }
  6693. , { SYBEBCNT, EXUSER, "Attempt to use Bulk Copy with a non-existent Server table\0" }
  6694. , { SYBEBCOR, EXCONSISTENCY, "Attempt to bulk copy an oversized row to the server\0" }
  6695. , { SYBEBCPB, EXPROGRAM, "bcp_bind, bcp_moretext and bcp_sendrow may not be used after bcp_init has been "
  6696. "passed a non-NULL input file name\0" }
  6697. , { SYBEBCPCTYP, EXPROGRAM, "bcp_colfmt: If table_colnum is 0, host_type cannot be 0\0" }
  6698. , { SYBEBCPI, EXPROGRAM, "bcp_init must be called before any other bcp routines\0" }
  6699. , { SYBEBCPN, EXPROGRAM, "bcp_bind, bcp_collen, bcp_colptr, bcp_moretext and bcp_sendrow may be used only "
  6700. "after bcp_init has been called with the copy direction set to DB_IN\0" }
  6701. , { SYBEBCPREC, EXNONFATAL, "Column %1!: Illegal precision value encountered\0%d" }
  6702. , { SYBEBCPREF, EXPROGRAM, "Illegal prefix length. Legal values are -1, 0, 1, 2 or 4\0" }
  6703. , { SYBEBCRE, EXNONFATAL, "I/O error while reading bcp datafile\0" }
  6704. , { SYBEBCRO, EXINFO, "The BCP hostfile '%1!' contains only %2! rows. It was impossible to read the "
  6705. "requested %3! rows\0%s %d %d" }
  6706. , { SYBEBCSA, EXUSER, "The BCP hostfile '%1!' contains only %2! rows. "
  6707. "Skipping all of these rows is not allowed\0%s %d" }
  6708. , { SYBEBCSET, EXCONSISTENCY, "Unknown character-set encountered\0" }
  6709. , { SYBEBCSI, EXPROGRAM, "Host-file columns may be skipped only when copying into the Server\0" }
  6710. , { SYBEBCSNDROW, EXPROGRAM, "bcp_sendrow may not be called unless all text data for the previous row has been "
  6711. "sent using bcp_moretext\0" }
  6712. , { SYBEBCSNTYP, EXPROGRAM, "column number %1!: if varaddr is NULL and varlen greater than 0, the table column "
  6713. "type must be SYBTEXT or SYBIMAGE and the program variable type must be SYBTEXT, "
  6714. "SYBCHAR, SYBIMAGE or SYBBINARY\0%d" }
  6715. , { SYBEBCUC, EXRESOURCE, "bcp: Unable to close host datafile\0" }
  6716. , { SYBEBCUO, EXRESOURCE, "bcp: Unable to open host datafile\0" }
  6717. , { SYBEBCVH, EXPROGRAM, "bcp_exec may be called only after bcp_init has been passed a valid host file\0" }
  6718. , { SYBEBCVLEN, EXPROGRAM, "varlen should be greater than or equal to -1\0" }
  6719. , { SYBEBCWE, EXNONFATAL, "I/O error while writing bcp datafile\0" }
  6720. , { SYBEBDIO, EXPROGRAM, "Bad bulk copy direction. Must be either IN or OUT\0" }
  6721. , { SYBEBEOF, EXNONFATAL, "Unexpected EOF encountered in bcp datafile\0" }
  6722. , { SYBEBIHC, EXPROGRAM, "Incorrect host-column number found in bcp format file\0" }
  6723. , { SYBEBIVI, EXPROGRAM, "bcp_columns, bcp_colfmt and bcp_colfmt_ps may be used only after bcp_init has been "
  6724. "passed a valid input file\0" }
  6725. , { SYBEBNCR, EXPROGRAM, "Attempt to bind user variable to a non-existent compute row\0" }
  6726. , { SYBEBNUM, EXPROGRAM, "Bad numbytes parameter passed to dbstrcpy\0" }
  6727. , { SYBEBPKS, EXPROGRAM, "In DBSETLPACKET, the packet size parameter must be between 0 and 999999\0" }
  6728. , { SYBEBPREC, EXPROGRAM, "Illegal precision specified\0" }
  6729. , { SYBEBPROBADDEF, EXCONSISTENCY, "bcp protocol error: illegal default column id received\0" }
  6730. , { SYBEBPROCOL, EXCONSISTENCY, "bcp protocol error: returned column count differs from the actual number of "
  6731. "columns received\0" }
  6732. , { SYBEBPRODEF, EXCONSISTENCY, "bcp protocol error: expected default information and got none\0" }
  6733. , { SYBEBPRODEFID, EXCONSISTENCY, "bcp protocol error: default column id and actual column id are not same\0" }
  6734. , { SYBEBPRODEFTYP, EXCONSISTENCY, "bcp protocol error: default value datatype differs from column datatype\0" }
  6735. , { SYBEBPROEXTDEF, EXCONSISTENCY, "bcp protocol error: more than one row of default information received\0" }
  6736. , { SYBEBPROEXTRES, EXCONSISTENCY, "bcp protocol error: unexpected set of results received\0" }
  6737. , { SYBEBPRONODEF, EXCONSISTENCY, "bcp protocol error: default value received for column that does not have default\0" }
  6738. , { SYBEBPRONUMDEF, EXCONSISTENCY, "bcp protocol error: expected number of defaults differs from the actual number of "
  6739. "defaults received\0" }
  6740. , { SYBEBRFF, EXRESOURCE, "I/O error while reading bcp format file\0" }
  6741. , { SYBEBSCALE, EXPROGRAM, "Illegal scale specified\0" }
  6742. , { SYBEBTMT, EXPROGRAM, "Attempt to send too much text data via the bcp_moretext call\0" }
  6743. , { SYBEBTOK, EXCOMM, "Bad token from the server: Datastream processing out of sync\0" }
  6744. , { SYBEBTYP, EXPROGRAM, "Unknown bind type passed to DB-Library function\0" }
  6745. , { SYBEBTYPSRV, EXPROGRAM, "Datatype is not supported by the server\0" }
  6746. , { SYBEBUCE, EXRESOURCE, "bcp: Unable to close error file\0" }
  6747. , { SYBEBUCF, EXPROGRAM, "bcp: Unable to close format file\0" }
  6748. , { SYBEBUDF, EXPROGRAM, "bcp: Unrecognized datatype found in format file\0" }
  6749. , { SYBEBUFF, EXPROGRAM, "bcp: Unable to create format file\0" }
  6750. , { SYBEBUFL, EXCONSISTENCY, "DB-Library internal error-send buffer length corrupted\0" }
  6751. , { SYBEBUOE, EXRESOURCE, "bcp: Unable to open error file\0" }
  6752. , { SYBEBUOF, EXPROGRAM, "bcp: Unable to open format file\0" }
  6753. , { SYBEBWEF, EXNONFATAL, "I/O error while writing bcp error file\0" }
  6754. , { SYBEBWFF, EXRESOURCE, "I/O error while writing bcp format file\0" }
  6755. , { SYBECAP, EXCOMM, "DB-Library capabilities not accepted by the Server\0" }
  6756. , { SYBECAPTYP, EXCOMM, "Unexpected capability type in CAPABILITY datastream\0" }
  6757. , { SYBECDNS, EXCONSISTENCY, "Datastream indicates that a compute column is derived from a non-existent select "
  6758. "list member\0" }
  6759. , { SYBECDOMAIN, EXCONVERSION, "Source field value is not within the domain of legal values\0" }
  6760. , { SYBECINTERNAL, EXCONVERSION, "Internal Conversion error\0" }
  6761. , { SYBECLOS, EXCOMM, "Error in closing network connection\0" }
  6762. , { SYBECLPR, EXCONVERSION, "Data conversion resulted in loss of precision\0" }
  6763. , { SYBECNOR, EXPROGRAM, "Column number out of range\0" }
  6764. , { SYBECNOV, EXCONVERSION, "Attempt to set variable to NULL resulted in overflow\0" }
  6765. , { SYBECOFL, EXCONVERSION, "Data conversion resulted in overflow\0" }
  6766. , { SYBECONN, EXCOMM, "Unable to connect: Adaptive Server is unavailable or does not exist\0" }
  6767. , { SYBECRNC, EXPROGRAM, "The current row is not a result of compute clause %1!, so it is illegal to attempt "
  6768. "to extract that data from this row\0%d" }
  6769. , { SYBECRSAGR, EXPROGRAM, "Aggregate functions are not allowed in a cursor statement\0" }
  6770. , { SYBECRSBROL, EXPROGRAM, "Backward scrolling cannot be used in a forward scrolling cursor\0" }
  6771. , { SYBECRSBSKEY, EXPROGRAM, "Keyset cannot be scrolled backward in mixed cursors with a previous fetch type\0" }
  6772. , { SYBECRSBUFR, EXPROGRAM, "Row buffering should not be turned on when using cursor APIs\0" }
  6773. , { SYBECRSDIS, EXPROGRAM, "Cursor statement contains one of the disallowed phrases compute, union, for "
  6774. "browse, or select into\0" }
  6775. , { SYBECRSFLAST, EXPROGRAM, "Fetch type LAST requires fully keyset driven cursors\0" }
  6776. , { SYBECRSFRAND, EXPROGRAM, "Fetch types RANDOM and RELATIVE can only be used within the keyset of keyset "
  6777. "driven cursors\0" }
  6778. , { SYBECRSFROWN, EXPROGRAM, "Row number to be fetched is outside valid range\0" }
  6779. , { SYBECRSFTYPE, EXRESOURCE, "Unknown fetch type\0" }
  6780. , { SYBECRSINV, EXPROGRAM, "Invalid cursor statement\0" }
  6781. , { SYBECRSINVALID, EXRESOURCE, "The cursor handle is invalid\0" }
  6782. , { SYBECRSMROWS, EXRESOURCE, "Multiple rows are returned, only one is expected while retrieving dbname\0" }
  6783. , { SYBECRSNOBIND, EXPROGRAM, "Cursor bind must be called prior to dbcursor invocation\0" }
  6784. , { SYBECRSNOCOUNT, EXPROGRAM, "The DBNOCOUNT option should not be turned on "
  6785. "when doing updates or deletes with dbcursor\0" }
  6786. , { SYBECRSNOFREE, EXPROGRAM, "The DBNOAUTOFREE option should not be turned on when using cursor APIs\0" }
  6787. , { SYBECRSNOIND, EXPROGRAM, "One of the tables involved in the cursor statement does not have a unique index\0" }
  6788. , { SYBECRSNOKEYS, EXRESOURCE, "The entire keyset must be defined for KEYSET type cursors\0" }
  6789. , { SYBECRSNOLEN, EXRESOURCE, "No unique index found\0" }
  6790. , { SYBECRSNOPTCC, EXRESOURCE, "No OPTCC was found\0" }
  6791. , { SYBECRSNORDER, EXRESOURCE, "The order of clauses must be from, where, and order by\0" }
  6792. , { SYBECRSNORES, EXPROGRAM, "Cursor statement generated no results\0" }
  6793. , { SYBECRSNROWS, EXRESOURCE, "No rows returned, at least one is expected\0" }
  6794. , { SYBECRSNOTABLE, EXRESOURCE, "Table name is NULL\0" }
  6795. , { SYBECRSNOUPD, EXPROGRAM, "Update or delete operation did not affect any rows\0" }
  6796. , { SYBECRSNOWHERE, EXPROGRAM, "A WHERE clause is not allowed in a cursor update or insert\0" }
  6797. , { SYBECRSNUNIQUE, EXRESOURCE, "No unique keys associated with this view\0" }
  6798. , { SYBECRSORD, EXPROGRAM, "Only fully keyset driven cursors can have order by, group by, or having phrases\0" }
  6799. , { SYBECRSRO, EXPROGRAM, "Data locking or modifications cannot be made in a READONLY cursor\0" }
  6800. , { SYBECRSSET, EXPROGRAM, "A SET clause is required for a cursor update or insert\0" }
  6801. , { SYBECRSTAB, EXPROGRAM, "Table name must be determined in operations involving data locking or modifications\0" }
  6802. , { SYBECRSVAR, EXRESOURCE, "There is no valid address associated with this bind\0" }
  6803. , { SYBECRSVIEW, EXPROGRAM, "A view cannot be joined with another table or a view in a cursor statement\0" }
  6804. , { SYBECRSVIIND, EXPROGRAM, "The view used in the cursor statement does not include all the unique index "
  6805. "columns of the underlying tables\0" }
  6806. , { SYBECRSUPDNB, EXPROGRAM, "Update or insert operations cannot use bind variables when binding type is NOBIND\0" }
  6807. , { SYBECRSUPDTAB, EXPROGRAM, "Update or insert operations using bind variables require single table cursors\0" }
  6808. , { SYBECSYN, EXCONVERSION, "Attempt to convert data stopped by syntax error in source field\0" }
  6809. , { SYBECUFL, EXCONVERSION, "Data conversion resulted in underflow\0" }
  6810. , { SYBECWLL, EXPROGRAM, "Attempt to set column width less than 1\0" }
  6811. , { SYBEDBPS, EXRESOURCE, "Maximum number of DBPROCESSes already allocated\0" }
  6812. , { SYBEDDNE, EXINFO, "DBPROCESS is dead or not enabled\0" }
  6813. , { SYBEDIVZ, EXUSER, "Attempt to divide by $0.00 in function %1!\0%s" }
  6814. , { SYBEDNTI, EXPROGRAM, "Attempt to use dbtxtsput to put a new text timestamp into a column whose datatype "
  6815. "is neither SYBTEXT nor SYBIMAGE\0" }
  6816. , { SYBEDPOR, EXPROGRAM, "Out-of-range datepart constant\0" }
  6817. , { SYBEDVOR, EXPROGRAM, "Day values must be between 1 and 7\0" }
  6818. , { SYBEECAN, EXINFO, "Attempted to cancel unrequested event notification\0" }
  6819. , { SYBEEINI, EXINFO, "Must call dbreginit before dbregexec\0" }
  6820. , { SYBEETD, EXPROGRAM, "Failure to send the expected amount of TEXT or IMAGE data via dbmoretext\0" }
  6821. , { SYBEEUNR, EXCOMM, "Unsolicited event notification received\0" }
  6822. , { SYBEEVOP, EXINFO, "Called dbregwatch with a bad options parameter\0" }
  6823. , { SYBEEVST, EXINFO, "Must initiate a transaction before calling dbregparam\0" }
  6824. , { SYBEFCON, EXCOMM, "Adaptive Server connection failed\0" }
  6825. , { SYBEFRES, EXFATAL, "Challenge-Response function failed\0" }
  6826. , { SYBEFSHD, EXRESOURCE, "Error in attempting to find the Sybase home directory\0" }
  6827. , { SYBEFUNC, EXPROGRAM, "Functionality not supported at the specified version level\0" }
  6828. , { SYBEICN, EXPROGRAM, "Invalid computeid or compute column number\0" }
  6829. , { SYBEIDCL, EXCONSISTENCY, "Illegal datetime column length returned by Adaptive Server. Legal datetime lengths "
  6830. "are 4 and 8 bytes\0" }
  6831. , { SYBEIDECCL, EXCONSISTENCY, "Invalid decimal column length returned by the server\0" }
  6832. , { SYBEIFCL, EXCONSISTENCY, "Illegal floating-point column length returned by Adaptive Server. Legal "
  6833. "floating-point lengths are 4 and 8 bytes\0" }
  6834. , { SYBEIFNB, EXPROGRAM, "Illegal field number passed to bcp_control\0" }
  6835. , { SYBEIICL, EXCONSISTENCY, "Illegal integer column length returned by Adaptive Server. Legal integer lengths "
  6836. "are 1, 2, and 4 bytes\0" }
  6837. , { SYBEIMCL, EXCONSISTENCY, "Illegal money column length returned by Adaptive Server. Legal money lengths are 4 "
  6838. "and 8 bytes\0" }
  6839. , { SYBEINLN, EXUSER, "Interface file: unexpected end-of-line\0" }
  6840. , { SYBEINTF, EXUSER, "Server name not found in configuration files\0" }
  6841. , { SYBEINUMCL, EXCONSISTENCY, "Invalid numeric column length returned by the server\0" }
  6842. , { SYBEIPV, EXINFO, "%1! is an illegal value for the %2! parameter of %3!\0%d %s %s" }
  6843. , { SYBEISOI, EXCONSISTENCY, "International Release: Invalid sort-order information found\0" }
  6844. , { SYBEISRVPREC, EXCONSISTENCY, "Illegal precision value returned by the server\0" }
  6845. , { SYBEISRVSCL, EXCONSISTENCY, "Illegal scale value returned by the server\0" }
  6846. , { SYBEITIM, EXPROGRAM, "Illegal timeout value specified\0" }
  6847. , { SYBEIVERS, EXPROGRAM, "Illegal version level specified\0" }
  6848. , { SYBEKBCI, EXINFO, "1000 rows sent to the server\0" }
  6849. , { SYBEKBCO, EXINFO, "1000 rows successfully bulk copied to host file\0" }
  6850. , { SYBEMEM, EXRESOURCE, "Unable to allocate sufficient memory\0" }
  6851. , { SYBEMOV, EXUSER, "Money arithmetic resulted in overflow in function %1!\0%s" }
  6852. , { SYBEMPLL, EXUSER, "Attempt to set maximum number of DBPROCESSes lower than 1\0" }
  6853. , { SYBEMVOR, EXPROGRAM, "Month values must be between 1 and 12\0" }
  6854. , { SYBENBUF, EXINFO, "Called dbsendpassthru with a NULL buf parameter\0" }
  6855. , { SYBENBVP, EXPROGRAM, "Cannot pass dbsetnull a NULL bindval pointer\0" }
  6856. , { SYBENDC, EXPROGRAM, "Cannot have negative component in date in numeric form\0" }
  6857. , { SYBENDTP, EXPROGRAM, "Called dbdatecrack with NULL datetime parameter\0" }
  6858. , { SYBENEG, EXCOMM, "Negotiated login attempt failed\0" }
  6859. , { SYBENHAN, EXINFO, "Called dbrecvpassthru with a NULL handle parameter\0" }
  6860. , { SYBENMOB, EXPROGRAM, "No such member of order by clause\0" }
  6861. , { SYBENOEV, EXINFO, "DBPOLL can not be called when registered procedure notifications have been disabled\0" }
  6862. , { SYBENPRM, EXPROGRAM, "NULL parameter not allowed for this dboption\0" }
  6863. , { SYBENSIP, EXPROGRAM, "Negative starting index passed to dbstrcpy\0" }
  6864. , { SYBENTLL, EXUSER, "Name too long for LOGINREC field\0" }
  6865. , { SYBENTTN, EXPROGRAM, "Attempt to use dbtxtsput to put a new text timestamp into a non-existent data row\0" }
  6866. , { SYBENULL, EXINFO, "NULL DBPROCESS pointer passed to DB-Library\0" }
  6867. , { SYBENULP, EXPROGRAM, "Called %1! with parameter %2! NULL\0%s %d" }
  6868. , { SYBENXID, EXNONFATAL, "The Server did not grant us a distributed-transaction ID\0" }
  6869. , { SYBEONCE, EXPROGRAM, "Function can be called only once\0" }
  6870. , { SYBEOOB, EXCOMM, "Error in sending out-of-band data to the server\0" }
  6871. , { SYBEOPIN, EXNONFATAL, "Could not open interface file\0" }
  6872. , { SYBEOPNA, EXNONFATAL, "Option is not available with current server\0" }
  6873. , { SYBEOREN, EXINFO, "International Release: Warning: an out-of-range error-number was encountered in "
  6874. "dblib.loc. The maximum permissible error-number is defined as DBERRCOUNT in sybdb.h\0" }
  6875. , { SYBEORPF, EXUSER, "Attempt to set remote password would overflow "
  6876. "the login record's remote password field\0" }
  6877. , { SYBEPOLL, EXINFO, "There is already an active dbpoll\0" }
  6878. , { SYBEPRTF, EXINFO, "dbtracestring may only be called from a printfunc\0" }
  6879. , { SYBEPWD, EXUSER, "Login incorrect\0" }
  6880. , { SYBERDCN, EXCONVERSION, "Requested data conversion does not exist\0" }
  6881. , { SYBERDNR, EXPROGRAM, "Attempt to retrieve data from a non-existent row\0" }
  6882. , { SYBEREAD, EXCOMM, "Read from the server failed\0" }
  6883. , { SYBERESP, EXPROGRAM, "Response function address passed to dbresponse must be non-NULL\0" }
  6884. , { SYBERPCS, EXINFO, "Must call dbrpcinit before dbrpcparam or dbrpcsend\0" }
  6885. , { SYBERPIL, EXPROGRAM, "It is illegal to pass -1 to dbrpcparam for the datalen of parameters which are of "
  6886. "type SYBCHAR, SYBVARCHAR, SYBBINARY, or SYBVARBINARY\0" }
  6887. , { SYBERPNA, EXNONFATAL, "The RPC facility is available only when using a server whose version number is 4.0 "
  6888. "or later\0" }
  6889. , { SYBERPND, EXPROGRAM, "Attempt to initiate a new Adaptive Server operation with results pending\0" }
  6890. , { SYBERPNULL, EXPROGRAM, "value parameter for dbrpcparam can be NULL, only if the datalen parameter is 0\0" }
  6891. , { SYBERPTXTIM, EXPROGRAM, "RPC parameters cannot be of type text or image\0" }
  6892. , { SYBERPUL, EXPROGRAM, "When passing a SYBINTN, SYBDATETIMN, SYBMONEYN, or SYBFLTN parameter via "
  6893. "dbrpcparam, it is necessary to specify the parameter's maximum or actual length so "
  6894. "that DB-Library can recognize it as a SYINT1, SYBINT2, SYBINT4, SYBMONEY, SYBMONEY4, "
  6895. "and so on\0" }
  6896. , { SYBERTCC, EXPROGRAM, "dbreadtext may not be used to receive the results of a query that contains a "
  6897. "COMPUTE clause\0" }
  6898. , { SYBERTSC, EXPROGRAM, "dbreadtext may be used only to receive the results of a query that contains a "
  6899. "single result column\0" }
  6900. , { SYBERXID, EXNONFATAL, "The Server did not recognize our distributed-transaction ID\0" }
  6901. , { SYBESECURE, EXPROGRAM, "Secure SQL Server function not supported in this version\0" }
  6902. , { SYBESEFA, EXPROGRAM, "DBSETNOTIFS cannot be called if connections are present\0" }
  6903. , { SYBESEOF, EXCOMM, "Unexpected EOF from the server\0" }
  6904. , { SYBESFOV, EXPROGRAM, "International Release: dbsafestr overflowed its destination buffer\0" }
  6905. , { SYBESMSG, EXSERVER, "General Adaptive Server error: Check messages from the server\0" }
  6906. , { SYBESOCK, EXCOMM, "Unable to open socket\0" }
  6907. , { SYBESPID, EXPROGRAM, "Called dbspid with a NULL dbproc\0" }
  6908. , { SYBESYNC, EXCOMM, "Read attempted while out of synchronization with Adaptive Server\0" }
  6909. , { SYBETEXS, EXINFO, "Called dbmoretext with a bad size parameter\0" }
  6910. , { SYBETIME, EXTIME, "Adaptive Server connection timed out\0" }
  6911. , { SYBETMCF, EXPROGRAM, "Attempt to install too many custom formats via dbfmtinstall\0" }
  6912. , { SYBETMTD, EXPROGRAM, "Attempt to send too much TEXT data via the dbmoretext call\0" }
  6913. , { SYBETPAR, EXPROGRAM, "No SYBTEXT or SYBIMAGE parameters were defined\0" }
  6914. , { SYBETPTN, EXUSER, "Syntax error: only two periods are permitted in table names\0" }
  6915. , { SYBETRAC, EXINFO, "Attempted to turn off a trace flag that was not on\0" }
  6916. , { SYBETRAN, EXINFO, "DBPROCESS is being used for another transaction\0" }
  6917. , { SYBETRAS, EXINFO, "DB-Library internal error - trace structure not found\0" }
  6918. , { SYBETRSN, EXINFO, "Bad numbytes parameter passed to dbtracestring\0" }
  6919. , { SYBETSIT, EXINFO, "Attempt to call dbtsput with an invalid timestamp\0" }
  6920. , { SYBETTS, EXUSER, "The table which bulk copy is attempting to copy to a host file is shorter than the "
  6921. "number of rows which bulk copy was instructed to skip\0" }
  6922. , { SYBETYPE, EXINFO, "Invalid argument type given to Hyper/DB-Library\0" }
  6923. , { SYBEUCPT, EXUSER, "Unrecognized custom-format parameter-type encountered in dbstrbuild\0" }
  6924. , { SYBEUCRR, EXCONSISTENCY, "Internal software error: Unknown connection result reported by dbpasswd\0" }
  6925. , { SYBEUDTY, EXCONSISTENCY, "Unknown datatype encountered\0" }
  6926. , { SYBEUFDS, EXUSER, "Unrecognized format encountered in dbstrbuild\0" }
  6927. , { SYBEUFDT, EXCONSISTENCY, "Unknown fixed-length datatype encountered\0" }
  6928. , { SYBEUHST, EXUSER, "Unknown host machine name\0" }
  6929. , { SYBEUMSG, EXCOMM, "Unknown message-id in MSG datastream\0" }
  6930. , { SYBEUNAM, EXFATAL, "Unable to get current user name from operating system\0" }
  6931. , { SYBEUNOP, EXNONFATAL, "Unknown option passed to dbsetopt\0" }
  6932. , { SYBEUNT, EXUSER, "Unknown network type found in interface file\0" }
  6933. , { SYBEURCI, EXRESOURCE, "International Release: Unable to read copyright information from the DB-Library "
  6934. "localization file\0" }
  6935. , { SYBEUREI, EXRESOURCE, "International Release: Unable to read error information from the DB-Library "
  6936. "localization file\0" }
  6937. , { SYBEUREM, EXRESOURCE, "International Release: Unable to read error mnemonic from the DB-Library "
  6938. "localization file\0" }
  6939. , { SYBEURES, EXRESOURCE, "International Release: Unable to read error string from the DB-Library "
  6940. "localization file. 401 Error severities\0" }
  6941. , { SYBEURMI, EXRESOURCE, "International Release: Unable to read money-format information from the DB-Library "
  6942. "localization file\0" }
  6943. , { SYBEUSCT, EXCOMM, "Unable to set communications timer\0" }
  6944. , { SYBEUTDS, EXCOMM, "Unrecognized TDS version received from the server\0" }
  6945. , { SYBEUVBF, EXPROGRAM, "Attempt to read an unknown version of bcp format file\0" }
  6946. , { SYBEUVDT, EXCONSISTENCY, "Unknown variable-length datatype encountered\0" }
  6947. , { SYBEVDPT, EXUSER, "For bulk copy, all variable-length data must have either a length-prefix or a "
  6948. "terminator specified\0" }
  6949. , { SYBEWAID, EXCONSISTENCY, "DB-Library internal error: ALTFMT following ALTNAME has wrong id\0" }
  6950. , { SYBEWRIT, EXCOMM, "Write to the server failed\0" }
  6951. , { SYBEXOCI, EXNONFATAL, "International Release: A character-set translation overflowed its destination "
  6952. "buffer while using bcp to copy data from a host-file to the server\0" }
  6953. , { SYBEXTDN, EXPROGRAM, "Warning: the xlt_todisp parameter to dbfree_xlate was NULL. The space associated "
  6954. "with the xlt_tosrv parameter has been freed\0" }
  6955. , { SYBEXTN, EXPROGRAM, "The xlt_tosrv and xlt_todisp parameters to dbfree_xlate were NULL\0" }
  6956. , { SYBEXTSN, EXPROGRAM, "Warning: the xlt_tosrv parameter to dbfree_xlate was NULL. The space associated "
  6957. "with the xlt_todisp parameter has been freed\0" }
  6958. , { SYBEZTXT, EXINFO, "Attempt to send zero length TEXT or IMAGE to dataserver via dbwritetext\0" }
  6959. , { SYBECOLSIZE, EXINFO, "Invalid column information structure size\0" }
  6960. };
  6961. /** \internal
  6962. * \ingroup dblib_internal
  6963. * \brief Call client-installed error handler
  6964. *
  6965. * \param dbproc contains all information needed by db-lib to manage communications with the server.
  6966. * \param msgno identifies the error message to be passed to the client's handler.
  6967. * \param errnum identifies the OS error (errno), if any. Use 0 if not applicable.
  6968. * \returns the handler's return code, subject to correction and adjustment for vendor style:
  6969. * - INT_CANCEL The db-lib function that encountered the error will return FAIL.
  6970. * - INT_TIMEOUT The db-lib function will cancel the operation and return FAIL. \a dbproc remains useable.
  6971. * - INT_CONTINUE The db-lib function will retry the operation.
  6972. * \remarks
  6973. * The client-installed handler may also return INT_EXIT. If Sybase semantics are used, this function notifies
  6974. * the user and calls exit(3). If Microsoft semantics are used, this function returns INT_CANCEL.
  6975. *
  6976. * If the client-installed handler returns something other than these four INT_* values, or returns timeout-related
  6977. * value for anything but SYBETIME, it's treated here as INT_EXIT (see above).
  6978. *
  6979. * Instead of sprinkling error text all over db-lib, we consolidate it here,
  6980. * where it can be translated (one day), and where it can be mapped to the TDS error number.
  6981. * The libraries don't use consistent error numbers or messages, so when libtds has to emit
  6982. * an error message, it can't include the text. It can pass its error number to a client-library
  6983. * function, which will interpret it, add the text, call the application's installed handler
  6984. * (if any) and return the handler's return code back to the caller.
  6985. *
  6986. * The call stack may look something like this:
  6987. *
  6988. * -# application
  6989. * -# db-lib function (encounters error)
  6990. * -# dbperror
  6991. * -# error handler (installed by application)
  6992. *
  6993. * The error handling in this case is unambiguous: the caller invokes this function, the client's handler returns its
  6994. * instruction, which the caller receives. Quite often the caller will get INT_CANCEL, in which case it should put its
  6995. * house in order and return FAIL.
  6996. *
  6997. * The call stack may otherwise look something like this:
  6998. *
  6999. * -# application
  7000. * -# db-lib function
  7001. * -# libtds function (encounters error)
  7002. * -# _dblib_handle_err_message
  7003. * -# dbperror
  7004. * -# error handler (installed by application)
  7005. *
  7006. * Because different client libraries specify their handler semantics differently,
  7007. * and because libtds doesn't know which client library is in charge of any given connection, it cannot interpret the
  7008. * raw return code from a db-lib error handler. For these reasons,
  7009. * libtds calls _dblib_handle_err_message, which translates between libtds and db-lib semantics.
  7010. * \sa dberrhandle(), _dblib_handle_err_message().
  7011. */
  7012. int
  7013. dbperror (DBPROCESS *dbproc, DBINT msgno, long errnum, ...)
  7014. {
  7015. static const char int_exit_text[] = "FreeTDS: db-lib: exiting because client error handler returned %s for msgno %d\n";
  7016. static const char int_invalid_text[] = "%s (%d) received from client-installed error handler for nontimeout for error %d."
  7017. " Treating as INT_EXIT\n";
  7018. static const DBLIB_ERROR_MESSAGE default_message = { 0, EXCONSISTENCY, "unrecognized msgno" };
  7019. DBLIB_ERROR_MESSAGE constructed_message = { 0, EXCONSISTENCY, NULL };
  7020. const DBLIB_ERROR_MESSAGE *msg = &default_message;
  7021. int i, rc = INT_CANCEL;
  7022. const char *os_msgtext = strerror(errnum), *rc_name = "logic error";
  7023. char rc_buf[16];
  7024. tdsdump_log(TDS_DBG_FUNC, "dbperror(%p, %d, %ld)\n", dbproc, msgno, errnum); /* dbproc can be NULL */
  7025. #ifdef _WIN32
  7026. /*
  7027. * Unfortunately MingW uses the "old" msvcrt.dll (Visual C++ 2005 uses
  7028. * a newer version) which does not set errno when allocation functions
  7029. * cannot allocate memory, so we do it for them.
  7030. */
  7031. if (msgno == SYBEMEM)
  7032. errnum = ENOMEM;
  7033. #endif
  7034. if (os_msgtext == NULL)
  7035. os_msgtext = "no OS error";
  7036. assert(_dblib_err_handler != NULL); /* always installed by dbinit() or dberrhandle() */
  7037. /* look up the error message */
  7038. for (i=0; i < TDS_VECTOR_SIZE(dblib_error_messages); i++ ) {
  7039. if (dblib_error_messages[i].msgno == msgno) {
  7040. /*
  7041. * See if the message has placeholders. If so, build a message string on the heap.
  7042. * The presence of placeholders is indicated by the existence of a "string after the string",
  7043. * i.e., a format string (for dbstrbuild) after a null "terminator" in the message.
  7044. * On error -- can't allocate, can't build the string -- give up and call the client handler anyway.
  7045. */
  7046. const char * ptext = dblib_error_messages[i].msgtext;
  7047. const char * pformats = ptext + strlen(ptext) + 1;
  7048. msg = &dblib_error_messages[i];
  7049. assert(*(pformats - 1) == '\0');
  7050. if(*pformats != '\0') {
  7051. va_list ap;
  7052. int result_len, len = 2 * (int)strlen(ptext);
  7053. char * buffer = (char*) calloc(1, len);
  7054. if (buffer == NULL)
  7055. break;
  7056. va_start(ap, errnum);
  7057. rc = tds_vstrbuild(buffer, len, &result_len, ptext, TDS_NULLTERM, pformats, TDS_NULLTERM, ap);
  7058. buffer[result_len] = '\0';
  7059. va_end(ap);
  7060. if (TDS_FAILED(rc)) {
  7061. free(buffer);
  7062. break;
  7063. }
  7064. constructed_message.msgtext = buffer;
  7065. constructed_message.severity = msg->severity;
  7066. msg = &constructed_message;
  7067. }
  7068. break;
  7069. }
  7070. }
  7071. if (dbproc && dbproc->tds_socket && dbproc->tds_socket->login) {
  7072. DSTR server_name_dstr = dbproc->tds_socket->login->server_name;
  7073. if (!tds_dstr_isempty(&server_name_dstr)) {
  7074. char * buffer = NULL;
  7075. if (asprintf(&buffer, "%s (%s)", msg->msgtext,
  7076. tds_dstr_cstr(&server_name_dstr)) >= 0) {
  7077. free((char*) constructed_message.msgtext);
  7078. constructed_message.msgtext = buffer;
  7079. constructed_message.severity = msg->severity;
  7080. msg = &constructed_message;
  7081. }
  7082. }
  7083. }
  7084. tdsdump_log(TDS_DBG_FUNC, "dbperror: Calling dblib_err_handler with msgno = %d; msg->msgtext = \"%s\"\n",
  7085. msgno, msg->msgtext);
  7086. /* call the error handler */
  7087. rc = (*_dblib_err_handler)(dbproc, msg->severity, msgno, errnum, (char*) msg->msgtext, (char*) os_msgtext);
  7088. switch (rc) {
  7089. case INT_EXIT:
  7090. rc_name = "INT_EXIT";
  7091. break;
  7092. case INT_CONTINUE:
  7093. rc_name = "INT_CONTINUE";
  7094. break;
  7095. case INT_CANCEL:
  7096. rc_name = "INT_CANCEL";
  7097. break;
  7098. case INT_TIMEOUT:
  7099. rc_name = "INT_TIMEOUT";
  7100. break;
  7101. default:
  7102. rc_name = "invalid";
  7103. break;
  7104. }
  7105. tdsdump_log(TDS_DBG_FUNC, "dbperror: dblib_err_handler for msgno = %d; msg->msgtext = \"%s\" -- returns %d (%s)\n",
  7106. msgno, msg->msgtext, rc, rc_name);
  7107. /* we're done with the dynamic string now. */
  7108. free((char*) constructed_message.msgtext);
  7109. /* Timeout return codes are errors for non-timeout conditions. */
  7110. if (msgno != SYBETIME) {
  7111. switch (rc) {
  7112. case INT_CONTINUE:
  7113. tdsdump_log(TDS_DBG_SEVERE, int_invalid_text, "INT_CONTINUE", rc, msgno);
  7114. rc = INT_EXIT;
  7115. break;
  7116. case INT_TIMEOUT:
  7117. tdsdump_log(TDS_DBG_SEVERE, int_invalid_text, "INT_TIMEOUT", rc, msgno);
  7118. rc = INT_EXIT;
  7119. break;
  7120. default:
  7121. break;
  7122. }
  7123. }
  7124. /*
  7125. * Sybase exits on INT_EXIT; Microsoft converts to INT_CANCEL.
  7126. * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dblibc/dbc_pdc04c_6v39.asp
  7127. */
  7128. switch (rc) {
  7129. case INT_CONTINUE:
  7130. /* Microsoft does not define INT_TIMEOUT. Instead, two consecutive INT_CONTINUEs yield INT_CANCEL. */
  7131. if (dbproc && dbproc->msdblib && ++dbproc->ntimeouts >=2) {
  7132. dbproc->ntimeouts = 0;
  7133. rc = INT_CANCEL;
  7134. } /* fall through */
  7135. case INT_CANCEL:
  7136. case INT_TIMEOUT:
  7137. return rc; /* normal case */
  7138. break;
  7139. default:
  7140. sprintf(rc_buf, "%d", rc);
  7141. rc_name = rc_buf;
  7142. tdsdump_log(TDS_DBG_SEVERE, int_invalid_text, "Invalid return code", rc, msgno);
  7143. /* fall through */
  7144. case INT_EXIT:
  7145. if (dbproc && dbproc->msdblib) {
  7146. /* Microsoft behavior */
  7147. return INT_CANCEL;
  7148. }
  7149. fprintf(stderr, int_exit_text, rc_name, msgno);
  7150. tdsdump_log(TDS_DBG_SEVERE, int_exit_text, rc_name, msgno);
  7151. break;
  7152. }
  7153. exit(EXIT_FAILURE);
  7154. return rc; /* not reached */
  7155. }