PageRenderTime 59ms CodeModel.GetById 16ms RepoModel.GetById 1ms 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

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

  1. /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
  2. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
  3. * Copyright (C) 2006-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.

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