NCBI C++ ToolKit
dblib.c
Go to the documentation of this file.

Go to the SVN repository for this 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 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 
25 #include <freetds/time.h>
26 
27 #include <assert.h>
28 #include <stdio.h>
29 
30 #if HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif /* HAVE_STDLIB_H */
33 
34 #if HAVE_STRING_H
35 #include <string.h>
36 #endif /* HAVE_STRING_H */
37 
38 #if HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif /* HAVE_UNISTD_H */
41 
42 #if HAVE_ERRNO_H
43 # include <errno.h>
44 #endif /* HAVE_ERRNO_H */
45 
46 /**
47  * \ingroup dblib_core
48  * \remarks Either SYBDBLIB or MSDBLIB (not both) must be defined.
49  * This affects how certain application-addressable
50  * strucures are defined.
51  */
52 #include <freetds/tds.h>
53 #include <freetds/thread.h>
54 #include <freetds/convert.h>
55 #include <freetds/string.h>
56 #include <freetds/data.h>
57 #include <replacements.h>
58 #include <sybfront.h>
59 #include <sybdb.h>
60 #include <syberror.h>
61 #include <dblib.h>
62 
64 static BYTE *_dbcoldata(TDSCOLUMN *colinfo);
65 static int _get_printable_size(TDSCOLUMN * colinfo);
66 static char *_dbprdate(char *timestr);
67 static int _dbnullable(DBPROCESS * dbproc, int column);
68 static const char *tds_prdatatype(int datatype_token);
69 
70 static int default_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
71 
72 void copy_data_to_host_var(DBPROCESS *, TDS_SERVER_TYPE, const BYTE *, int, BYTE *, DBINT, int, DBINT *);
73 RETCODE dbgetnull(DBPROCESS *dbproc, int bindtype, int varlen, BYTE* varaddr);
74 
75 /**
76  * \file dblib.c
77  * Main implementation file for \c db-lib.
78  */
79 /**
80  * \file bcp.c
81  * Implementation of \c db-lib bulk copy functions.
82  */
83 /**
84  * \defgroup dblib_api The db-lib API
85  * Functions callable by \c db-lib client programs
86  *
87  * The \c db_lib interface is implemented by both Sybase and Microsoft. FreeTDS seeks to implement
88  * first the intersection of the functions defined by the vendors.
89  */
90 
91 /**
92  * \ingroup dblib_api
93  * \defgroup dblib_core Primary functions
94  * Core functions needed by most db-lib programs.
95 */
96 /**
97  * \ingroup dblib_api
98  * \defgroup dblib_rpc Remote Procedure functions
99  * Functions used with stored procedures.
100  * Especially useful for OUTPUT parameters, because modern Microsoft servers do not
101  * return output parameter data to the client unless the procedure was invoked
102  * with dbrpcsend().
103  */
104 /**
105  * \ingroup dblib_api
106  * \defgroup dblib_bcp Bulk copy functions
107  * Functions to bulk-copy (a/k/a \em bcp) data to/from the database.
108  */
109 /**
110  * \ingroup dblib_bcp
111  * \defgroup dblib_bcp_internal Internal bcp functions
112  * Static functions internal to the bcp library.
113  */
114 /**
115  * \ingroup dblib_api
116  * \defgroup dblib_money Money functions
117  * Functions to manipulate the MONEY datatype.
118  */
119 /**
120  * \ingroup dblib_api
121  * \defgroup dblib_datetime Datetime functions
122  * Functions to manipulate DBDATETIME structures. Defined by Sybase only.
123  * These are not implemented:
124  * - dbdate4cmp()
125  * - dbdate4zero()
126  * - dbdatechar()
127  * - dbdatename()
128  * - dbdateorder()
129  * - dbdatepart()
130  * - dbdatezero()
131  * - dbdayname()
132  */
133 /**
134  * \ingroup dblib_api
135  * \defgroup dblib_internal Internals
136  * Functions called within \c db-lib for self-help.
137  * These functions are of interest only to people hacking on the FreeTDS db-lib implementation.
138  */
139 /**
140  * \ingroup dblib_api
141  * \defgroup dblib_unimplemented Unimplemented
142  * Functions thus far not implemented in the FreeTDS db-lib implementation.
143  * While some of these are simply awaiting someone with time and skill (and inclination)
144  * it might be noted here that the old browse functions (e.g. dbcolbrowse())
145  * are on the never-to-do list.
146  * They were defined by Sybase and were superseded long ago, although they're still
147  * present in Microsoft's implementation.
148  * They were never popular and today better alternatives are available.
149  * For completeness, they are:
150  * - dbcolbrowse()
151  * - dbcolsource()
152  * - dbfreequal()
153  * - dbqual()
154  * - dbtabbrowse()
155  * - dbtabcount()
156  * - dbtabname()
157  * - dbtabsource()
158  * - dbtsnewlen()
159  * - dbtsnewval()
160  * - dbtsput()
161  */
162 
163 /* info/err message handler functions (or rather pointers to them) */
166 
167 /** \internal
168  * \dblib_internal
169  * \remarks A db-lib connection has an implicit TDS context.
170  */
171 typedef struct dblib_context
172 {
173  /** reference count, time dbinit called */
175 
176  /** libTDS context */
178  /** libTDS context reference counter */
180 
181  /* save all connection in a list */
187  int login_timeout; /**< not used unless positive */
188  int query_timeout; /**< not used unless positive */
189 }
191 
193 #ifdef TDS_HAVE_MUTEX
194 static tds_mutex dblib_mutex = TDS_MUTEX_INITIALIZER;
195 #endif
196 
197 static int g_dblib_version =
198 #ifdef TDS42
199  DBVERSION_42;
200 #elif TDS50
202 #elif TDS46
203  DBVERSION_46;
204 #elif TDS70
205  DBVERSION_70;
206 #elif TDS71
207  DBVERSION_71;
208 #elif TDS72
209  DBVERSION_72;
210 #elif TDS73
211  DBVERSION_73;
212 #elif TDS74
213  DBVERSION_74;
214 #else
216 #endif
217 static int g_dbsetversion_called = 0;
218 
219 
220 static int
222 {
223  int i = 0;
224  const int list_size = ctx->connection_list_size_represented;
225 
226  tdsdump_log(TDS_DBG_FUNC, "dblib_add_connection(%p, %p)\n", ctx, tds);
227 
228  while (i < list_size && ctx->connection_list[i])
229  i++;
230  if (i == list_size) {
231  dbperror((DBPROCESS *) tds_get_parent(tds), 50001, 0);
232  return 1;
233  } else {
234  ctx->connection_list[i] = tds;
235  return 0;
236  }
237 }
238 
239 static void
241 {
242  int i = 0;
243  const int list_size = ctx->connection_list_size;
244 
245  tdsdump_log(TDS_DBG_FUNC, "dblib_del_connection(%p, %p)\n", ctx, tds);
246 
247  while (i < list_size && ctx->connection_list[i] != tds)
248  i++;
249  if (i == list_size) {
250  /* connection wasn't on the free list...now what */
251  } else {
252  /* remove it */
253  ctx->connection_list[i] = NULL;
254  }
255 }
256 
257 static TDSCONTEXT*
259 {
260  tdsdump_log(TDS_DBG_FUNC, "dblib_get_tds_ctx(void)\n");
261 
262  tds_mutex_lock(&dblib_mutex);
264  if (g_dblib_ctx.tds_ctx == NULL) {
266 
267  /*
268  * Set the functions in the TDS layer to point to the correct handler functions
269  */
273 
275  /* set default in case there's no locale file */
276  const static char date_format[] =
277 #ifndef _WIN32
278  "%b %e %Y %I:%M:%S:%z%p";
279 #else
280  "%b %d %Y %I:%M:%S:%z%p";
281 #endif
282  g_dblib_ctx.tds_ctx->locale->date_fmt = strdup(date_format);
283  }
284  }
285  tds_mutex_unlock(&dblib_mutex);
286  return g_dblib_ctx.tds_ctx;
287 }
288 
289 static void
291 {
292  tdsdump_log(TDS_DBG_FUNC, "dblib_release_tds_ctx(%d)\n", count);
293 
294  tds_mutex_lock(&dblib_mutex);
296  if (g_dblib_ctx.tds_ctx_ref_count <= 0) {
299  }
300  tds_mutex_unlock(&dblib_mutex);
301 }
302 
303 #include "buffering.h"
304 
305 static void
306 db_env_chg(TDSSOCKET * tds, int type, char *oldval, char *newval)
307 {
308  DBPROCESS *dbproc;
309 
310  assert(oldval != NULL && newval != NULL);
311  if (strlen(oldval) == 1 && *oldval == 1)
312  oldval = "(0x1)";
313 
314  tdsdump_log(TDS_DBG_FUNC, "db_env_chg(%p, %d, %s, %s)\n", tds, type, oldval, newval);
315 
316  if (!tds || !tds_get_parent(tds))
317  return;
319 
320  dbproc->envchange_rcv |= (1 << (type - 1));
321  switch (type) {
322  case TDS_ENV_DATABASE:
323  strlcpy(dbproc->dbcurdb, newval, sizeof(dbproc->dbcurdb));
324  break;
325  case TDS_ENV_CHARSET:
326  strlcpy(dbproc->servcharset, newval, sizeof(dbproc->servcharset));
327  break;
328  default:
329  break;
330  }
331  return;
332 }
333 
334 /** \internal
335  * \ingroup dblib_internal
336  * \brief Sanity checks for column-oriented functions.
337  *
338  * \param dbproc contains all information needed by db-lib to manage communications with the server.
339  * \param pcolinfo address of pointer to a TDSCOLUMN structure.
340  * \remarks Makes sure dbproc and the requested column are valid.
341  * Calls dbperror() if not.
342  * \returns appropriate error or SUCCEED
343  */
344 static TDSCOLUMN*
346 {
347  if (!dbproc) {
348  dbperror(dbproc, SYBENULL, 0);
349  return NULL;
350  }
351  if (IS_TDSDEAD(dbproc->tds_socket)) {
352  dbperror(dbproc, SYBEDDNE, 0);
353  return NULL;
354  }
355  if (!dbproc->tds_socket->res_info)
356  return NULL;
357  if (column < 1 || column > dbproc->tds_socket->res_info->num_cols) {
358  dbperror(dbproc, SYBECNOR, 0);
359  return NULL;
360  }
361 
362  return dbproc->tds_socket->res_info->columns[column - 1];
363 }
364 
365 static TDSCOLUMN*
366 dbacolptr(DBPROCESS* dbproc, int computeid, int column, int is_bind)
367 {
368  TDS_UINT i;
369  TDSSOCKET *tds;
371 
372  if (!dbproc) {
373  dbperror(dbproc, SYBENULL, 0);
374  return NULL;
375  }
376  tds = dbproc->tds_socket;
377  if (IS_TDSDEAD(tds)) {
378  dbperror(dbproc, SYBEDDNE, 0);
379  return NULL;
380  }
381  for (i = 0;; ++i) {
382  if (i >= tds->num_comp_info) {
383  /* Attempt to bind user variable to a non-existent compute row */
384  if (is_bind)
385  dbperror(dbproc, SYBEBNCR, 0);
386  return NULL;
387  }
388  info = tds->comp_info[i];
389  if (info->computeid == computeid)
390  break;
391  }
392  /* Fail if either the compute id or the column number is invalid. */
393  if (column < 1 || column > info->num_cols) {
394  dbperror(dbproc, is_bind ? SYBEABNC : SYBECNOR, 0);
395  return NULL;
396  }
397 
398  return info->columns[column - 1];
399 }
400 
401 /*
402  * Default null substitution values
403  * Binding Type Null Substitution Value
404  * TINYBIND 0
405  * SMALLBIND 0
406  * INTBIND 0
407  * CHARBIND Empty string (padded with blanks)
408  * STRINGBIND Empty string (padded with blanks, null-terminated)
409  * NTBSTRINGBIND Empty string (null-terminated)
410  * VARYCHARBIND Empty string
411  * BINARYBIND Empty array (padded with zeros)
412  * VARYBINBIND Empty array
413  * DATETIMEBIND 8 bytes of zeros
414  * SMALLDATETIMEBIND 8 bytes of zeros
415  * MONEYBIND $0.00
416  * SMALLMONEYBIND $0.00
417  * FLT8BIND 0.0
418  * REALBIND 0.0
419  * DECIMALBIND 0.0 (with default scale and precision)
420  * NUMERICBIND 0.0 (with default scale and precision)
421  * BOUNDARYBIND Empty string (null-terminated)
422  * SENSITIVITYBIND Empty string (null-terminated)
423  */
424 
425 static const DBBIT null_BIT = 0;
426 static const DBTINYINT null_TINYINT = 0;
427 static const DBSMALLINT null_SMALLINT = 0;
428 static const DBINT null_INT = 0;
429 static const DBBIGINT null_BIGINT = 0;
430 static const DBFLT8 null_FLT8 = 0;
431 static const DBREAL null_REAL = 0;
432 
433 static const DBCHAR null_CHAR = '\0';
434 static const DBVARYCHAR null_VARYCHAR = { 0, {0} };
435 /* static const DBBINARY null_BINARY = 0; */
436 
437 static const DBDATETIME null_DATETIME = { 0, 0 };
438 static const DBDATETIME4 null_SMALLDATETIME = { 0, 0 };
439 static const DBMONEY null_MONEY = { 0, 0 };
440 static const DBMONEY4 null_SMALLMONEY = {0};
441 static const DBNUMERIC null_NUMERIC = { 0, 0, {0} };
442 static const TDS_DATETIMEALL null_DATETIMEALL = { 0, 0, 0, 0 };
443 
445  /* CHARBIND 0 */ { NULL, 0 }
446  /* STRINGBIND 1 */ , { NULL, 0 }
447  /* NTBSTRINGBIND 2 */ , { (BYTE*) &null_CHAR, sizeof(null_CHAR) }
448  /* VARYCHARBIND 3 */ , { (BYTE*) &null_VARYCHAR, sizeof(null_VARYCHAR) }
449  /* VARYBINBIND 4 */ , { (BYTE*) &null_VARYCHAR, sizeof(null_VARYCHAR) }
450  /* no such bind 5 */ , { NULL, 0 }
451  /* TINYBIND 6 */ , { &null_TINYINT, sizeof(null_TINYINT) }
452  /* SMALLBIND 7 */ , { (BYTE*) &null_SMALLINT, sizeof(null_SMALLINT) }
453  /* INTBIND 8 */ , { (BYTE*) &null_INT, sizeof(null_INT) }
454  /* FLT8BIND 9 */ , { (BYTE*) &null_FLT8, sizeof(null_FLT8) }
455  /* REALBIND 10 */ , { (BYTE*) &null_REAL, sizeof(null_REAL) }
456  /* DATETIMEBIND 11 */ , { (BYTE*) &null_DATETIME, sizeof(null_DATETIME) }
457  /* SMALLDATETIMEBIND 12 */ , { (BYTE*) &null_SMALLDATETIME, sizeof(null_SMALLDATETIME) }
458  /* MONEYBIND 13 */ , { (BYTE*) &null_MONEY, sizeof(null_MONEY) }
459  /* SMALLMONEYBIND 14 */ , { (BYTE*) &null_SMALLMONEY, sizeof(null_SMALLMONEY) }
460  /* BINARYBIND 15 */ , { NULL, 0 }
461  /* BITBIND 16 */ , { &null_BIT, sizeof(null_BIT) }
462  /* NUMERICBIND 17 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
463  /* DECIMALBIND 18 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
464  /* SRCNUMERICBIND 19 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
465  /* SRCDECIMALBIND 20 */ , { (BYTE*) &null_NUMERIC, sizeof(null_NUMERIC) }
466  /* DATEBIND 21 */ , { (BYTE*) &null_INT, sizeof(null_INT) }
467  /* TIMEBIND 22 */ , { (BYTE*) &null_INT, sizeof(null_INT) }
468  /* BIGDATETIMEBIND 23 */ , { (BYTE*) &null_BIGINT, sizeof(null_BIGINT) }
469  /* BIGTIMEBIND 24 */ , { (BYTE*) &null_BIGINT, sizeof(null_BIGINT) }
470  /* 25 */ , { NULL, 0 }
471  /* 26 */ , { NULL, 0 }
472  /* 27 */ , { NULL, 0 }
473  /* 28 */ , { NULL, 0 }
474  /* 29 */ , { NULL, 0 }
475  /* BIGINTBIND 30 */ , { (BYTE*) &null_BIGINT, sizeof(null_BIGINT) }
476  /* DATETIME2BIND 31 */ , { (BYTE*) &null_DATETIMEALL, sizeof(null_DATETIMEALL) }
477  /* MAXBINDTYPES 32 */
478 };
479 
480 static int
481 dbbindtype(int datatype)
482 {
483  switch (datatype) {
484  case SYBIMAGE:
485  case SYBVARBINARY:
486  case SYBBINARY: return BINARYBIND;
487 
488  case SYBBIT: return BITBIND;
489 
490  case SYBTEXT:
491  case SYBVARCHAR:
492  case SYBCHAR: return NTBSTRINGBIND;
493 
494  case SYBDATETIME: return DATETIMEBIND;
495  case SYBDATETIME4: return SMALLDATETIMEBIND;
496 
497  case SYBDATE: return DATEBIND;
498  case SYBTIME: return TIMEBIND;
499 
500  case SYB5BIGDATETIME: return BIGDATETIMEBIND;
501  case SYB5BIGTIME: return BIGTIMEBIND;
502 
503  case SYBDECIMAL: return DECIMALBIND;
504  case SYBNUMERIC: return NUMERICBIND;
505 
506  case SYBFLT8: return FLT8BIND;
507  case SYBREAL: return REALBIND;
508 
509  case SYBINT1: return TINYBIND;
510  case SYBINT2: return SMALLBIND;
511  case SYBINT4: return INTBIND;
512  case SYBINT8: return BIGINTBIND;
513 
514  case SYBMONEY: return MONEYBIND;
515  case SYBMONEY4: return SMALLMONEYBIND;
516 
517  case SYBMSDATE:
518  case SYBMSTIME:
519  case SYBMSDATETIME2:
520  case SYBMSDATETIMEOFFSET:
521  return DATETIME2BIND;
522 
523  default:
524  assert(0 == "no such datatype");
525  }
526 
527  return 0;
528 }
529 
530 /** \internal
531  * dbbind() says: "Note that if varlen is 0, no padding takes place"
532  * dbgetnull() will not pad varaddr unless varlen is positive.
533  * Vartype Program Type Padding Terminator
534  * ------------------- -------------- -------------- ----------
535  * CHARBIND DBCHAR blanks none
536  * STRINGBIND DBCHAR blanks \0
537  * NTBSTRINGBIND DBCHAR none \0
538  * VARYCHARBIND DBVARYCHAR none none
539  * BOUNDARYBIND DBCHAR none \0
540  * SENSITIVITYBIND DBCHAR none \0
541  */
542 RETCODE
543 dbgetnull(DBPROCESS *dbproc, int bindtype, int varlen, BYTE* varaddr)
544 {
545  NULLREP *pnullrep = default_null_representations + bindtype;
546 
547  tdsdump_log(TDS_DBG_FUNC, "dbgetnull(%p, %d, %d, %p)\n", dbproc, bindtype, varlen, varaddr);
548 
549  CHECK_PARAMETER(varaddr, SYBENULL, FAIL);
550  CHECK_PARAMETER(0 <= bindtype && bindtype < MAXBINDTYPES, SYBEBTYP, FAIL);
551 
552  /* dbproc can be NULL */
553  if (NULL != dbproc) {
555  pnullrep = dbproc->nullreps + bindtype;
556  }
557 
558  /*
559  * Fixed types: ignore varlen
560  * Other types: ignore varlen if <= 0, else varlen must be >= pnullrep->len.
561  */
562  switch (bindtype) {
563  case DATETIMEBIND:
564  case DATETIME2BIND:
565  case DECIMALBIND:
566  case SRCDECIMALBIND:
567  case FLT8BIND:
568  case INTBIND:
569  case MONEYBIND:
570  case NUMERICBIND:
571  case SRCNUMERICBIND:
572  case REALBIND:
573  case SMALLBIND:
574  case SMALLDATETIMEBIND:
575  case SMALLMONEYBIND:
576  case TINYBIND:
577  case BIGINTBIND:
578  case BITBIND:
579  case TIMEBIND:
580  case DATEBIND:
581  case BIGDATETIMEBIND:
582  case BIGTIMEBIND:
583  memcpy(varaddr, pnullrep->bindval, pnullrep->len);
584  return SUCCEED;
585  case CHARBIND:
586  case STRINGBIND:
587  case NTBSTRINGBIND:
588  case BINARYBIND:
589  case VARYCHARBIND:
590  case VARYBINBIND:
591  if (pnullrep->bindval && (varlen <= 0 || (size_t)varlen >= pnullrep->len)) {
592  memcpy(varaddr, pnullrep->bindval, pnullrep->len);
593  }
594  break;
595  default:
596  dbperror(dbproc, SYBEBTYP, 0);
597  return FAIL;
598  }
599 
600  /*
601  * For variable-length types, nonpositive varlen indicates
602  * buffer is "big enough" but also not to pad.
603  * Apply terminator (if applicable) and go home.
604  */
605  if (varlen <= 0) {
606  varlen = pnullrep->len;
607  switch (bindtype) {
608  case STRINGBIND:
609  case NTBSTRINGBIND:
610  ++varlen;
611  break;
612 #if 0
613  case BOUNDARYBIND:
614  case SENSITIVITYBIND:
615 #endif
616  }
617  }
618 
619  if (varlen < (long)pnullrep->len) {
620  tdsdump_log(TDS_DBG_FUNC, "dbgetnull: error: not setting varaddr(%p) because %d < %lu\n",
621  varaddr, varlen, (unsigned long int) pnullrep->len);
622  return FAIL;
623  }
624 
625  tdsdump_log(TDS_DBG_FUNC, "varaddr(%p) varlen %d < %lu?\n",
626  varaddr, varlen, (unsigned long int) pnullrep->len);
627 
628  assert(varlen >= 0);
629 
630  /*
631  * CHARBIND Empty string (padded with blanks)
632  * STRINGBIND Empty string (padded with blanks, null-terminated)
633  * NTBSTRINGBIND Empty string (unpadded, null-terminated)
634  * BINARYBIND Empty array (padded with zeros)
635  */
636  varaddr += pnullrep->len;
637  varlen -= (int)pnullrep->len;
638  if (varlen > 0) {
639  switch (bindtype) {
640  case CHARBIND:
641  memset(varaddr, ' ', varlen);
642  break;
643  case STRINGBIND:
644  memset(varaddr, ' ', varlen);
645  varaddr[varlen-1] = '\0';
646  break;
647  case NTBSTRINGBIND:
648  varaddr[0] = '\0';
649  break;
650  case BINARYBIND:
651  memset(varaddr, 0, varlen);
652  break;
653  case VARYCHARBIND:
654  case VARYBINBIND:
655  break;
656  default:
657  assert(!"unknown bindtype");
658  }
659  }
660  return SUCCEED;
661 }
662 
663 /**
664  * \ingroup dblib_core
665  * \brief Initialize db-lib.
666  *
667  * \remarks Call this function before trying to use db-lib in any way.
668  * Allocates various internal structures and reads \c locales.conf (if any) to determine the default
669  * date format.
670  * \retval SUCCEED normal.
671  * \retval FAIL cannot allocate an array of \c TDS_MAX_CONN \c TDSSOCKET pointers.
672  */
673 RETCODE
674 dbinit(void)
675 {
677 
678  tds_mutex_lock(&dblib_mutex);
679 
680  tdsdump_log(TDS_DBG_FUNC, "dbinit(void)\n");
681 
682  if (++g_dblib_ctx.ref_count != 1) {
683  tds_mutex_unlock(&dblib_mutex);
684  return SUCCEED;
685  }
686  /*
687  * DBLIBCONTEXT stores a list of current connections so they may be closed with dbexit()
688  */
689 
692  tdsdump_log(TDS_DBG_FUNC, "dbinit: out of memory\n");
693  tds_mutex_unlock(&dblib_mutex);
694  return FAIL;
695  }
698 
701 
702  tds_mutex_unlock(&dblib_mutex);
703 
705 
706  return SUCCEED;
707 }
708 
709 /**
710  * \ingroup dblib_core
711  * \brief Allocate a \c LOGINREC structure.
712  *
713  * \remarks A \c LOGINREC structure is passed to \c dbopen() to create a connection to the database.
714  * Does not communicate to the server; interacts strictly with library.
715  * \retval NULL the \c LOGINREC cannot be allocated.
716  * \retval LOGINREC* to valid memory, otherwise.
717  */
718 LOGINREC *
719 dblogin(void)
720 {
721  LOGINREC *loginrec;
722 
723  tdsdump_log(TDS_DBG_FUNC, "dblogin(void)\n");
724 
725  if ((loginrec = tds_new(LOGINREC, 1)) == NULL) {
726  dbperror(NULL, SYBEMEM, errno);
727  return NULL;
728  }
729  if ((loginrec->tds_login = tds_alloc_login(1)) == NULL) {
730  dbperror(NULL, SYBEMEM, errno);
731  free(loginrec);
732  return NULL;
733  }
734 
735  /* set default values for loginrec */
736  if (!tds_set_library(loginrec->tds_login, "DB-Library")) {
737  dbperror(NULL, SYBEMEM, errno);
738  free(loginrec);
739  return NULL;
740  }
741 
742  return loginrec;
743 }
744 
745 /**
746  * \ingroup dblib_core
747  * \brief free the \c LOGINREC
748  *
749  */
750 void
752 {
753  tdsdump_log(TDS_DBG_FUNC, "dbloginfree(%p)\n", login);
754 
755  if (login) {
756  tds_free_login(login->tds_login);
758  }
759 }
760 
761 /** \internal
762  * \ingroup dblib_internal
763  * \brief Set the value of a string in a \c LOGINREC structure.
764  *
765  * Called by various macros to populate \a login.
766  * \param login the \c LOGINREC* to modify.
767  * \param value the value to set it to.
768  * \param which the field to set.
769  * \retval SUCCEED the value was set.
770  * \retval FAIL \c DBSETHID or other invalid \a which was tried.
771  */
772 RETCODE
773 dbsetlname(LOGINREC * login, const char *value, int which)
774 {
775  bool copy_ret;
776  const char *value_nonull = value ? value : "";
777 
778  tdsdump_log(TDS_DBG_FUNC, "dbsetlname(%p, %s, %d)\n", login, value, which);
779 
780  if (login == NULL) {
781  dbperror(NULL, SYBEASNL, 0);
782  return FAIL;
783  }
784 
785  if (TDS_MAX_LOGIN_STR_SZ < strlen(value_nonull)) {
786  dbperror(NULL, SYBENTLL, 0);
787  return FAIL;
788  }
789 
790  switch (which) {
791  case DBSETHOST:
792  copy_ret = tds_set_host(login->tds_login, value_nonull);
793  break;
794  case DBSETUSER:
795  copy_ret = tds_set_user(login->tds_login, value_nonull);
796  break;
797  case DBSETPWD:
798  copy_ret = tds_set_passwd(login->tds_login, value_nonull);
799  break;
800  case DBSETAPP:
801  copy_ret = tds_set_app(login->tds_login, value_nonull);
802  break;
803  case DBSETCHARSET:
804  /* TODO NULL == no conversion desired */
805  copy_ret = tds_set_client_charset(login->tds_login, value_nonull);
806  break;
807  case DBSETNATLANG:
808  copy_ret = tds_set_language(login->tds_login, value_nonull);
809  break;
810  case DBSETDBNAME:
811  copy_ret = !!tds_dstr_copy(&login->tds_login->database, value_nonull);
812  break;
813  default:
814  dbperror(NULL, SYBEASUL, 0); /* Attempt to set unknown LOGINREC field */
815  return FAIL;
816  break;
817  }
818 
819  if (!copy_ret)
820  return FAIL;
821  return SUCCEED;
822 }
823 
824 /** \internal
825  * \ingroup dblib_internal
826  * \brief Set an integer value in a \c LOGINREC structure.
827  *
828  * Called by various macros to populate \a login.
829  * \param login the \c LOGINREC* to modify.
830  * \param value the value to set it to.
831  * \param which the field to set.
832  * \retval SUCCEED the value was set.
833  * \retval FAIL anything other than \c DBSETPACKET was passed for \a which.
834  */
835 RETCODE
836 dbsetllong(LOGINREC * login, long value, int which)
837 {
838  tdsdump_log(TDS_DBG_FUNC, "dbsetllong(%p, %ld, %d)\n", login, value, which);
839 
840  if( login == NULL ) {
841  dbperror(NULL, SYBEASNL, 0);
842  return FAIL;
843  }
844 
845  switch (which) {
846  case DBSETPACKET:
847  if (0 <= value && value <= 999999) {
848  tds_set_packet(login->tds_login, (int) value);
849  return SUCCEED;
850  }
851  dbperror(0, SYBEBADPK, 0, (int) value, (int) login->tds_login->block_size);
852  return FAIL;
853  break;
854  default:
855  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetllong() which = %d\n", which);
856  return FAIL;
857  break;
858  }
859 }
860 
861 #if defined(DBLIB_UNIMPLEMENTED)
862 /** \internal
863  * \ingroup dblib_internal
864  * \brief Set an integer value in a \c LOGINREC structure.
865  *
866  * Called by various macros to populate \a login.
867  * \param login the \c LOGINREC* to modify.
868  * \param value the value to set it to.
869  * \param which the field to set.
870  * \retval SUCCEED the value was set.
871  * \retval FAIL anything other than \c DBSETHIER was passed for \a which.
872  */
873 RETCODE
874 dbsetlshort(LOGINREC * login, int value, int which)
875 {
876  tdsdump_log(TDS_DBG_FUNC, "dbsetlshort(%p, %d, %d)\n", login, value, which);
877 
878  if( login == NULL ) {
879  dbperror(NULL, SYBEASNL, 0);
880  return FAIL;
881  }
882 
883  switch (which) {
884  case DBSETHIER:
885  default:
886  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetlshort() which = %d\n", which);
887  return FAIL;
888  break;
889  }
890 }
891 #endif
892 
893 /** \internal
894  * \ingroup dblib_internal
895  * \brief Set a boolean value in a \c LOGINREC structure.
896  *
897  * Called by various macros to populate \a login.
898  * \param login the \c LOGINREC* to modify.
899  * \param value the value to set it to.
900  * \param which the field to set.
901  * \remark Only DBSETBCP is implemented.
902  * \retval SUCCEED the value was set.
903  * \retval FAIL invalid value passed for \a which.
904  * \todo DBSETNOSHORT, DBSETENCRYPT, DBSETLABELED
905  */
906 RETCODE
907 dbsetlbool(LOGINREC * login, int value, int which)
908 {
909  tdsdump_log(TDS_DBG_FUNC, "dbsetlbool(%p, %d, %d)\n", login, value, which);
910 
911  if( login == NULL ) {
912  dbperror(NULL, SYBEASNL, 0);
913  return FAIL;
914  }
915 
916  switch (which) {
917  case DBSETBCP:
918  tds_set_bulk(login->tds_login, (TDS_TINYINT) value);
919  return SUCCEED;
920  break;
921  case DBSETUTF16:
922  login->tds_login->use_utf16 = (value != 0);
923  return SUCCEED;
924  case DBSETNTLMV2:
925  login->tds_login->use_ntlmv2 = (value != 0);
926  return SUCCEED;
927  case DBSETREADONLY:
928  login->tds_login->readonly_intent = (value != 0);
929  return SUCCEED;
930  case DBSETENCRYPT:
931  case DBSETLABELED:
932  default:
933  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetlbool() which = %d\n", which);
934  return FAIL;
935  break;
936  }
937 }
938 
939 /**
940  * \ingroup dblib_core
941  * \brief Set TDS version for future connections
942  *
943  */
944 RETCODE
946 {
947  tdsdump_log(TDS_DBG_FUNC, "dbsetlversion(%p, %x)\n", login, version);
948 
949  if( login == NULL ) {
950  dbperror(NULL, SYBEASNL, 0);
951  return FAIL;
952  }
953 
954  assert(login->tds_login != NULL);
955 
956  switch (version) {
957  case DBVER42:
958  login->tds_login->tds_version = 0x402;
959  return SUCCEED;
960  case DBVER60:
961  login->tds_login->tds_version = 0x700;
962  return SUCCEED;
963  case DBVERSION_100:
964  tds_set_version(login->tds_login, 5, 0);
965  return SUCCEED;
966  case DBVERSION_71:
967  tds_set_version(login->tds_login, 7, 1);
968  return SUCCEED;
969  case DBVERSION_72:
970  tds_set_version(login->tds_login, 7, 2);
971  return SUCCEED;
972  case DBVERSION_73:
973  tds_set_version(login->tds_login, 7, 3);
974  return SUCCEED;
975  case DBVERSION_74:
976  tds_set_version(login->tds_login, 7, 4);
977  return SUCCEED;
978  }
979 
980  return FAIL;
981 }
982 
983 static void
985 {
986  DBSTRING *curr, *next;
987  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_free(%p)\n", dbstrp); */
988 
989  if (!dbstrp)
990  return;
991 
992  curr = *dbstrp;
993  *dbstrp = NULL;
994  for (; curr; ) {
995  next = curr->strnext;
996  free(curr->strtext);
997  free(curr);
998  curr = next;
999  }
1000 }
1001 
1002 static RETCODE
1003 dbstring_concat(DBSTRING ** dbstrp, const char *p)
1004 {
1005  DBSTRING **strp = dbstrp;
1006 
1007  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_concat(%p, %s)\n", *dbstrp, p); */
1008 
1009  while (*strp != NULL) {
1010  strp = &((*strp)->strnext);
1011  }
1012  if ((*strp = tds_new(DBSTRING, 1)) == NULL) {
1013  dbperror(NULL, SYBEMEM, errno);
1014  return FAIL;
1015  }
1016  (*strp)->strtotlen = (DBINT)strlen(p);
1017  if (((*strp)->strtext = tds_new(BYTE, (*strp)->strtotlen)) == NULL) {
1018  TDS_ZERO_FREE(*strp);
1019  dbperror(NULL, SYBEMEM, errno);
1020  return FAIL;
1021  }
1022  memcpy((*strp)->strtext, p, (*strp)->strtotlen);
1023  (*strp)->strnext = NULL;
1024  return SUCCEED;
1025 }
1026 
1027 static RETCODE
1028 dbstring_assign(DBSTRING ** dbstrp, const char *p)
1029 {
1030  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_assign(%p, %s)\n", *dbstrp, p); */
1031 
1032  dbstring_free(dbstrp);
1033  return dbstring_concat(dbstrp, p);
1034 }
1035 
1036 static DBINT
1038 {
1039  DBINT len = 0;
1040  DBSTRING *next;
1041 
1042  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_length(%p)\n", dbstr); */
1043 
1044  for (next = dbstr; next != NULL; next = next->strnext) {
1045  len += next->strtotlen;
1046  }
1047  return len;
1048 }
1049 
1050 static int
1052 {
1053 
1054  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_getchar(%p, %d)\n", dbstr, i); */
1055 
1056  if (dbstr == NULL) {
1057  return -1;
1058  }
1059  if (i < 0) {
1060  return -1;
1061  }
1062  if (i < dbstr->strtotlen) {
1063  return dbstr->strtext[i];
1064  }
1065  return dbstring_getchar(dbstr->strnext, i - dbstr->strtotlen);
1066 }
1067 
1068 static char *
1070 {
1071  DBSTRING *next;
1072  int len;
1073  char *ret;
1074  char *cp;
1075 
1076  /* tdsdump_log(TDS_DBG_FUNC, "dbstring_get(%p)\n", dbstr); */
1077 
1078  if (dbstr == NULL) {
1079  return NULL;
1080  }
1081  len = dbstring_length(dbstr);
1082  if ((ret = tds_new(char, len + 1)) == NULL) {
1083  dbperror(NULL, SYBEMEM, errno);
1084  return NULL;
1085  }
1086  cp = ret;
1087  for (next = dbstr; next != NULL; next = next->strnext) {
1088  memcpy(cp, next->strtext, next->strtotlen);
1089  cp += next->strtotlen;
1090  }
1091  *cp = '\0';
1092  return ret;
1093 }
1094 
1095 static const char *const opttext[DBNUMOPTIONS] = {
1096  "parseonly",
1097  "estimate",
1098  "showplan",
1099  "noexec",
1100  "arithignore",
1101  "nocount",
1102  "arithabort",
1103  "textlimit",
1104  "browse",
1105  "offsets",
1106  "statistics",
1107  "errlvl",
1108  "confirm",
1109  "spid",
1110  "buffer",
1111  "noautofree",
1112  "rowcount",
1113  "textsize",
1114  "language",
1115  "dateformat",
1116  "prpad",
1117  "prcolsep",
1118  "prlinelen",
1119  "prlinesep",
1120  "lfconvert",
1121  "datefirst",
1122  "chained",
1123  "fipsflagger",
1124  "transaction isolation level",
1125  "auth",
1126  "identity_insert",
1127  "no_identity_column",
1128  "cnv_date2char_short",
1129  "client cursors",
1130  "set time",
1131  "quoted_identifier"
1132 };
1133 
1134 static DBOPTION *
1136 {
1137  DBOPTION *dbopts;
1138  int i;
1139 
1140  if ((dbopts = tds_new0(DBOPTION, DBNUMOPTIONS)) == NULL) {
1141  dbperror(NULL, SYBEMEM, errno);
1142  return NULL;
1143  }
1144  for (i = 0; i < DBNUMOPTIONS; i++) {
1145  dbopts[i].text = opttext[i];
1146  dbopts[i].param = NULL;
1147  dbopts[i].factive = FALSE;
1148  }
1149  dbstring_assign(&(dbopts[DBPRPAD].param), " ");
1150  dbstring_assign(&(dbopts[DBPRCOLSEP].param), " ");
1151  dbstring_assign(&(dbopts[DBPRLINELEN].param), "80");
1152  dbstring_assign(&(dbopts[DBPRLINESEP].param), "\n");
1153  dbstring_assign(&(dbopts[DBCLIENTCURSORS].param), " ");
1154  dbstring_assign(&(dbopts[DBSETTIME].param), " ");
1155  return dbopts;
1156 }
1157 
1158 /** \internal
1159  * \ingroup dblib_internal
1160  * \brief Form a connection with the server.
1161  *
1162  * Called by the \c dbopen() macro, normally. If FreeTDS was configured with \c --enable-msdblib, this
1163  * function is called by (exported) \c dbopen() function. \c tdsdbopen is so-named to avoid
1164  * namespace conflicts with other database libraries that use the same function name.
1165  * \param login \c LOGINREC* carrying the account information.
1166  * \param server name of the dataserver to connect to.
1167  * \return valid pointer on successful login.
1168  * \retval NULL insufficient memory, unable to connect for any reason.
1169  * \sa dbopen()
1170  * \todo use \c asprintf() to avoid buffer overflow.
1171  * \todo separate error messages for \em no-such-server and \em no-such-user.
1172  */
1173 DBPROCESS *
1174 tdsdbopen(LOGINREC * login, const char *server, int msdblib)
1175 {
1176  DBPROCESS *dbproc = NULL;
1177  TDSLOGIN *connection;
1178 
1179  char *tdsdump = getenv("TDSDUMP");
1180  if (tdsdump && *tdsdump) {
1181  tdsdump_open(tdsdump);
1182  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen(%p, %s, [%s])\n", login, server? server : "0x0", msdblib? "microsoft" : "sybase");
1183  }
1184 
1185  /*
1186  * Sybase supports the DSQUERY environment variable and falls back to "SYBASE" if server is NULL.
1187  * Microsoft uses a NULL or "" server to indicate a local server.
1188  * FIXME: support local server for win32.
1189  */
1190  if (!server && !msdblib) {
1191  if ((server = getenv("TDSQUERY")) == NULL)
1192  if ((server = getenv("DSQUERY")) == NULL)
1193  server = "SYBASE";
1194  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: servername set to %s\n", server);
1195  }
1196 
1197  if ((dbproc = tds_new0(DBPROCESS, 1)) == NULL) {
1198  dbperror(NULL, SYBEMEM, errno);
1199  return NULL;
1200  }
1201  dbproc->msdblib = msdblib;
1202 
1204  if (dbproc->dbopts == NULL) {
1205  free(dbproc);
1206  return NULL;
1207  }
1208  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: dbproc->dbopts = %p\n", dbproc->dbopts);
1209 
1210  dbproc->dboptcmd = NULL;
1211  dbproc->avail_flag = TRUE;
1213 
1214  if (!tds_set_server(login->tds_login, server)) {
1215  dbperror(NULL, SYBEMEM, 0);
1216  free(dbproc);
1217  return NULL;
1218  }
1219  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: tds_set_server(%p, \"%s\")\n", login->tds_login, server);
1220 
1222  dbperror(NULL, SYBEMEM, 0);
1223  free(dbproc);
1224  return NULL;
1225  }
1226 
1227 
1229 
1231  dbproc->envchange_rcv = 0;
1232 
1233  dbproc->dbcurdb[0] = '\0';
1234  dbproc->servcharset[0] = '\0';
1235 
1236  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: About to call tds_read_config_info...\n");
1237 
1238  connection = tds_read_config_info(dbproc->tds_socket, login->tds_login, g_dblib_ctx.tds_ctx->locale);
1239  if (!connection) {
1240  dbclose(dbproc);
1241  return NULL;
1242  }
1243  connection->option_flag2 &= ~TDS_ODBC_ON; /* we're not an ODBC driver */
1244  tds_fix_login(connection); /* initialize from Environment variables */
1245 
1246  dbproc->chkintr = NULL;
1247  dbproc->hndlintr = NULL;
1248 
1249  tds_mutex_lock(&dblib_mutex);
1250 
1251  /* override connection timeout if dbsetlogintime() was called */
1252  if (g_dblib_ctx.login_timeout > 0) {
1254  }
1255 
1256  /* override query timeout if dbsettime() was called */
1257  if (g_dblib_ctx.query_timeout > 0) {
1258  connection->query_timeout = g_dblib_ctx.query_timeout;
1259  }
1260 
1261  /* override TDS version if dbsetversion() was called */
1262  if (g_dbsetversion_called) {
1263  switch (g_dblib_version) {
1264  case DBVERSION_42: connection->tds_version=0x402; break;
1265  case DBVERSION_46: connection->tds_version=0x406; break;
1266  case DBVERSION_100: connection->tds_version=0x500; break;
1267  case DBVERSION_70: connection->tds_version=0x700; break;
1268  case DBVERSION_71: connection->tds_version=0x701; break;
1269  case DBVERSION_72: connection->tds_version=0x702; break;
1270  case DBVERSION_73: connection->tds_version=0x703; break;
1271  case DBVERSION_74: connection->tds_version=0x704; break;
1272  default: connection->tds_version=0; break;
1273  };
1274  }
1275 
1276  tds_mutex_unlock(&dblib_mutex);
1277 
1278  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: Calling tds_connect_and_login(%p, %p)\n",
1279  dbproc->tds_socket, connection);
1280 
1281  if (TDS_FAILED(tds_connect_and_login(dbproc->tds_socket, connection))) {
1282  tdsdump_log(TDS_DBG_ERROR, "tdsdbopen: tds_connect_and_login failed for \"%s\"!\n",
1283  tds_dstr_cstr(&connection->server_name));
1284  tds_free_login(connection);
1285  dbclose(dbproc);
1286  return NULL;
1287  }
1288  tds_free_login(connection);
1289 
1290  dbproc->dbbuf = NULL;
1291  dbproc->dbbufsz = 0;
1292 
1293  tds_mutex_lock(&dblib_mutex);
1295  tds_mutex_unlock(&dblib_mutex);
1296 
1297  /* set the DBBUFFER capacity to nil */
1299 
1300  tds_mutex_lock(&dblib_mutex);
1301 
1303  char *temp_filename = NULL;
1304  const int len = asprintf(&temp_filename, "%s.%d",
1306  if (len >= 0) {
1307  dbproc->ftos = fopen(temp_filename, "w");
1308  if (dbproc->ftos != NULL) {
1309  fprintf(dbproc->ftos, "/* dbopen() at %s */\n", _dbprdate(temp_filename));
1310  fflush(dbproc->ftos);
1312  }
1313  free(temp_filename);
1314  }
1315  }
1316 
1318 
1319  tds_mutex_unlock(&dblib_mutex);
1320 
1321  tdsdump_log(TDS_DBG_FUNC, "tdsdbopen: Returning dbproc = %p\n", dbproc);
1322 
1323  return dbproc;
1324 }
1325 
1326 /**
1327  * \ingroup dblib_core
1328  * \brief \c printf-like way to form SQL to send to the server.
1329  *
1330  * Forms a command string and writes to the command buffer with dbcmd().
1331  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1332  * \param fmt <tt> man vasprintf</tt> for details.
1333  * \retval SUCCEED success.
1334  * \retval FAIL insufficient memory, or dbcmd() failed.
1335  * \sa dbcmd(), dbfreebuf(), dbgetchar(), dbopen(), dbstrcpy(), dbstrlen().
1336  */
1337 RETCODE
1338 dbfcmd(DBPROCESS * dbproc, const char *fmt, ...)
1339 {
1340  va_list ap;
1341  char *s;
1342  int len;
1343  RETCODE ret;
1344 
1345  tdsdump_log(TDS_DBG_FUNC, "dbfcmd(%p, %s, ...)\n", dbproc, fmt);
1346  CHECK_CONN(FAIL);
1347  CHECK_NULP(fmt, "dbfcmd", 2, FAIL);
1348 
1349  va_start(ap, fmt);
1350  len = vasprintf(&s, fmt, ap);
1351  va_end(ap);
1352 
1353  if (len < 0) {
1354  dbperror(dbproc, SYBEMEM, errno);
1355  return FAIL;
1356  }
1357 
1358  ret = dbcmd(dbproc, s);
1359  free(s);
1360 
1361  return ret;
1362 }
1363 
1364 /**
1365  * \ingroup dblib_core
1366  * \brief \c Append SQL to the command buffer.
1367  *
1368  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1369  * \param cmdstring SQL to append to the command buffer.
1370  * \retval SUCCEED success.
1371  * \retval FAIL insufficient memory.
1372  * \remarks set command state to \c DBCMDPEND unless the command state is DBCMDSENT, in which case
1373  * it frees the command buffer. This latter may or may not be the Right Thing to do.
1374  * \sa dbfcmd(), dbfreebuf(), dbgetchar(), dbopen(), dbstrcpy(), dbstrlen().
1375  */
1376 RETCODE
1377 dbcmd(DBPROCESS * dbproc, const char cmdstring[])
1378 {
1379  size_t cmd_len, buf_len, newsz;
1380 
1381  tdsdump_log(TDS_DBG_FUNC, "dbcmd(%p, %s)\n", dbproc, cmdstring);
1382  CHECK_CONN(FAIL);
1383  CHECK_NULP(cmdstring, "dbcmd", 2, FAIL);
1384 
1385  dbproc->avail_flag = FALSE;
1386 
1387  tdsdump_log(TDS_DBG_FUNC, "dbcmd() bufsz = %d\n", dbproc->dbbufsz);
1388 
1389  if (dbproc->command_state == DBCMDSENT) {
1390  if (!dbproc->noautofree) {
1391  dbfreebuf(dbproc);
1392  }
1393  }
1394 
1395  buf_len = (dbproc->dbbufsz == 0) ? 0 : dbproc->dbbufsz - 1;
1396  cmd_len = strlen(cmdstring);
1397  newsz = buf_len + cmd_len + 1;
1398  if (newsz > 0x7fffffffu || !TDS_RESIZE(dbproc->dbbuf, newsz)) {
1399  dbperror(dbproc, SYBEMEM, errno);
1400  return FAIL;
1401  }
1402  memcpy(dbproc->dbbuf + buf_len, cmdstring, cmd_len);
1403  dbproc->dbbuf[newsz - 1] = 0;
1404  dbproc->dbbufsz = (int) newsz;
1405 
1407 
1408  return SUCCEED;
1409 }
1410 
1411 /**
1412  * \ingroup dblib_core
1413  * \brief send the SQL command to the server and wait for an answer.
1414  *
1415  * Please be patient. This function waits for the server to respond. \c dbsqlexec is equivalent
1416  * to dbsqlsend() followed by dbsqlok().
1417  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1418  * \retval SUCCEED query was processed without errors.
1419  * \retval FAIL was returned by dbsqlsend() or dbsqlok().
1420  * \sa dbcmd(), dbfcmd(), dbnextrow(), dbresults(), dbretstatus(), dbsettime(), dbsqlok(), dbsqlsend()
1421  */
1422 RETCODE
1424 {
1425  RETCODE rc = FAIL;
1426 
1427  tdsdump_log(TDS_DBG_FUNC, "dbsqlexec(%p)\n", dbproc);
1428  CHECK_CONN(FAIL);
1429 
1430  if (SUCCEED == (rc = dbsqlsend(dbproc))) {
1431  rc = dbsqlok(dbproc);
1432  }
1433  return rc;
1434 }
1435 
1436 /**
1437  * \ingroup dblib_core
1438  * \brief Change current database.
1439  *
1440  * Analagous to the unix command \c cd, dbuse() makes \a name the default database. Waits for an answer
1441  * from the server.
1442  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1443  * \param name database to use.
1444  * \retval SUCCEED query was processed without errors.
1445  * \retval FAIL query was not processed
1446  * \sa dbchange(), dbname().
1447  */
1448 RETCODE
1449 dbuse(DBPROCESS * dbproc, const char *name)
1450 {
1451  RETCODE rc;
1452  char *query;
1453 
1454  tdsdump_log(TDS_DBG_FUNC, "dbuse(%p, %s)\n", dbproc, name);
1455  CHECK_CONN(FAIL);
1456  CHECK_NULP(name, "dbuse", 2, FAIL);
1457 
1458  if (!dbproc->tds_socket)
1459  return FAIL;
1460 
1461  /* quote name */
1462  query = tds_new(char, tds_quote_id(dbproc->tds_socket, NULL, name, -1) + 6);
1463  if (!query) {
1464  dbperror(dbproc, SYBEMEM, errno);
1465  return FAIL;
1466  }
1467  strcpy(query, "use ");
1468  /* TODO PHP suggest to quote by yourself with []... what should I do ?? quote or not ?? */
1469  if (name[0] == '[' && name[strlen(name)-1] == ']')
1470  strcat(query, name);
1471  else
1472  tds_quote_id(dbproc->tds_socket, query + 4, name, -1);
1473 
1474  rc = SUCCEED;
1475  if ((dbcmd(dbproc, query) == FAIL)
1476  || (dbsqlexec(dbproc) == FAIL)
1477  || (dbresults(dbproc) == FAIL)
1478  || (dbcanquery(dbproc) == FAIL))
1479  rc = FAIL;
1480  free(query);
1481  return rc;
1482 }
1483 
1484 /**
1485  * \ingroup dblib_core
1486  * \brief Close a connection to the server and free associated resources.
1487  *
1488  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1489  * \sa dbexit(), dbopen().
1490  */
1491 void
1493 {
1494  TDSSOCKET *tds;
1495  int i;
1496  char timestr[256];
1497 
1498  tdsdump_log(TDS_DBG_FUNC, "dbclose(%p)\n", dbproc);
1500 
1501  tds = dbproc->tds_socket;
1502  if (tds) {
1503  /*
1504  * this MUST be done before socket destruction
1505  * it is possible that a TDSSOCKET is allocated on same position
1506  */
1507  tds_mutex_lock(&dblib_mutex);
1509  tds_mutex_unlock(&dblib_mutex);
1510 
1514  }
1515  buffer_free(&(dbproc->row_buf));
1516 
1517  if (dbproc->ftos != NULL) {
1518  fprintf(dbproc->ftos, "/* dbclose() at %s */\n", _dbprdate(timestr));
1519  fclose(dbproc->ftos);
1520  }
1521 
1523  if (dbproc->hostfileinfo) {
1527  for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
1530  }
1532  }
1533  }
1534 
1535  for (i = 0; i < DBNUMOPTIONS; i++) {
1537  }
1538  free(dbproc->dbopts);
1539 
1541 
1542  for (i=0; i < MAXBINDTYPES; i++) {
1545  }
1546 
1547  dbfreebuf(dbproc);
1548  free(dbproc);
1549 }
1550 
1551 /**
1552  * \ingroup dblib_core
1553  * \brief Close server connections and free all related structures.
1554  *
1555  * \sa dbclose(), dbinit(), dbopen().
1556  * \todo breaks if ctlib/dblib used in same process.
1557  */
1558 void
1560 {
1561  TDSSOCKET *tds;
1562  DBPROCESS *dbproc;
1563  int i, list_size, count = 1;
1564 
1565  tdsdump_log(TDS_DBG_FUNC, "dbexit(void)\n");
1566 
1567  tds_mutex_lock(&dblib_mutex);
1568 
1569  if (--g_dblib_ctx.ref_count != 0) {
1570  tds_mutex_unlock(&dblib_mutex);
1571  return;
1572  }
1573 
1574  list_size = g_dblib_ctx.connection_list_size;
1575 
1576  for (i = 0; i < list_size; i++) {
1579  if (tds) {
1580  ++count;
1584  if (dbproc) {
1585  /* avoid locking in dbclose */
1586  dbproc->tds_socket = NULL;
1587  dbclose(dbproc);
1588  }
1589  }
1590  }
1594  }
1595 
1596  tds_mutex_unlock(&dblib_mutex);
1597 
1598  dblib_release_tds_ctx(count);
1599 }
1600 
1601 typedef char prbuf_t[24];
1602 
1603 static const char *
1605 {
1606  switch(retcode) {
1607  case _DB_RES_INIT: return "_DB_RES_INIT";
1608  case _DB_RES_RESULTSET_EMPTY: return "_DB_RES_RESULTSET_EMPTY";
1609  case _DB_RES_RESULTSET_ROWS: return "_DB_RES_RESULTSET_ROWS";
1610  case _DB_RES_NEXT_RESULT: return "_DB_RES_NEXT_RESULT";
1611  case _DB_RES_NO_MORE_RESULTS: return "_DB_RES_NO_MORE_RESULTS";
1612  case _DB_RES_SUCCEED: return "_DB_RES_SUCCEED";
1613  default:
1614  sprintf(buf, "oops: %u ??", retcode);
1615  }
1616  return buf;
1617 }
1618 
1619 static const char *
1621 {
1622  switch(retcode) {
1623  case REG_ROW: return "REG_ROW/MORE_ROWS";
1624  case NO_MORE_ROWS: return "NO_MORE_ROWS";
1625  case BUF_FULL: return "BUF_FULL";
1626  case NO_MORE_RESULTS: return "NO_MORE_RESULTS";
1627  case SUCCEED: return "SUCCEED";
1628  case FAIL: return "FAIL";
1629  default:
1630  sprintf(buf, "oops: %u ??", retcode);
1631  }
1632  return buf;
1633 }
1634 
1635 static const char *
1636 prretcode(int retcode, prbuf_t buf)
1637 {
1638  switch(retcode) {
1639  case TDS_SUCCESS: return "TDS_SUCCESS";
1640  case TDS_FAIL: return "TDS_FAIL";
1641  case TDS_NO_MORE_RESULTS: return "TDS_NO_MORE_RESULTS";
1642  case TDS_CANCELLED: return "TDS_CANCELLED";
1643  default:
1644  sprintf(buf, "oops: %u ??", retcode);
1645  }
1646  return buf;
1647 }
1648 
1649 static const char *
1650 prresult_type(int result_type, prbuf_t buf)
1651 {
1652  switch(result_type) {
1653  case TDS_ROW_RESULT: return "TDS_ROW_RESULT";
1654  case TDS_PARAM_RESULT: return "TDS_PARAM_RESULT";
1655  case TDS_STATUS_RESULT: return "TDS_STATUS_RESULT";
1656  case TDS_MSG_RESULT: return "TDS_MSG_RESULT";
1657  case TDS_COMPUTE_RESULT: return "TDS_COMPUTE_RESULT";
1658  case TDS_CMD_DONE: return "TDS_CMD_DONE";
1659  case TDS_CMD_SUCCEED: return "TDS_CMD_SUCCEED";
1660  case TDS_CMD_FAIL: return "TDS_CMD_FAIL";
1661  case TDS_ROWFMT_RESULT: return "TDS_ROWFMT_RESULT";
1662  case TDS_COMPUTEFMT_RESULT: return "TDS_COMPUTEFMT_RESULT";
1663  case TDS_DESCRIBE_RESULT: return "TDS_DESCRIBE_RESULT";
1664  case TDS_DONE_RESULT: return "TDS_DONE_RESULT";
1665  case TDS_DONEPROC_RESULT: return "TDS_DONEPROC_RESULT";
1666  case TDS_DONEINPROC_RESULT: return "TDS_DONEINPROC_RESULT";
1667  case TDS_OTHERS_RESULT: return "TDS_OTHERS_RESULT";
1668  default:
1669  sprintf(buf, "oops: %u ??", result_type);
1670  }
1671  return buf;
1672 }
1673 
1674 /**
1675  * \ingroup dblib_core
1676  * \brief Set up query results.
1677  *
1678  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1679  * \retval SUCCEED Some results are available.
1680  * \retval FAIL query was not processed successfully by the server
1681  * \retval NO_MORE_RESULTS query produced no results.
1682  *
1683  * \remarks Call dbresults() after calling dbsqlexec() or dbsqlok(), or dbrpcsend() returns SUCCEED. Unless
1684  * one of them fails, dbresults will return either SUCCEED or NO_MORE_RESULTS.
1685  *
1686  * The meaning of \em results is very specific and not very intuitive. Results are created by either
1687  * - a SELECT statement
1688  * - a stored procedure
1689  *
1690  * When dbresults returns SUCCEED, therefore, it indicates the server processed the query successfully and
1691  * that one or more of these is present:
1692  * - metadata -- dbnumcols() returns 1 or more
1693  * - data -- dbnextrow() returns SUCCEED
1694  * - return status -- dbhasretstat() returns TRUE
1695  * - output parameters -- dbnumrets() returns 1 or more
1696  *
1697  * If none of the above are present, dbresults() returns NO_MORE_RESULTS.
1698  *
1699  * SUCCEED does not imply that DBROWS() will return TRUE or even that dbnumcols() will return nonzero.
1700  * A general algorithm for reading results will call dbresults() until it return NO_MORE_RESULTS (or FAIL).
1701  * An application should check for all the above kinds of results within the dbresults() loop.
1702  *
1703  * \sa dbsqlexec(), dbsqlok(), dbrpcsend(), dbcancel(), DBROWS(), dbnextrow(), dbnumcols(), dbhasretstat(), dbretstatus(), dbnumrets()
1704  */
1705 RETCODE
1707 {
1708  RETCODE erc = _dbresults(dbproc);
1709  prbuf_t buf;
1710 
1711  tdsdump_log(TDS_DBG_FUNC, "dbresults returning %d (%s)\n", erc, prdbretcode(erc, buf));
1712  return erc;
1713 }
1714 
1715 static RETCODE
1717 {
1718  TDSSOCKET *tds;
1719  int result_type = 0, done_flags;
1720  prbuf_t prbuf1, prbuf2;
1721 
1722  tdsdump_log(TDS_DBG_FUNC, "dbresults(%p)\n", dbproc);
1723  CHECK_CONN(FAIL);
1724 
1725  tds = dbproc->tds_socket;
1726 
1727  tdsdump_log(TDS_DBG_FUNC, "dbresults: dbresults_state is %d (%s)\n",
1729  switch ( dbproc->dbresults_state ) {
1730  case _DB_RES_SUCCEED:
1732  return SUCCEED;
1733  break;
1735  dbperror(dbproc, SYBERPND, 0); /* dbresults called while rows outstanding.... */
1736  return FAIL;
1737  break;
1739  return NO_MORE_RESULTS;
1740  break;
1741  default:
1742  break;
1743  }
1744 
1745  for (;;) {
1746  TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS);
1747 
1748  tdsdump_log(TDS_DBG_FUNC, "dbresults() tds_process_tokens returned %d (%s),\n\t\t\tresult_type %s\n",
1749  retcode, prretcode(retcode, prbuf1), prresult_type(result_type, prbuf2));
1750 
1751  switch (retcode) {
1752 
1753  case TDS_SUCCESS:
1754 
1755  switch (result_type) {
1756 
1757  case TDS_ROWFMT_RESULT:
1761  break;
1762 
1763  case TDS_COMPUTEFMT_RESULT:
1764  break;
1765 
1766  case TDS_ROW_RESULT:
1767  case TDS_COMPUTE_RESULT:
1768 
1770  return SUCCEED;
1771  break;
1772 
1773  case TDS_DONE_RESULT:
1774  case TDS_DONEPROC_RESULT:
1775  tdsdump_log(TDS_DBG_FUNC, "dbresults(): dbresults_state is %d (%s)\n",
1777 
1778  /* A done token signifies the end of a logical command.
1779  * There are three possibilities:
1780  * 1. Simple command with no result set, i.e. update, delete, insert
1781  * 2. Command with result set but no rows
1782  * 3. Command with result set and rows
1783  */
1784  switch (dbproc->dbresults_state) {
1785 
1786  case _DB_RES_INIT:
1787  case _DB_RES_NEXT_RESULT:
1789  if (done_flags & TDS_DONE_ERROR)
1790  return FAIL;
1791  if (result_type == TDS_DONE_RESULT)
1792  return SUCCEED;
1793  break;
1794 
1798  return SUCCEED;
1799  break;
1800  default:
1801  assert(0);
1802  break;
1803  }
1804  break;
1805 
1806  case TDS_DONEINPROC_RESULT:
1807  /*
1808  * Return SUCCEED on a command within a stored procedure
1809  * only if the command returned a result set.
1810  */
1811  switch (dbproc->dbresults_state) {
1812  case _DB_RES_INIT:
1813  case _DB_RES_NEXT_RESULT:
1815  break;
1817  case _DB_RES_RESULTSET_ROWS :
1819  return SUCCEED;
1820  break;
1822  case _DB_RES_SUCCEED:
1823  break;
1824  }
1825  break;
1826 
1827  case TDS_STATUS_RESULT:
1828  case TDS_MSG_RESULT:
1829  case TDS_DESCRIBE_RESULT:
1830  case TDS_PARAM_RESULT:
1831  default:
1832  break;
1833  }
1834 
1835  break;
1836 
1837  case TDS_NO_MORE_RESULTS:
1839  return NO_MORE_RESULTS;
1840  break;
1841 
1842  default:
1843  assert(TDS_FAILED(retcode));
1845  return FAIL;
1846  break;
1847  }
1848  }
1849 }
1850 
1851 
1852 /**
1853  * \ingroup dblib_core
1854  * \brief Return number of regular columns in a result set.
1855  *
1856  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1857  * \sa dbcollen(), dbcolname(), dbnumalts().
1858  */
1859 int
1861 {
1862  tdsdump_log(TDS_DBG_FUNC, "dbnumcols(%p)\n", dbproc);
1864 
1866  return dbproc->tds_socket->res_info->num_cols;
1867  return 0;
1868 }
1869 
1870 /**
1871  * \ingroup dblib_core
1872  * \brief Return name of a regular result column.
1873  *
1874  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1875  * \param column Nth in the result set, starting with 1.
1876  * \return pointer to ASCII null-terminated string, the name of the column.
1877  * \retval NULL \a column is not in range.
1878  * \sa dbcollen(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols().
1879  * \bug Relies on ASCII column names, post iconv conversion.
1880  * Will not work as described for UTF-8 or UCS-2 clients.
1881  * But maybe it shouldn't.
1882  */
1883 char *
1885 {
1886  TDSCOLUMN *colinfo;
1887 
1888  tdsdump_log(TDS_DBG_FUNC, "dbcolname(%p, %d)\n", dbproc, column);
1889 
1890  colinfo = dbcolptr(dbproc, column);
1891  if (!colinfo)
1892  return NULL;
1893 
1894  return tds_dstr_buf(&colinfo->column_name);
1895 }
1896 
1897 static
1898 const char *
1900 {
1901  TDSCOLUMN *colinfo;
1902 
1903  tdsdump_log(TDS_DBG_FUNC, "dbcoltablename(%p, %d)\n", dbproc, column);
1905 
1906  colinfo = dbcolptr(dbproc, column);
1907  if (!colinfo)
1908  return NULL;
1909 
1910  return tds_dstr_cstr(&colinfo->table_name);
1911 }
1912 
1913 /**
1914  * \ingroup dblib_core
1915  * \brief Read a row from the row buffer.
1916  *
1917  * When row buffering is enabled (DBBUFFER option is on), the client can use dbgetrow() to re-read a row previously fetched
1918  * with dbnextrow(). The effect is to move the row pointer -- analogous to fseek() -- back to \a row.
1919  * Calls to dbnextrow() read from \a row + 1 until the buffer is exhausted, at which point it resumes
1920  * its normal behavior, except that as each row is fetched from the server, it is added to the row
1921  * buffer (in addition to being returned to the client). When the buffer is filled, dbnextrow() returns
1922  * \c FAIL until the buffer is at least partially emptied with dbclrbuf().
1923  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1924  * \param row Nth row to read, starting with 1.
1925  * \retval REG_ROW returned row is a regular row.
1926  * \returns computeid when returned row is a compute row.
1927  * \retval NO_MORE_ROWS no such row in the row buffer. Current row is unchanged.
1928  * \retval FAIL unsuccessful; row buffer may be full.
1929  * \sa dbaltbind(), dbbind(), dbclrbuf(), DBCURROW(), DBFIRSTROW(), DBLASTROW(), dbnextrow(), dbsetrow().
1930  */
1931 RETCODE
1933 {
1934  RETCODE result = FAIL;
1935  const int idx = buffer_row2idx(&dbproc->row_buf, row);
1936 
1937  tdsdump_log(TDS_DBG_FUNC, "dbgetrow(%p, %d)\n", dbproc, row);
1938  CHECK_CONN(FAIL);
1939 
1940  if (-1 == idx)
1941  return NO_MORE_ROWS;
1942 
1943  dbproc->row_buf.current = idx;
1945  result = REG_ROW;
1946 
1947  return result;
1948 }
1949 
1950 /**
1951  * \ingroup dblib_core
1952  * \brief Define substitution values to be used when binding null values.
1953  *
1954  * \param dbproc contains all information needed by db-lib to manage communications with the server.
1955  * \param bindtype type of binding to which the substitute value will apply.
1956  * \param bindlen size of the substitute value you are supplying, in bytes.
1957  * Ignored except for CHARBIND and BINARYBIND.
1958  * \param bindval pointer to a buffer containing the substitute value.
1959  * \retval SUCCEED query was processed without errors.
1960  * \retval FAIL query was not processed
1961  * \sa dbaltbind(), dbbind(), dbconvert(), dbnullbind().
1962  */
1963 RETCODE
1964 dbsetnull(DBPROCESS * dbproc, int bindtype, int bindlen, BYTE *bindval)
1965 {
1966  BYTE *pval;
1967 
1968  tdsdump_log(TDS_DBG_FUNC, "dbsetnull(%p, %d, %d, %p)\n", dbproc, bindtype, bindlen, bindval);
1969 
1970  CHECK_CONN(FAIL);
1971  CHECK_PARAMETER(bindval, SYBENBVP, FAIL);
1972 
1973  switch (bindtype) {
1974  case DATETIMEBIND:
1975  case DECIMALBIND:
1976  case SRCDECIMALBIND:
1977  case FLT8BIND:
1978  case INTBIND:
1979  case MONEYBIND:
1980  case NUMERICBIND:
1981  case SRCNUMERICBIND:
1982  case REALBIND:
1983  case SMALLBIND:
1984  case SMALLDATETIMEBIND:
1985  case SMALLMONEYBIND:
1986  case TINYBIND:
1987  case BIGINTBIND:
1988  case DATEBIND:
1989  case TIMEBIND:
1990  case BIGDATETIMEBIND:
1991  case BIGTIMEBIND:
1992  bindlen = (int)default_null_representations[bindtype].len;
1993  break;
1994 
1995  case CHARBIND:
1996  case BINARYBIND:
1997  CHECK_PARAMETER(bindlen >= 0, SYBEBBL, FAIL);
1998  break;
1999 
2000  case NTBSTRINGBIND: bindlen = (int)strlen((char *) bindval);
2001  break;
2002  case STRINGBIND: bindlen = (int)strlen((char *) bindval);
2003  break;
2004  case VARYBINBIND: bindlen = ((DBVARYBIN*) bindval)->len;
2005  break;
2006  case VARYCHARBIND: bindlen = ((DBVARYCHAR*) bindval)->len;
2007  break;
2008 
2009 #if 0
2010  case SENSITIVITYBIND:
2011  case BOUNDARYBIND:
2012 #endif
2013  default:
2014  dbperror(dbproc, SYBEBTYP, 0);
2015  return FAIL;
2016  }
2017 
2018  if ((pval = tds_new(BYTE, bindlen)) == NULL) {
2019  dbperror(dbproc, SYBEMEM, errno);
2020  return FAIL;
2021  }
2022 
2023  /* free any prior allocation */
2024  if (dbproc->nullreps[bindtype].bindval != default_null_representations[bindtype].bindval)
2025  free((BYTE*)dbproc->nullreps[bindtype].bindval);
2026 
2027  memcpy(pval, bindval, bindlen);
2028 
2029  dbproc->nullreps[bindtype].bindval = pval;
2030  dbproc->nullreps[bindtype].len = bindlen;
2031 
2032  tdsdump_dump_buf(TDS_DBG_NETWORK, "null representation set ", pval, bindlen);
2033  return SUCCEED;
2034 }
2035 
2036 /**
2037  * \ingroup dblib_core
2038  * \brief Make a buffered row "current" without fetching it into bound variables.
2039  *
2040  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2041  * \retval MORE_ROWS row found
2042  * \retval NO_MORE_ROWS row not found
2043  * \retval FAIL \a dbproc is dead or not enabled
2044  * \sa dbaltbind(), dbbind(), dbcanquery(), dbclrbuf(), dbgetrow(), dbnextrow(), dbprrow().
2045  */
2046 STATUS
2048 {
2049  const int idx = buffer_row2idx(&dbproc->row_buf, row);
2050 
2051  tdsdump_log(TDS_DBG_FUNC, "dbsetrow(%p, %d)\n", dbproc, row);
2052  CHECK_CONN(FAIL);
2053 
2054  if (-1 == idx)
2055  return NO_MORE_ROWS;
2056 
2057  dbproc->row_buf.current = idx;
2058 
2059  /* FIXME: should determine REG_ROW or compute_id; */
2060  return REG_ROW;
2061 }
2062 
2063 /**
2064  * \ingroup dblib_core
2065  * \brief Read result row into the row buffer and into any bound host variables.
2066  *
2067  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2068  * \retval REG_ROW regular row has been read.
2069  * \returns computeid when a compute row is read.
2070  * \retval BUF_FULL reading next row would cause the buffer to be exceeded (and buffering is turned on).
2071  * No row was read from the server
2072  * \sa dbaltbind(), dbbind(), dbcanquery(), dbclrbuf(), dbgetrow(), dbprrow(), dbsetrow().
2073  */
2074 struct pivot_t;
2075 STATUS
2077 {
2078  TDSRESULTINFO *resinfo;
2079  TDSSOCKET *tds;
2080  STATUS result = FAIL;
2081  TDS_INT res_type;
2082  TDS_INT computeid;
2083  int idx; /* row buffer index. Unless DBUFFER is on, idx will always be 0. */
2084  struct pivot_t *pivot;
2085  prbuf_t prbuf;
2086 
2087  tdsdump_log(TDS_DBG_FUNC, "dbnextrow(%p)\n", dbproc);
2088  CHECK_CONN(FAIL);
2089 
2090  tds = dbproc->tds_socket;
2091  resinfo = tds->res_info;
2092 
2093  tdsdump_log(TDS_DBG_FUNC, "dbnextrow() dbresults_state = %d (%s)\n",
2095 
2096  if (!resinfo || dbproc->dbresults_state != _DB_RES_RESULTSET_ROWS) {
2097  /* no result set or result set empty (no rows) */
2098  tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %d (NO_MORE_ROWS)\n", NO_MORE_ROWS);
2099  return dbproc->row_type = NO_MORE_ROWS;
2100  }
2101 
2102  /*
2103  * Try to get the dbproc->row_buf.current item from the buffered rows, if any.
2104  * Else read from the stream, unless the buffer is exhausted.
2105  * If no rows are read, DBROWTYPE() will report NO_MORE_ROWS.
2106  */
2108  computeid = REG_ROW;
2109  if (-1 != (idx = buffer_current_index(dbproc))) {
2110  /*
2111  * Cool, the item we want is already there
2112  */
2114  res_type = TDS_ROW_RESULT;
2115 
2116  } else if (buffer_is_full(&dbproc->row_buf)) {
2117 
2118  result = BUF_FULL;
2119  res_type = TDS_ROWFMT_RESULT;
2120 
2121  } else if ((pivot = dbrows_pivoted(dbproc)) != NULL) {
2122 
2123  tdsdump_log(TDS_DBG_FUNC, "returning pivoted row\n");
2124  return dbnextrow_pivoted(dbproc, pivot);
2125 
2126  } else {
2128  TDS_INT8 row_count = TDS_NO_COUNT;
2129  bool rows_set = false;
2131 
2132  /* Get the row from the TDS stream. */
2133 again:
2134  switch (tds_process_tokens(tds, &res_type, NULL, mask)) {
2135  case TDS_SUCCESS:
2136  if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) {
2137  if (res_type == TDS_COMPUTE_RESULT)
2138  computeid = tds->current_results->computeid;
2139  /* Add the row to the row buffer, whose capacity is always at least 1 */
2140  resinfo = tds->current_results;
2141  idx = buffer_add_row(dbproc, resinfo);
2142  assert(idx != -1);
2143  result = dbproc->row_type = (res_type == TDS_ROW_RESULT)? REG_ROW : computeid;
2144 #if 0 /* TODO */
2146 #endif
2147  break;
2148  }
2149  /* allows to process trailing tokens */
2150  if (res_type == TDS_DONEINPROC_RESULT) {
2151  if (!rows_set)
2152  row_count = tds->rows_affected;
2153  rows_set = true;
2154  goto again;
2155  }
2156  /* fall through */
2157  case TDS_NO_MORE_RESULTS:
2159  result = NO_MORE_ROWS;
2160  break;
2161  default:
2162  tdsdump_log(TDS_DBG_FUNC, "unexpected: leaving dbnextrow() returning FAIL\n");
2163  return FAIL;
2164  break;
2165  }
2166  if (rows_set)
2167  tds->rows_affected = row_count;
2168  }
2169 
2170  if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) {
2171  /*
2172  * Transfer the data from the row buffer to the bound variables.
2173  */
2174  buffer_transfer_bound_data(&dbproc->row_buf, res_type, computeid, dbproc, idx);
2175  }
2176 
2177  if (res_type == TDS_COMPUTE_RESULT) {
2178  tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning compute_id %d\n", result);
2179  } else {
2180  tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %s\n", prdbretcode(result, prbuf));
2181  }
2182  return result;
2183 } /* dbnextrow() */
2184 
2185 static TDS_SERVER_TYPE
2186 dblib_bound_type(int bindtype)
2187 {
2188  switch (bindtype) {
2189  case CHARBIND:
2190  case STRINGBIND:
2191  case NTBSTRINGBIND:
2192  return SYBCHAR;
2193  break;
2194  case FLT8BIND:
2195  return SYBFLT8;
2196  break;
2197  case REALBIND:
2198  return SYBREAL;
2199  break;
2200  case INTBIND:
2201  return SYBINT4;
2202  break;
2203  case SMALLBIND:
2204  return SYBINT2;
2205  break;
2206  case TINYBIND:
2207  return SYBINT1;
2208  break;
2209  case BIGINTBIND:
2210  return SYBINT8;
2211  break;
2212  case DATETIMEBIND:
2213  return SYBDATETIME;
2214  break;
2215  case SMALLDATETIMEBIND:
2216  return SYBDATETIME4;
2217  break;
2218  case DATEBIND:
2219  return SYBDATE;
2220  break;
2221  case TIMEBIND:
2222  return SYBTIME;
2223  break;
2224  case BIGDATETIMEBIND:
2225  return SYB5BIGDATETIME;
2226  break;
2227  case BIGTIMEBIND:
2228  return SYB5BIGTIME;
2229  break;
2230  case MONEYBIND:
2231  return SYBMONEY;
2232  break;
2233  case SMALLMONEYBIND:
2234  return SYBMONEY4;
2235  break;
2236  case BINARYBIND:
2237  return SYBBINARY;
2238  break;
2239  case VARYBINBIND:
2240  return SYBVARBINARY;
2241  break;
2242  case VARYCHARBIND:
2243  return SYBVARCHAR;
2244  break;
2245  case BITBIND:
2246  return SYBBIT;
2247  break;
2248  case NUMERICBIND:
2249  case SRCNUMERICBIND:
2250  case DECIMALBIND:
2251  case SRCDECIMALBIND:
2252  return SYBNUMERIC;
2253  break;
2254  case DATETIME2BIND:
2255  return SYBMSDATETIMEOFFSET;
2256  break;
2257  default:
2258  return TDS_INVALID_TYPE;
2259  }
2260 }
2261 
2262 /**
2263  * \ingroup dblib_core
2264  * \brief Convert one datatype to another.
2265  *
2266  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2267  * \param srctype datatype of the data to convert.
2268  * \param src buffer to convert
2269  * \param srclen length of \a src
2270  * \param desttype target datatype
2271  * \param dest output buffer
2272  * \param destlen size of \a dest
2273  * \returns On success, the count of output bytes in \a dest, else -1. On failure, it will call any user-supplied error handler.
2274  * \remarks Causes of failure:
2275  * - No such conversion unavailable.
2276  * - Character data output was truncated, or numerical data overflowed or lost precision.
2277  * - In converting character data to one of the numeric types, the string could not be interpreted as a number.
2278  *
2279  * Conversion functions are handled in the TDS layer.
2280  *
2281  * The main reason for this is that \c ct-lib and \c ODBC (and presumably \c DBI) need
2282  * to be able to do conversions between datatypes. This is possible because
2283  * the format of complex data (dates, money, numeric, decimal) is defined by
2284  * its representation on the wire; thus what we call \c DBMONEY is exactly its
2285  * format on the wire. CLIs that need a different representation (ODBC?)
2286  * need to convert from this format anyway, so the code would already be in
2287  * place.
2288  *
2289  * Each datatype is also defined by its Server-type so all CLIs should be
2290  * able to map native types to server types as well.
2291  *
2292  * tds_convert() copies from src to dest and returns the output data length,
2293  * period. All padding and termination is the responsibility of the API library
2294  * and is done post-conversion. The peculiar rule in dbconvert() is that
2295  * a \a destlen of -1 and a \a desttype of \c SYBCHAR means the output buffer
2296  * should be null-terminated.
2297  *
2298  * \sa dbaltbind(), dbaltbind_ps(), dbbind(), dbbind_ps(), dbconvert_ps(), dberrhandle(), dbsetnull(), dbsetversion(), dbwillconvert().
2299  * \todo What happens if client does not reset values?
2300  * \todo Microsoft and Sybase define this function differently.
2301  */
2302 DBINT
2303 dbconvert_ps(DBPROCESS * dbproc, int db_srctype, const BYTE * src, DBINT srclen,
2304  int db_desttype, BYTE * dest, DBINT destlen, DBTYPEINFO * typeinfo)
2305 {
2306  CONV_RESULT dres;
2307  DBINT ret;
2308  int i;
2309  int len;
2310  TDS_SERVER_TYPE srctype, desttype;
2311 
2312  tdsdump_log(TDS_DBG_FUNC, "dbconvert_ps(%p, %s, %p, %d, %s, %p, %d, %p)\n",
2313  dbproc, tds_prdatatype(db_srctype), src, srclen,
2314  tds_prdatatype(db_desttype), dest, destlen, typeinfo);
2315  /* dbproc and src can be NULLs */
2316  CHECK_PARAMETER(dest, SYBEACNV, -1);
2317 
2319  srctype = (TDS_SERVER_TYPE) db_srctype;
2320  DBPERROR_RETURN(!is_tds_type_valid(db_desttype), SYBEUDTY);
2321  desttype = (TDS_SERVER_TYPE) db_desttype;
2322 
2323  if (is_numeric_type(desttype)) {
2324  TDS_NUMERIC *d = &dres.n;
2325 
2326  if (typeinfo == NULL) {
2327  if (is_numeric_type(srctype)) {
2328  DBNUMERIC *s = (DBNUMERIC *) src;
2329  d->precision = s->precision;
2330  d->scale = s->scale;
2331  } else {
2332  d->precision = 18;
2333  d->scale = 0;
2334  }
2335  } else {
2336  d->precision = typeinfo->precision;
2337  d->scale = typeinfo->scale;
2338  }
2339  }
2340 
2341  if (0 == destlen)
2342  return 0;
2343 
2344  if (src == NULL || srclen == 0) {
2345  int bind = dbbindtype(desttype);
2346  int size = tds_get_size_by_type(desttype);
2347 
2348  if (bind == NTBSTRINGBIND) {
2349  if (destlen > 0) {
2350  size = destlen;
2351  bind = CHARBIND;
2352  } else {
2353  size = 1;
2354  bind = NTBSTRINGBIND;
2355  }
2356  } else if (bind == BINARYBIND) {
2357  if (destlen > 0)
2358  size = destlen;
2359  else
2360  size = 0;
2361  }
2362 
2363  dbgetnull(dbproc, bind, size, dest);
2364  return size;
2365  }
2366 
2367  /* srclen of -1 means the source data is definitely NULL terminated */
2368  if (srclen == -1)
2369  srclen = (int)strlen((const char *) src);
2370 
2371  /* often times we are asked to convert a data type to itself */
2372  if (srctype == desttype && !is_numeric_type(desttype)) {
2373  ret = -2; /* to make sure we always set it */
2374  tdsdump_log(TDS_DBG_INFO1, "dbconvert_ps() srctype == desttype\n");
2375  switch (desttype) {
2376 
2377  case SYBBINARY:
2378  case SYBVARBINARY:
2379  case SYBIMAGE:
2380  if (srclen > destlen && destlen >= 0) {
2381  dbperror(dbproc, SYBECOFL, 0);
2382  ret = -1;
2383  } else {
2384  memcpy(dest, src, srclen);
2385  if (srclen < destlen)
2386  memset(dest + srclen, 0, destlen - srclen);
2387  ret = srclen;
2388  }
2389  break;
2390 
2391  case SYBCHAR:
2392  case SYBVARCHAR:
2393  case SYBTEXT:
2394  /* srclen of -1 means the source data is definitely NULL terminated */
2395  if (srclen == -1)
2396  srclen = (int)strlen((const char *) src);
2397 
2398  switch (destlen) {
2399  case 0: /* nothing to copy */
2400  ret = 0;
2401  break;
2402  case -1: /* rtrim and null terminate */
2403  while (srclen && src[srclen - 1] == ' ') {
2404  --srclen;
2405  }
2406  /* fall thru */
2407  case -2: /* just null terminate */
2408  memcpy(dest, src, srclen);
2409  dest[srclen] = '\0';
2410  ret = srclen;
2411  break;
2412  default:
2413  assert(destlen > 0);
2414  if (destlen < 0) {
2415  dbperror(dbproc, SYBECOFL, 0);
2416  ret = -1;
2417  } else {
2418  if (srclen > destlen) {
2419  dbperror(dbproc, 50000, 0);
2420  srclen = destlen;
2421  }
2422  memcpy(dest, src, srclen);
2423  for (i = srclen; i < destlen; i++)
2424  dest[i] = ' ';
2425  ret = srclen;
2426  }
2427  break;
2428  }
2429  break;
2430  case SYBINT1:
2431  case SYBINT2:
2432  case SYBINT4:
2433  case SYBINT8:
2434  case SYBFLT8:
2435  case SYBREAL:
2436  case SYBBIT:
2437  case SYBBITN:
2438  case SYBMONEY:
2439  case SYBMONEY4:
2440  case SYBDATETIME:
2441  case SYBDATETIME4:
2442  case SYBDATE:
2443  case SYBTIME:
2444  case SYB5BIGDATETIME:
2445  case SYB5BIGTIME:
2446  case SYBUNIQUE:
2447  ret = tds_get_size_by_type(desttype);
2448  memcpy(dest, src, ret);
2449  break;
2450 
2451  case SYBMSDATE:
2452  case SYBMSTIME:
2453  case SYBMSDATETIME2:
2454  case SYBMSDATETIMEOFFSET:
2455  ret = sizeof(TDS_DATETIMEALL);
2456  memcpy(dest, src, ret);
2457  break;
2458 
2459  default:
2460  ret = -1;
2461  break;
2462  }
2463  assert(ret > -2);
2464  return ret;
2465  }
2466  /* end srctype == desttype */
2467 
2468  /*
2469  * Character types need no conversion. Just move the data.
2470  */
2471  if (is_similar_type(srctype, desttype)) {
2472  if (src && dest && srclen > 0 && destlen >= srclen) {
2473  memcpy(dest, src, srclen);
2474  return srclen;
2475  }
2476  }
2477 
2478  tdsdump_log(TDS_DBG_INFO1, "dbconvert_ps() calling tds_convert\n");
2479 
2480  len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *) src, srclen, desttype, &dres);
2481  tdsdump_log(TDS_DBG_INFO1, "dbconvert_ps() called tds_convert returned %d\n", len);
2482 
2483  if (len < 0) {
2485  return -1;
2486  }
2487 
2488  switch (desttype) {
2489  case SYBBINARY:
2490  case SYBVARBINARY:
2491  case SYBIMAGE:
2492  if (len > destlen && destlen >= 0) {
2493  dbperror(dbproc, SYBECOFL, 0);
2494  ret = -1;
2495  } else {
2496  memcpy(dest, dres.ib, len);
2497  if (len < destlen)
2498  memset(dest + len, 0, destlen - len);
2499  ret = len;
2500  }
2501  free(dres.ib);
2502  break;
2503  case SYBINT1:
2504  case SYBINT2:
2505  case SYBINT4:
2506  case SYBINT8:
2507  case SYBFLT8:
2508  case SYBREAL:
2509  case SYBBIT:
2510  case SYBBITN:
2511  case SYBMONEY:
2512  case SYBMONEY4:
2513  case SYBDATETIME:
2514  case SYBDATETIME4:
2515  case SYBTIME:
2516  case SYBDATE:
2517  case SYB5BIGDATETIME:
2518  case SYB5BIGTIME:
2519  case SYBUNIQUE:
2520  case SYBMSDATE:
2521  case SYBMSTIME:
2522  case SYBMSDATETIME2:
2523  case SYBMSDATETIMEOFFSET:
2524  case SYBNUMERIC:
2525  case SYBDECIMAL:
2526  memcpy(dest, &(dres.ti), len);
2527  ret = len;
2528  break;
2529  case SYBCHAR:
2530  case SYBVARCHAR:
2531  case SYBTEXT:
2532  tdsdump_log(TDS_DBG_INFO1, "dbconvert_ps() outputting %d bytes character data destlen = %d \n", len, destlen);
2533 
2534  if (destlen < -2)
2535  destlen = 0; /* failure condition */
2536 
2537  switch (destlen) {
2538  case 0:
2539  ret = -1;
2540  break;
2541  case -1: /* rtrim and null terminate */
2542  for (i = len - 1; i >= 0 && dres.c[i] == ' '; --i) {
2543  len = i;
2544  }
2545  memcpy(dest, dres.c, len);
2546  dest[len] = '\0';
2547  ret = len;
2548  break;
2549  case -2: /* just null terminate */
2550  memcpy(dest, dres.c, len);
2551  dest[len] = 0;
2552  ret = len;
2553  break;
2554  default:
2555  assert(destlen > 0);
2556  if (destlen < 0) {
2557  dbperror(dbproc, SYBECOFL, 0);
2558  ret = -1;
2559  tdsdump_log(TDS_DBG_INFO1, "%d bytes type %d -> %d, destlen %d < %d required\n",
2560  srclen, srctype, desttype, destlen, len);
2561  break;
2562  }
2563  if (len > destlen) {
2564  dbperror(dbproc, 50000, 0);
2565  len = destlen;
2566  }
2567  /* else pad with blanks */
2568  memcpy(dest, dres.c, len);
2569  for (i = len; i < destlen; i++)
2570  dest[i] = ' ';
2571  ret = len;
2572 
2573  break;
2574  }
2575 
2576  free(dres.c);
2577 
2578  break;
2579  default:
2580  tdsdump_log(TDS_DBG_INFO1, "error: dbconvert_ps(): unrecognized desttype %d \n", desttype);
2581  ret = -1;
2582  break;
2583 
2584  }
2585  return (ret);
2586 }
2587 
2588 /**
2589  * \ingroup dblib_core
2590  * \brief cf. dbconvert_ps(), above
2591  *
2592  * \em Sybase: Convert numeric types.
2593  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2594  * \param srctype datatype of the data to convert.
2595  * \param src buffer to convert
2596  * \param srclen length of \a src
2597  * \param desttype target datatype
2598  * \param dest output buffer
2599  * \param destlen size of \a dest
2600  * \param typeinfo address of a \c DBTYPEINFO structure that governs the precision & scale of the output, may be \c NULL.
2601  * \sa dbaltbind(), dbaltbind_ps(), dbbind(), dbbind_ps(), dbconvert_ps(), dberrhandle(), dbsetnull(), dbsetversion(), dbwillconvert().
2602  */
2603 DBINT
2605  int srctype, const BYTE * src, DBINT srclen, int desttype, BYTE * dest, DBINT destlen)
2606 {
2607  DBTYPEINFO ti, *pti = NULL;
2608 
2609  tdsdump_log(TDS_DBG_FUNC, "dbconvert(%p)\n", dbproc);
2610  /* dbproc can be NULL*/
2611 
2613 
2614  if (is_numeric_type(desttype)) {
2615  DBNUMERIC *num;
2616 
2617  /* FIXME what happen if client do not reset values ??? */
2618  if (dbproc->msdblib) {
2619  num = (DBNUMERIC *) dest;
2620  ti.precision = num->precision;
2621  ti.scale = num->scale;
2622  pti = &ti;
2623  } else {
2624  /* for Sybase passing NULL as DBTYPEINFO is fine */
2625  }
2626  }
2627 
2628  return dbconvert_ps(dbproc, srctype, src, srclen, desttype, dest, destlen, pti);
2629 }
2630 
2631 /**
2632  * \ingroup dblib_core
2633  * \brief Tie a host variable to a resultset column.
2634  *
2635  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2636  * \param column Nth column, starting at 1.
2637  * \param vartype datatype of the host variable that will receive the data
2638  * \param varlen size of host variable pointed to \a varaddr
2639  * \param varaddr address of host variable
2640  * \retval SUCCEED everything worked.
2641  * \retval FAIL no such \a column or no such conversion possible, or target buffer too small.
2642  * \sa
2643  */
2644 RETCODE
2645 dbbind(DBPROCESS * dbproc, int column, int vartype, DBINT varlen, BYTE * varaddr)
2646 {
2647  TDSCOLUMN *colinfo = NULL;
2648  TDSRESULTINFO* results;
2649  TDS_SERVER_TYPE srctype, desttype;
2650 
2651  tdsdump_log(TDS_DBG_FUNC, "dbbind(%p, %d, %d, %d, %p)\n", dbproc, column, vartype, varlen, varaddr);
2652  CHECK_CONN(FAIL);
2653  CHECK_PARAMETER(varaddr, SYBEABNV, FAIL);
2654 
2655  results = dbproc->tds_socket->res_info;
2656 
2657  if (results == NULL || results->num_cols < column || column < 1) {
2658  dbperror(dbproc, SYBEABNC, 0);
2659  return FAIL;
2660  }
2661 
2662  if (varlen < 0) {
2663  switch (vartype) {
2664  case CHARBIND:
2665  case STRINGBIND:
2666  case NTBSTRINGBIND:
2667  case VARYCHARBIND:
2668  case VARYBINBIND:
2669  /*
2670  * No message for this error. Documentation doesn't define varlen < 0, but
2671  * experimentation with Sybase db-lib shows it's accepted as if zero.
2672  */
2673  tdsdump_log(TDS_DBG_FUNC, "dbbind: setting varlen (%d) to 0\n", varlen);
2674  varlen = 0;
2675  break;
2676  }
2677  }
2678 
2679  if (0 == varlen) { /* "Note that if varlen is 0, no padding takes place." */
2680  switch (vartype) {
2681  case CHARBIND:
2682  case STRINGBIND:
2683  case NTBSTRINGBIND:
2684  varlen = -1;
2685  break;
2686  default:
2687  break; /* dbconvert: "The destlen is ignored for all fixed-length, non-NULL data types." */
2688  }
2689  }
2690 
2691  dbproc->avail_flag = FALSE;
2692 
2693  colinfo = dbproc->tds_socket->res_info->columns[column - 1];
2694  srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
2695  desttype = dblib_bound_type(vartype);
2696  if (desttype == TDS_INVALID_TYPE) {
2697  dbperror(dbproc, SYBEBTYP, 0);
2698  return FAIL;
2699  }
2700 
2701  if (!dbwillconvert(srctype, desttype)) {
2702  dbperror(dbproc, SYBEABMT, 0);
2703  return FAIL;
2704  }
2705 
2706  colinfo->column_varaddr = (char *) varaddr;
2707  colinfo->column_bindtype = vartype;
2708  colinfo->column_bindlen = varlen;
2709 
2710  return SUCCEED;
2711 } /* dbbind() */
2712 
2713 /**
2714  * \ingroup dblib_core
2715  * \brief set name and location of the \c interfaces file FreeTDS should use to look up a servername.
2716  *
2717  * Does not affect lookups or location of \c freetds.conf.
2718  * \param filename name of \c interfaces
2719  * \sa dbopen()
2720  */
2721 void
2722 dbsetifile(char *filename)
2723 {
2724  tdsdump_log(TDS_DBG_FUNC, "dbsetifile(%s)\n", filename? filename : "0x00");
2725  if (filename == NULL) {
2726  dbperror(NULL, SYBENULP, 0);
2727  return;
2728  }
2729  tds_set_interfaces_file_loc(filename);
2730 }
2731 
2732 /**
2733  * \ingroup dblib_core
2734  * \brief Tie a null-indicator to a regular result column.
2735  *
2736  *
2737  * When a row is fetched, the indicator variable tells the state of the column's data.
2738  *
2739  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2740  * \param column Nth column in the result set, starting with 1.
2741  * \param indicator address of host variable.
2742  * \retval SUCCEED variable accepted.
2743  * \retval FAIL \a indicator is NULL or \a column is out of range.
2744  * \remarks Contents of \a indicator are set with \c dbnextrow(). Possible values are:
2745  * - 0 \a column bound successfully
2746  * - -1 \a column is NULL.
2747  * - >0 true length of data, had \a column not been truncated due to insufficient space in the columns bound host variable .
2748  * \sa dbanullbind(), dbbind(), dbdata(), dbdatlen(), dbnextrow().
2749  */
2750 RETCODE
2752 {
2753  TDSCOLUMN *colinfo;
2754 
2755  tdsdump_log(TDS_DBG_FUNC, "dbnullbind(%p, %d, %p)\n", dbproc, column, indicator);
2756 
2757  colinfo = dbcolptr(dbproc, column);
2758  if (!colinfo)
2759  return FAIL; /* dbcolptr sent SYBECNOR, Column number out of range */
2760 
2761  colinfo->column_nullbind = (TDS_SMALLINT *)indicator;
2762  return SUCCEED;
2763 }
2764 
2765 /**
2766  * \ingroup dblib_core
2767  * \brief Tie a null-indicator to a compute result column.
2768  *
2769  *
2770  * When a row is fetched, the indicator variable tells the state of the column's data.
2771  *
2772  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2773  * \param computeid identifies which one of potientially many compute rows is meant. The first compute
2774  * clause has \a computeid == 1.
2775  * \param column Nth column in the result set, starting with 1.
2776  * \param indicator address of host variable.
2777  * \retval SUCCEED variable accepted.
2778  * \retval FAIL \a indicator is NULL or \a column is out of range.
2779  * \remarks Contents of \a indicator are set with \c dbnextrow(). Possible values are:
2780  * - 0 \a column bound successfully
2781  * - -1 \a column is NULL.
2782  * - >0 true length of data, had \a column not been truncated due to insufficient space in the columns bound host variable .
2783  * \sa dbadata(), dbadlen(), dbaltbind(), dbnextrow(), dbnullbind().
2784  * \todo Never fails, but only because failure conditions aren't checked.
2785  */
2786 RETCODE
2787 dbanullbind(DBPROCESS * dbproc, int computeid, int column, DBINT * indicator)
2788 {
2789  TDSCOLUMN *curcol;
2790 
2791  tdsdump_log(TDS_DBG_FUNC, "dbanullbind(%p, %d, %d, %p)\n", dbproc, computeid, column, indicator);
2792 
2793  curcol = dbacolptr(dbproc, computeid, column, 1);
2794  if (!curcol)
2795  return FAIL;
2796 
2797  /*
2798  * XXX Need to check for possibly problems before assuming
2799  * everything is okay
2800  */
2801  curcol->column_nullbind = (TDS_SMALLINT *)indicator;
2802 
2803  return SUCCEED;
2804 }
2805 
2806 /**
2807  * \ingroup dblib_core
2808  * \brief Indicates whether or not the count returned by dbcount is real (Microsoft-compatibility feature).
2809  *
2810  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2811  * \returns TRUE if the count returned by dbcount is real or FALSE if the count returned by dbcount is not real.
2812  * \sa DBCOUNT(), dbcount().
2813  */
2814 BOOL
2816 {
2817  tdsdump_log(TDS_DBG_FUNC, "dbiscount(%p)\n", dbproc);
2819 
2821 }
2822 
2823 /**
2824  * \ingroup dblib_core
2825  * \brief Get count of rows processed
2826  *
2827  *
2828  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2829  * \returns
2830  * - for insert/update/delete, count of rows affected.
2831  * - for select, count of rows returned, after all rows have been fetched.
2832  * \sa DBCOUNT(), dbnextrow(), dbresults().
2833  */
2834 DBINT
2836 {
2837  tdsdump_log(TDS_DBG_FUNC, "dbcount(%p)\n", dbproc);
2839 
2841  return -1;
2843 }
2844 
2845 /**
2846  * \ingroup dblib_core
2847  * \brief Clear \a n rows from the row buffer.
2848  *
2849  *
2850  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2851  * \param n number of rows to remove, >= 0.
2852  * \sa dbgetrow(), dbnextrow(), dbsetopt().
2853  */
2854 void
2856 {
2857  tdsdump_log(TDS_DBG_FUNC, "dbclrbuf(%p, %d)\n", dbproc, n);
2859 
2860  if (n <= 0)
2861  return;
2862 
2863  if (dbproc->dbopts[DBBUFFER].factive) {
2864  DBPROC_ROWBUF * buf = &(dbproc->row_buf);
2865  int count = buffer_count(buf);
2866  if (n >= count)
2867  n = count - 1;
2869  }
2870 }
2871 
2872 /**
2873  * \ingroup dblib_core
2874  * \brief Test whether or not a datatype can be converted to another datatype
2875  *
2876  * \param srctype type converting from
2877  * \param desttype type converting to
2878  * \remarks dbwillconvert() lies sometimes. Some datatypes \em should be convertible but aren't yet in our implementation.
2879  * Legal unimplemented conversions return \em TRUE.
2880  * \retval TRUE convertible, or should be.
2881  * \retval FAIL not convertible.
2882  * \sa dbaltbind(), dbbind(), dbconvert(), dbconvert_ps(), \c src/dblib/unittests/convert().c().
2883  */
2884 DBBOOL
2885 dbwillconvert(int srctype, int desttype)
2886 {
2887  tdsdump_log(TDS_DBG_FUNC, "dbwillconvert(%s, %s)\n", tds_prdatatype(srctype), tds_prdatatype(desttype));
2888  return tds_willconvert(srctype, desttype) ? TRUE : FALSE;
2889 }
2890 
2891 /**
2892  * \ingroup dblib_core
2893  * \brief Get the datatype of a regular result set column.
2894  *
2895  *
2896  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2897  * \param column Nth in the result set, starting from 1.
2898  * \returns \c SYB* datetype token value, or zero if \a column out of range
2899  * \sa dbcollen(), dbcolname(), dbdata(), dbdatlen(), dbnumcols(), dbprtype(), dbvarylen().
2900  */
2901 int
2903 {
2904  TDSCOLUMN *colinfo;
2905 
2906  tdsdump_log(TDS_DBG_FUNC, "dbcoltype(%p, %d)\n", dbproc, column);
2907 
2908  colinfo = dbcolptr(dbproc, column);
2909  if (!colinfo)
2910  return -1;
2911 
2912  switch (colinfo->column_type) {
2913  case SYBVARCHAR:
2914  return SYBCHAR;
2915  case SYBVARBINARY:
2916  return SYBBINARY;
2917  default:
2918  return tds_get_conversion_type(colinfo->column_type,
2919  colinfo->column_size);
2920  }
2921 }
2922 
2923 /**
2924  * \ingroup dblib_core
2925  * \brief Get user-defined datatype of a regular result column.
2926  *
2927  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2928  * \param column Nth in the result set, starting from 1.
2929  * \returns \c SYB* datetype token value, or -1 if \a column out of range
2930  * \sa dbaltutype(), dbcoltype().
2931  */
2932 int
2934 {
2935  TDSCOLUMN *colinfo;
2936 
2937  tdsdump_log(TDS_DBG_FUNC, "dbcolutype(%p, %d)\n", dbproc, column);
2938 
2939  colinfo = dbcolptr(dbproc, column);
2940  if (!colinfo)
2941  return -1;
2942 
2943  return colinfo->column_usertype;
2944 }
2945 
2946 /**
2947  * \ingroup dblib_core
2948  * \brief Get precision and scale information for a regular result column.
2949  *
2950  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2951  * \param column Nth in the result set, starting from 1.
2952  * \return Pointer to a DBTYPEINFO structure . NULL \a column is out of range.
2953  * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols(), dbprtype(), dbvarylen().
2954  */
2955 DBTYPEINFO *
2957 {
2958  /* moved typeinfo from static into dbproc structure to make thread safe. (mlilback 11/7/01) */
2959  TDSCOLUMN *colinfo;
2960 
2961  tdsdump_log(TDS_DBG_FUNC, "dbcoltypeinfo(%p, %d)\n", dbproc, column);
2962 
2963  colinfo = dbcolptr(dbproc, column);
2964  if (!colinfo)
2965  return NULL;
2966 
2967  dbproc->typeinfo.precision = colinfo->column_prec;
2968  dbproc->typeinfo.scale = colinfo->column_scale;
2969  return &dbproc->typeinfo;
2970 }
2971 
2972 /**
2973  * \brief Get a bunch of column attributes with a single call (Microsoft-compatibility feature).
2974  *
2975  * \param dbproc contains all information needed by db-lib to manage communications with the server.
2976  * \param type must be CI_REGULAR or CI_ALTERNATE (CI_CURSOR is defined by the vendor, but is not yet implemented).
2977  * \param column Nth in the result set, starting from 1.
2978  * \param computeid (ignored)
2979  * \param pdbcol address of structure to be populated by this function.
2980  * \return SUCCEED or FAIL.
2981  * \sa dbcolbrowse(), dbqual(), dbtabbrowse(), dbtabcount(), dbtabname(), dbtabsource(), dbtsnewlen(), dbtsnewval(), dbtsput().
2982  * \todo Support cursor rows.
2983  */
2984 RETCODE
2986 {
2987  DBTYPEINFO *ps;
2989  TDSCOLUMN *colinfo;
2990  TDS_UINT i;
2991 
2992  tdsdump_log(TDS_DBG_FUNC, "dbcolinfo(%p, %d, %d, %d, %p)\n", dbproc, type, column, computeid, pdbcol);
2993 
2994  colinfo = dbcolptr(dbproc, column);
2995  if (!colinfo)
2996  return FAIL;
2997 
2998  CHECK_NULP(pdbcol, "dbcolinfo", 5, FAIL);
2999 
3000  if (type == CI_REGULAR) {
3001 
3002  strlcpy(pdbcol->Name, dbcolname(dbproc, column), sizeof(pdbcol->Name));
3003  strlcpy(pdbcol->ActualName, dbcolname(dbproc, column), sizeof(pdbcol->ActualName));
3005  sizeof(pdbcol->TableName));
3006 
3007  pdbcol->Type = dbcoltype(dbproc, column);
3008  pdbcol->UserType = dbcolutype(dbproc, column);
3009  pdbcol->MaxLength = dbcollen(dbproc, column);
3010  pdbcol->Null = _dbnullable(dbproc, column);
3011  pdbcol->VarLength = dbvarylen(dbproc, column);
3012 
3013  ps = dbcoltypeinfo(dbproc, column);
3014 
3015  if( ps ) {
3016  pdbcol->Precision = ps->precision;
3017  pdbcol->Scale = ps->scale;
3018  }
3019 
3020  pdbcol->Updatable = colinfo->column_writeable ? TRUE : FALSE;
3021  pdbcol->Identity = colinfo->column_identity ? TRUE : FALSE;
3022 
3023  return SUCCEED;
3024  }
3025 
3026  if (type == CI_ALTERNATE) {
3027 
3028  if (computeid == 0)
3029  return FAIL;
3030 
3031  for (i = 0;; ++i) {
3032  if (i >= dbproc->tds_socket->num_comp_info)
3033  return FAIL;
3035  if (info->computeid == computeid)
3036  break;
3037  }
3038 
3039  /* if either the compute id or the column number are invalid, return -1 */
3040  if (column < 1 || column > info->num_cols)
3041  return FAIL;
3042 
3043  colinfo = info->columns[column - 1];
3044 
3045  strlcpy(pdbcol->Name, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->Name));
3046  strlcpy(pdbcol->ActualName, tds_dstr_cstr(&colinfo->column_name), sizeof(pdbcol->ActualName));
3047 
3048  pdbcol->Type = dbalttype(dbproc, computeid, column);
3049  pdbcol->UserType = dbaltutype(dbproc, computeid, column);
3050  pdbcol->MaxLength = dbaltlen(dbproc, computeid, column);
3051  if (colinfo->column_nullable)
3052  pdbcol->Null = TRUE;
3053  else
3054  pdbcol->Null = FALSE;
3055 
3056  pdbcol->VarLength = FALSE;
3057 
3058  if (colinfo->column_nullable
3059  || is_nullable_type(colinfo->column_type))
3060  pdbcol->VarLength = TRUE;
3061 
3062  pdbcol->Precision = colinfo->column_prec;
3063  pdbcol->Scale = colinfo->column_scale;
3064 
3065  pdbcol->Updatable = colinfo->column_writeable ? TRUE : FALSE ;
3066  pdbcol->Identity = colinfo->column_identity ? TRUE : FALSE ;
3067 
3068  return SUCCEED;
3069  }
3070 
3071  return FAIL;
3072 }
3073 
3074 /**
3075  * \ingroup dblib_core
3076  * \brief Get base database column name for a result set column.
3077  *
3078  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3079  * \param column Nth in the result set, starting from 1.
3080  * \return pointer to ASCII null-terminated string, the name of the column. On error, NULL.
3081  * \sa dbcolbrowse(), dbqual(), dbtabbrowse(), dbtabcount(), dbtabname(), dbtabsource(), dbtsnewlen(), dbtsnewval(), dbtsput().
3082  */
3083 char *
3085 {
3086  TDSCOLUMN *colinfo;
3087 
3088  tdsdump_log(TDS_DBG_FUNC, "dbcolsource(%p, %d)\n", dbproc, column);
3089 
3090  colinfo = dbcolptr(dbproc, column);
3091  if (!colinfo)
3092  return NULL;
3093 
3094  return tds_dstr_buf(tds_dstr_isempty(&colinfo->table_column_name) ?
3095  &colinfo->column_name :
3096  &colinfo->table_column_name);
3097 }
3098 
3099 /**
3100  * \ingroup dblib_core
3101  * \brief Get size of a regular result column.
3102  *
3103  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3104  * \param column Nth in the result set, starting from 1.
3105  * \return size of the column (not of data in any particular row). On error, -1.
3106  * \sa dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols().
3107  */
3108 DBINT
3110 {
3111  TDSCOLUMN *colinfo;
3112 
3113  tdsdump_log(TDS_DBG_FUNC, "dbcollen(%p, %d)\n", dbproc, column);
3114 
3115  colinfo = dbcolptr(dbproc, column);
3116  if (!colinfo)
3117  return -1;
3118 
3119  return colinfo->column_size;
3120 }
3121 
3122 /**
3123  * \ingroup dblib_core
3124  * \brief Get size of a result column needed to print column.
3125  *
3126  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3127  * \param column Nth in the result set, starting from 1.
3128  * \return size of the column in characters (not of data in any particular row). On error, -1.
3129  * \sa dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols().
3130  */
3131 DBINT
3133 {
3134  TDSCOLUMN *colinfo;
3135 
3136  tdsdump_log(TDS_DBG_FUNC, "dbprcollen(%p, %d)\n", dbproc, column);
3137 
3138  colinfo = dbcolptr(dbproc, column);
3139  if (!colinfo)
3140  return 0;
3141 
3142  return _get_printable_size(colinfo);
3143 }
3144 
3145 
3146 /* dbvarylen(), pkleef@openlinksw.com 01/21/02 */
3147 /**
3148  * \ingroup dblib_core
3149  * \brief Determine whether a column can vary in size.
3150  *
3151  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3152  * \param column Nth in the result set, starting from 1.
3153  * \retval TRUE datatype of column can vary in size, or is nullable.
3154  * \retval FALSE datatype of column is fixed and is not nullable.
3155  * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbdatlen(), dbnumcols(), dbprtype().
3156  */
3157 DBINT
3159 {
3160  TDSCOLUMN *colinfo;
3161 
3162  tdsdump_log(TDS_DBG_FUNC, "dbvarylen(%p, %d)\n", dbproc, column);
3163 
3164  colinfo = dbcolptr(dbproc, column);
3165  if (!colinfo)
3166  return FALSE;
3167 
3168  if (colinfo->column_nullable)
3169  return TRUE;
3170 
3171  switch (colinfo->column_type) {
3172  /* variable length fields */
3173  case SYBNVARCHAR:
3174  case SYBVARBINARY:
3175  case SYBVARCHAR:
3176  return TRUE;
3177 
3178  /* types that can be null */
3179  case SYBBITN:
3180  case SYBDATETIMN:
3181  case SYBDECIMAL:
3182  case SYBFLTN:
3183  case SYBINTN:
3184  case SYBMONEYN:
3185  case SYBNUMERIC:
3186  return TRUE;
3187 
3188  /* blob types */
3189  case SYBIMAGE:
3190  case SYBNTEXT:
3191  case SYBTEXT:
3192  return TRUE;
3193 
3194  default:
3195  return FALSE;
3196  }
3197 }
3198 
3199 /**
3200  * \ingroup dblib_core
3201  * \brief Get size of current row's data in a regular result column.
3202  *
3203  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3204  * \param column Nth in the result set, starting from 1.
3205  * \return size of the data, in bytes.
3206  * \sa dbcollen(), dbcolname(), dbcoltype(), dbdata(), dbnumcols().
3207  */
3208 DBINT
3210 {
3211  DBINT len;
3212  TDSCOLUMN *colinfo;
3213 
3214  tdsdump_log(TDS_DBG_FUNC, "dbdatlen(%p, %d)\n", dbproc, column);
3215 
3216  colinfo = dbcolptr(dbproc, column);
3217  if (!colinfo)
3218  return -1;
3219 
3220  len = (colinfo->column_cur_size < 0)? 0 : colinfo->column_cur_size;
3221 
3222  tdsdump_log(TDS_DBG_FUNC, "dbdatlen() type = %d, len= %d\n", colinfo->column_type, len);
3223 
3224  return len;
3225 }
3226 
3227 /**
3228  * \ingroup dblib_core
3229  * \brief Get address of data in a regular result column.
3230  *
3231  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3232  * \param column Nth in the result set, starting from 1.
3233  * \return pointer the data, or NULL if data are NULL, or if \a column is out of range.
3234  * \sa dbbind(), dbcollen(), dbcolname(), dbcoltype(), dbdatlen(), dbnumcols().
3235  */
3236 BYTE *
3238 {
3239  tdsdump_log(TDS_DBG_FUNC, "dbdata(%p, %d)\n", dbproc, column);
3240 
3241  return _dbcoldata(dbcolptr(dbproc, column));
3242 }
3243 
3244 /** \internal
3245  * \ingroup dblib_internal
3246  * \brief Return data from a column
3247  *
3248  * \param colinfo contains information on a result column.
3249  * \return pointer to the data, or NULL if data are NULL
3250  * \sa dbdata(), dbretdata()
3251  */
3252 static BYTE *
3254 {
3255  BYTE *res;
3256  const static BYTE empty[1] = { 0 };
3257 
3258  if (!colinfo || colinfo->column_cur_size < 0)
3259  return NULL;
3260 
3261  res = colinfo->column_data;
3262  if (is_blob_col(colinfo))
3263  res = (BYTE *) ((TDSBLOB *) res)->textvalue;
3264  if (!res)
3265  return (BYTE *) empty;
3266  return res;
3267 }
3268 
3269 /**
3270  * \ingroup dblib_core
3271  * \brief Cancel the current command batch.
3272  *
3273  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3274  * \retval SUCCEED always.
3275  * \sa dbcanquery(), dbnextrow(), dbresults(), dbsetinterrupt(), dbsqlexec(), dbsqlok(), dbsqlsend().
3276  * \todo Check for failure and return accordingly.
3277  */
3278 RETCODE
3280 {
3281  TDSSOCKET *tds;
3282 
3283  tdsdump_log(TDS_DBG_FUNC, "dbcancel(%p)\n", dbproc);
3284  CHECK_CONN(FAIL);
3285 
3286  tds = dbproc->tds_socket;
3287 
3290 
3291  return SUCCEED;
3292 }
3293 
3294 /**
3295  * \ingroup dblib_core
3296  * \brief Determine size buffer required to hold the results returned by dbsprhead(), dbsprline(), and dbspr1row().
3297  *
3298  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3299  * \return size of buffer requirement, in bytes.
3300  * \remarks An esoteric function.
3301  * \sa dbprhead(), dbprrow(), dbspr1row(), dbsprhead(), dbsprline().
3302  */
3303 DBINT
3305 {
3306  TDSSOCKET *tds;
3307  int col, len = 0;
3308 
3309  tdsdump_log(TDS_DBG_FUNC, "dbspr1rowlen(%p)\n", dbproc);
3312 
3313  tds = dbproc->tds_socket;
3314 
3315  for (col = 0; col < tds->res_info->num_cols; col++) {
3316  TDSCOLUMN *colinfo = tds->res_info->columns[col];
3317  int collen = _get_printable_size(colinfo);
3318  int namlen = (int) tds_dstr_len(&colinfo->column_name);
3319 
3320  len += collen > namlen ? collen : namlen;
3321 
3322  if (col > 0) /* allow for the space between columns */
3324  }
3325 
3326  return ++len; /* allow for the nul */
3327 }
3328 
3329 /**
3330  * \ingroup dblib_core
3331  * \brief Print a regular result row to a buffer.
3332  *
3333  * Fills a buffer with one data row, represented as a null-terminated ASCII string. Helpful for debugging.
3334  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3335  * \param buffer \em output: Address of a buffer to hold ASCII null-terminated string.
3336  * \param buf_len size of \a buffer, in bytes.
3337  * \retval SUCCEED on success.
3338  * \retval FAIL trouble encountered.
3339  * \sa dbclropt(), dbisopt(), dbprhead(), dbprrow(), dbspr1rowlen(), dbsprhead(), dbsprline().
3340  */
3341 RETCODE
3343 {
3344  TDSSOCKET *tds;
3345  TDSDATEREC when;
3346  int i, c, col;
3347  DBINT len;
3348 
3349  tdsdump_log(TDS_DBG_FUNC, "dbspr1row(%p, %s, %d)\n", dbproc, buffer, buf_len);
3350  CHECK_CONN(FAIL);
3351  CHECK_NULP(buffer, "dbspr1row", 2, FAIL);
3352 
3353  if (!dbproc->tds_socket)
3354  return FAIL;
3355 
3356  tds = dbproc->tds_socket;
3357 
3358  for (col = 0; col < tds->res_info->num_cols; col++) {
3359  size_t padlen, collen, namlen;
3360  TDSCOLUMN *colinfo = tds->res_info->columns[col];
3361  if (colinfo->column_cur_size < 0) {
3362  len = 4;
3363  if (buf_len <= len) {
3364  return FAIL;
3365  }
3366  strcpy(buffer, "NULL");
3367  } else {
3368  TDS_SERVER_TYPE desttype, srctype;
3369 
3370  desttype = dblib_bound_type(STRINGBIND);
3371  srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
3372  if (is_datetime_type(srctype)) {
3373  tds_datecrack(srctype, dbdata(dbproc, col + 1), &when);
3374  len = (int)tds_strftime(buffer, buf_len, STD_DATETIME_FMT, &when, 3);
3375  } else {
3376  len = dbconvert(dbproc, srctype, dbdata(dbproc, col + 1), dbdatlen(dbproc, col + 1),
3377  desttype, (BYTE *) buffer, buf_len);
3378  }
3379  if (len == -1) {
3380  return FAIL;
3381  }
3382  }
3383  buffer += len;
3384  buf_len -= len;
3385  collen = _get_printable_size(colinfo);
3386  namlen = tds_dstr_len(&colinfo->column_name);
3387  padlen = (collen > namlen ? collen : namlen) - len;
3388  if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
3389  c = ' ';
3390  }
3391  for (; padlen > 0; padlen--) {
3392  if (buf_len < 1) {
3393  return FAIL;
3394  }
3395  *buffer++ = c;
3396  buf_len--;
3397  }
3398  if ((col + 1) < tds->res_info->num_cols) {
3399  i = 0;
3400  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
3401  if (buf_len < 1) {
3402  return FAIL;
3403  }
3404  *buffer++ = c;
3405  buf_len--;
3406  i++;
3407  }
3408  }
3409  }
3410  if (buf_len < 1) {
3411  return FAIL;
3412  }
3413  *buffer = '\0';
3414  return SUCCEED;
3415 }
3416 
3417 /**
3418  * \ingroup dblib_core
3419  * \brief Print a result set to stdout.
3420  *
3421  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3422  * \sa dbbind(), dbnextrow(), dbprhead(), dbresults(), dbspr1row(), dbsprhead(), dbsprline().
3423  */
3424 RETCODE
3426 {
3427  TDSCOLUMN *colinfo;
3428  TDSRESULTINFO *resinfo;
3429  TDSSOCKET *tds;
3430  int i, col;
3431  size_t collen, namlen, len;
3432  char dest[8192];
3433  int desttype, srctype;
3434  TDSDATEREC when;
3435  STATUS status;
3436  ssize_t padlen;
3437  int c;
3438  int selcol;
3439  int linechar;
3440  int op;
3441  const char *opname, *p;
3442 
3443  /* these are for compute rows */
3444  DBINT computeid, num_cols, colid;
3445  TDS_SMALLINT *col_printlens = NULL;
3446 
3447  tdsdump_log(TDS_DBG_FUNC, "dbprrow(%p)\n", dbproc);
3448  CHECK_CONN(FAIL);
3449 
3450  tds = dbproc->tds_socket;
3451 
3452  while ((status = dbnextrow(dbproc)) != NO_MORE_ROWS) {
3453 
3454  if (status == FAIL) {
3455  free(col_printlens);
3456  return FAIL;
3457  }
3458 
3459  if (status == REG_ROW) {
3460 
3461  resinfo = tds->res_info;
3462 
3463  if (col_printlens == NULL) {
3464  if ((col_printlens = tds_new0(TDS_SMALLINT, resinfo->num_cols)) == NULL) {
3465  dbperror(dbproc, SYBEMEM, errno);
3466  return FAIL;
3467  }
3468  }
3469 
3470  for (col = 0; col < resinfo->num_cols; col++) {
3471  colinfo = resinfo->columns[col];
3472  if (colinfo->column_cur_size < 0) {
3473  len = 4;
3474  strcpy(dest, "NULL");
3475  } else {
3476  desttype = dblib_bound_type(STRINGBIND);
3477  srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
3478  if (is_datetime_type(srctype)) {
3479  tds_datecrack(srctype, dbdata(dbproc, col + 1), &when);
3480  len = (int)tds_strftime(dest, sizeof(dest), STD_DATETIME_FMT, &when, 3);
3481  } else {
3482  len = dbconvert(dbproc, srctype, dbdata(dbproc, col + 1), dbdatlen(dbproc, col + 1),
3483  desttype, (BYTE *) dest, sizeof(dest));
3484  }
3485  }
3486 
3487  p = memchr(dest, '\0', len);
3488  fwrite(dest, 1, p == NULL ? len : (p - dest),
3489  stdout);
3490  collen = _get_printable_size(colinfo);
3491  namlen = tds_dstr_len(&colinfo->column_name);
3492  padlen = (collen > namlen ? collen : namlen) - len;
3493 
3495  for (; c > -1 && padlen > 0; padlen--) {
3496  putchar(c);
3497  }
3498 
3499  if ((col + 1) < resinfo->num_cols) {
3500  i = 0;
3501  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3502  putchar(c);
3503  }
3504  }
3505  col_printlens[col] = collen;
3506  }
3507  i = 0;
3508  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
3509  putchar(c);
3510  }
3511 
3512  } else if (col_printlens == NULL) {
3513  return FAIL;
3514  } else {
3515 
3516  computeid = status;
3517 
3518  for (i = 0;; ++i) {
3519  if ((TDS_UINT) i >= tds->num_comp_info) {
3520  free(col_printlens);
3521  return FAIL;
3522  }
3523  resinfo = tds->comp_info[i];
3524  if (resinfo->computeid == computeid)
3525  break;
3526  }
3527 
3528  num_cols = dbnumalts(dbproc, computeid);
3529  tdsdump_log(TDS_DBG_FUNC, "dbprrow num compute cols = %d\n", num_cols);
3530 
3531  i = 0;
3532  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
3533  putchar(c);
3534  }
3535  for (selcol = col = 1; col <= num_cols; col++) {
3536  tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
3537  colid = dbaltcolid(dbproc, computeid, col);
3538  /*
3539  * The pad character is pointed to by dbopts[DBPRPAD].param. If that pointer
3540  * is NULL -- meaning padding is turned off -- dbstring_getchar returns -1.
3541  */
3542  while (selcol < colid) {
3543  for (i = 0; i < col_printlens[selcol - 1]; i++) {
3544  if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) >= 0)
3545  putchar(c);
3546  }
3547  selcol++;
3548  i = 0;
3549  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3550  putchar(c);
3551  }
3552  }
3553  op = dbaltop(dbproc, computeid, col);
3554  opname = dbprtype(op);
3555  printf("%s", opname);
3556  for (i = 0;
3557  i < (col_printlens[selcol - 1]
3558  - (int) strlen(opname));
3559  i++) {
3560  if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) >= 0)
3561  putchar(c);
3562  }
3563  selcol++;
3564  if ((colid + 1) < num_cols) {
3565  i = 0;
3566  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3567  putchar(c);
3568  }
3569  }
3570  }
3571  i = 0;
3572  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
3573  putchar(c);
3574  }
3575 
3576  for (selcol = col = 1; col <= num_cols; col++) {
3577  tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
3578  colid = dbaltcolid(dbproc, computeid, col);
3579  while (selcol < colid) {
3580  for (i = 0; i < col_printlens[selcol - 1]; i++) {
3581  putchar(' ');
3582  }
3583  selcol++;
3584  i = 0;
3585  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3586  putchar(c);
3587  }
3588  }
3589  if (resinfo->by_cols > 0) {
3590  linechar = '-';
3591  } else {
3592  linechar = '=';
3593  }
3594  for (i = 0; i < col_printlens[colid - 1]; i++)
3595  putchar(linechar);
3596  selcol++;
3597  if ((colid + 1) < num_cols) {
3598  i = 0;
3599  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3600  putchar(c);
3601  }
3602  }
3603  }
3604  i = 0;
3605  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
3606  putchar(c);
3607  }
3608 
3609  for (selcol = col = 1; col <= num_cols; col++) {
3610  colinfo = resinfo->columns[col - 1];
3611 
3612  desttype = dblib_bound_type(STRINGBIND);
3613  srctype = dbalttype(dbproc, computeid, col);
3614 
3615  if (is_datetime_type(srctype)) {
3616  tds_datecrack(srctype, dbadata(dbproc, computeid, col), &when);
3617  len = (int)tds_strftime(dest, sizeof(dest), STD_DATETIME_FMT, &when, 3);
3618  } else {
3619  len = dbconvert(dbproc, srctype, dbadata(dbproc, computeid, col), -1, desttype,
3620  (BYTE *) dest, sizeof(dest));
3621  }
3622 
3623  tdsdump_log(TDS_DBG_FUNC, "dbprrow calling dbaltcolid(%d,%d)\n", computeid, col);
3624  colid = dbaltcolid(dbproc, computeid, col);
3625  tdsdump_log(TDS_DBG_FUNC, "dbprrow select column = %d\n", colid);
3626 
3627  while (selcol < colid) {
3628  for (i = 0; i < col_printlens[selcol - 1]; i++) {
3629  putchar(' ');
3630  }
3631  selcol++;
3632  i = 0;
3633  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3634  putchar(c);
3635  }
3636  }
3637  p = memchr(dest, '\0', len);
3638  fwrite(dest, 1, p == NULL ? len : (p - dest),
3639  stdout);
3640  collen = _get_printable_size(colinfo);
3641  namlen = tds_dstr_len(&colinfo->column_name);
3642  padlen = (collen > namlen ? collen : namlen) - len;
3643  if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
3644  c = ' ';
3645  }
3646  for (; padlen > 0; padlen--) {
3647  putchar(c);
3648  }
3649  selcol++;
3650  if ((colid + 1) < num_cols) {
3651  i = 0;
3652  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i++)) != -1) {
3653  putchar(c);
3654  }
3655  }
3656  }
3657  i = 0;
3658  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i++)) != -1) {
3659  putchar(c);
3660  }
3661  }
3662  }
3663 
3664  free(col_printlens);
3665 
3666  return SUCCEED;
3667 }
3668 
3669 static int
3671 {
3672  switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
3673  case SYBINT1:
3674  return 3;
3675  case SYBINT2:
3676  return 6;
3677  case SYBINT4:
3678  return 11;
3679  case SYBINT8:
3680  return 21;
3681  case SYBVARCHAR:
3682  case SYBCHAR:
3683  case SYBTEXT:
3684  case SYBNTEXT:
3685  case SYBNVARCHAR:
3686  case SYBLONGCHAR:
3687  return colinfo->column_size;
3688  case SYBBINARY:
3689  case SYBIMAGE:
3690  case SYBLONGBINARY:
3691  case SYBVARBINARY:
3692  return colinfo->column_size * 2u;
3693  case SYBFLT8:
3694  case SYBREAL:
3695  return 11; /* FIX ME -- we do not track precision */
3696  case SYBMONEY:
3697  case SYBMONEY4:
3698  return 12;
3699  case SYB5BIGDATETIME:
3700  case SYBDATETIME:
3701  case SYBDATETIME4:
3702  return 26;
3703  case SYBTIME:
3704  case SYB5BIGTIME:
3705  return 15;
3706  case SYBDATE:
3707  return 10;
3708  case SYBUNIQUE:
3709  return 36;
3710  case SYBBIT:
3711  return 1;
3712  /* FIX ME -- not all types present */
3713  default:
3714  return 0;
3715  }
3716 }
3717 
3718 /**
3719  * \ingroup dblib_core
3720  * \brief Get formatted string for underlining dbsprhead() column names.
3721  *
3722  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3723  * \param buffer output buffer
3724  * \param buf_len size of \a buffer
3725  * \param line_char character to use to represent underlining.
3726  * \retval SUCCEED \a buffer filled.
3727  * \retval FAIL insufficient space in \a buffer, usually.
3728  * \sa dbprhead(), dbprrow(), dbspr1row(), dbspr1rowlen(), dbsprhead().
3729  */
3730 RETCODE
3731 dbsprline(DBPROCESS * dbproc, char *buffer, DBINT buf_len, DBCHAR line_char)
3732 {
3733  TDSCOLUMN *colinfo;
3734  TDSRESULTINFO *resinfo;
3735  TDSSOCKET *tds;
3736  size_t i, col, len, collen, namlen;
3737  int c;
3738 
3739  tdsdump_log(TDS_DBG_FUNC, "dbsprline(%p, %s, %d, '%c')\n", dbproc, buffer, buf_len, line_char);
3740  CHECK_CONN(FAIL);
3741  CHECK_NULP(buffer, "dbsprline", 2, FAIL);
3742 
3743  tds = dbproc->tds_socket;
3744  resinfo = tds->res_info;
3745 
3746  for (col = 0; col < resinfo->num_cols; col++) {
3747  colinfo = resinfo->columns[col];
3748  collen = _get_printable_size(colinfo);
3749  namlen = tds_dstr_len(&colinfo->column_name);
3750  len = collen > namlen ? collen : namlen;
3751  for (i = 0; i < len; i++) {
3752  if (buf_len < 1) {
3753  return FAIL;
3754  }
3755  *buffer++ = line_char;
3756  buf_len--;
3757  }
3758  if ((col + 1) < resinfo->num_cols) {
3759  i = 0;
3760  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
3761  if (buf_len < 1) {
3762  return FAIL;
3763  }
3764  *buffer++ = c;
3765  buf_len--;
3766  i++;
3767  }
3768  }
3769  }
3770  if (buf_len < 1) {
3771  return FAIL;
3772  }
3773  *buffer = '\0';
3774  return SUCCEED;
3775 }
3776 
3777 /**
3778  * \ingroup dblib_core
3779  * \brief Print result set headings to a buffer.
3780  *
3781  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3782  * \param buffer output buffer
3783  * \param buf_len size of \a buffer
3784  * \retval SUCCEED \a buffer filled.
3785  * \retval FAIL insufficient spaace in \a buffer, usually.
3786  * \sa dbprhead(), dbprrow(), dbsetopt(), dbspr1row(), dbspr1rowlen(), dbsprline().
3787  */
3788 RETCODE
3790 {
3791  TDSCOLUMN *colinfo;
3792  TDSRESULTINFO *resinfo;
3793  TDSSOCKET *tds;
3794  int i, collen, namlen;
3795  TDS_USMALLINT col;
3796  int padlen;
3797  int c;
3798 
3799  tdsdump_log(TDS_DBG_FUNC, "dbsprhead(%p, %p, %d)\n", dbproc, buffer, buf_len);
3800  CHECK_CONN(FAIL);
3801  CHECK_NULP(buffer, "dbsprhead", 2, FAIL);
3802 
3803  tds = dbproc->tds_socket;
3804  resinfo = tds->res_info;
3805 
3806  for (col = 0; col < resinfo->num_cols; col++) {
3807  colinfo = resinfo->columns[col];
3808  collen = _get_printable_size(colinfo);
3809  namlen = (int) tds_dstr_len(&colinfo->column_name);
3810  padlen = (collen > namlen ? collen : namlen) - namlen;
3811  if (buf_len < namlen) {
3812  return FAIL;
3813  }
3814  memcpy(buffer, tds_dstr_cstr(&colinfo->column_name), namlen);
3815  buffer += namlen;
3816  buf_len -= namlen;
3817  if ((c = dbstring_getchar(dbproc->dbopts[DBPRPAD].param, 0)) == -1) {
3818  c = ' ';
3819  }
3820  for (; padlen > 0; padlen--) {
3821  if (buf_len < 1) {
3822  return FAIL;
3823  }
3824  *buffer++ = c;
3825  buf_len--;
3826  }
3827  if ((col + 1) < resinfo->num_cols) {
3828  i = 0;
3829  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
3830  if (buf_len < 1) {
3831  return FAIL;
3832  }
3833  *buffer++ = c;
3834  buf_len--;
3835  i++;
3836  }
3837  }
3838  }
3839  if (buf_len < 1) {
3840  return FAIL;
3841  }
3842  *buffer = '\0';
3843  return SUCCEED;
3844 }
3845 
3846 /**
3847  * \ingroup dblib_core
3848  * \brief Print result set headings to stdout.
3849  *
3850  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3851  * \sa
3852  */
3853 void
3855 {
3856  TDSCOLUMN *colinfo;
3857  TDSRESULTINFO *resinfo;
3858  TDSSOCKET *tds;
3859  size_t i, col, len, collen, namlen;
3860  size_t padlen;
3861  int c;
3862 
3863  tdsdump_log(TDS_DBG_FUNC, "dbprhead(%p)\n", dbproc);
3865 
3866  tds = dbproc->tds_socket;
3867  resinfo = tds->res_info;
3868  if (resinfo == NULL) {
3869  return;
3870  }
3871  for (col = 0; col < resinfo->num_cols; col++) {
3872  colinfo = resinfo->columns[col];
3873  collen = _get_printable_size(colinfo);
3874  namlen = tds_dstr_len(&colinfo->column_name);
3875  padlen = (collen > namlen ? collen : namlen) - namlen;
3876  printf("%s", tds_dstr_cstr(&colinfo->column_name));
3877 
3879  if (c == -1) {
3880  c = ' ';
3881  }
3882  for (; padlen > 0; padlen--) {
3883  putchar(c);
3884  }
3885 
3886  if ((col + 1) < resinfo->num_cols) {
3887  i = 0;
3888  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
3889  putchar(c);
3890  i++;
3891  }
3892  }
3893  }
3894  i = 0;
3895  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i)) != -1) {
3896  putchar(c);
3897  i++;
3898  }
3899  for (col = 0; col < resinfo->num_cols; col++) {
3900  colinfo = resinfo->columns[col];
3901  collen = _get_printable_size(colinfo);
3902  namlen = tds_dstr_len(&colinfo->column_name);
3903  len = collen > namlen ? collen : namlen;
3904  for (i = 0; i < len; i++)
3905  putchar('-');
3906  if ((col + 1) < resinfo->num_cols) {
3907  i = 0;
3908  while ((c = dbstring_getchar(dbproc->dbopts[DBPRCOLSEP].param, i)) != -1) {
3909  putchar(c);
3910  i++;
3911  }
3912  }
3913  }
3914  i = 0;
3915  while ((c = dbstring_getchar(dbproc->dbopts[DBPRLINESEP].param, i)) != -1) {
3916  putchar(c);
3917  i++;
3918  }
3919 }
3920 
3921 /** \internal
3922  * \ingroup dblib_internal
3923  * \brief Indicate whether a query returned rows.
3924  *
3925  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3926  * \sa DBROWS(), DBCMDROW(), dbnextrow(), dbresults(), DBROWTYPE().
3927  */
3928 RETCODE
3930 {
3931  TDSSOCKET *tds;
3932 
3933  tdsdump_log(TDS_DBG_FUNC, "dbrows(%p)\n", dbproc);
3934  CHECK_CONN(FAIL);
3935 
3936  if (!(tds=dbproc->tds_socket))
3937  return FAIL;
3938 
3939  return (tds->res_info && tds->res_info->rows_exist)? SUCCEED : FAIL;
3940 }
3941 
3942 #if defined(DBLIB_UNIMPLEMENTED)
3943 /**
3944  * \ingroup dblib_core
3945  * \brief Set the default character set for an application.
3946  *
3947  * \param language ASCII null-terminated string.
3948  * \sa dbsetdeflang(), dbsetdefcharset(), dblogin(), dbopen().
3949  * \retval SUCCEED Always.
3950  * \todo Unimplemented.
3951  */
3952 RETCODE
3953 dbsetdeflang(char *language)
3954 {
3955  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetdeflang(%s)\n", language);
3956  CHECK_PARAMETER_NOPROC(language, SYBENULP);
3957  return SUCCEED;
3958 }
3959 #endif
3960 
3961 /**
3962  * \ingroup dblib_core
3963  * \brief Get TDS packet size for the connection.
3964  *
3965  * \param dbproc contains all information needed by db-lib to manage communications with the server.
3966  * \return TDS packet size, in bytes.
3967  * \sa DBSETLPACKET()
3968  */
3969 int
3971 {
3972  TDSSOCKET *tds;
3973 
3974  tdsdump_log(TDS_DBG_FUNC, "dbgetpacket(%p)\n", dbproc);
3976 
3977  tds = dbproc->tds_socket;
3978  if (!tds) {
3979  return TDS_DEF_BLKSZ;
3980  } else {
3981  return tds->conn->env.block_size;
3982  }
3983 }
3984 
3985 /**
3986  * \ingroup dblib_core
3987  * \brief Set maximum simultaneous connections db-lib will open to the server.
3988  *
3989  * \param maxprocs Limit for process.
3990  * \retval SUCCEED Always.
3991  * \sa dbgetmaxprocs(), dbopen()
3992  */
3993 RETCODE
3994 dbsetmaxprocs(int maxprocs)
3995 {
3996  int i, j;
3997  TDSSOCKET **old_list;
3998 
3999  tdsdump_log(TDS_DBG_FUNC, "UNTESTED dbsetmaxprocs(%d)\n", maxprocs);
4000 
4001  /* not too few elements */
4002  if (maxprocs <= 0)
4003  return FAIL;
4004 
4005  tds_mutex_lock(&dblib_mutex);
4006 
4007  old_list = g_dblib_ctx.connection_list;
4008 
4009  /* "compress" array */
4010  for (i = 0; i < g_dblib_ctx.connection_list_size; ++i) {
4011  /* if empty replace with first no-empty */
4012  if (old_list[i])
4013  continue;
4014  for (j = i + 1; j < g_dblib_ctx.connection_list_size; ++j)
4015  if (old_list[j]) {
4016  old_list[i] = old_list[j];
4017  old_list[j] = NULL;
4018  break;
4019  }
4021  break;
4022  }
4023  /* do not restrict too much, i here contains minimun size */
4024  if (maxprocs < i)
4025  maxprocs = i;
4026  assert(maxprocs > 0);
4027 
4028  /*
4029  * Don't reallocate less memory.
4030  * If maxprocs is less than was initially allocated, just reduce the represented list size.
4031  * If larger, reallocate and copy.
4032  * We probably should check for valid connections beyond the new max.
4033  */
4034  if (maxprocs <= g_dblib_ctx.connection_list_size) {
4036  tds_mutex_unlock(&dblib_mutex);
4037  return SUCCEED;
4038  }
4039 
4041 
4042  if (g_dblib_ctx.connection_list == NULL) {
4043  g_dblib_ctx.connection_list = old_list;
4044  tds_mutex_unlock(&dblib_mutex);
4045  dbperror(NULL, SYBEMEM, errno);
4046  return FAIL;
4047  }
4048 
4049  for (i = 0; i < g_dblib_ctx.connection_list_size; i++) {
4050  g_dblib_ctx.connection_list[i] = old_list[i];
4051  }
4052 
4053  g_dblib_ctx.connection_list_size = maxprocs;
4055 
4056  tds_mutex_unlock(&dblib_mutex);
4057 
4058  return SUCCEED;
4059 }
4060 
4061 /**
4062  * \ingroup dblib_core
4063  * \brief get maximum simultaneous connections db-lib will open to the server.
4064  *
4065  * \return Current maximum.
4066  * \sa dbsetmaxprocs(), dbopen()
4067  */
4068 int
4070 {
4071  int r;
4072 
4073  tdsdump_log(TDS_DBG_FUNC, "dbgetmaxprocs(void)\n");
4074 
4075  tds_mutex_lock(&dblib_mutex);
4077  tds_mutex_unlock(&dblib_mutex);
4078  return r;
4079 }
4080 
4081 /**
4082  * \ingroup dblib_core
4083  * \brief Set maximum seconds db-lib waits for a server response to query.
4084  *
4085  * \param seconds New limit for application.
4086  * \retval SUCCEED Always.
4087  * \sa dberrhandle(), DBGETTIME(), dbsetlogintime(), dbsqlexec(), dbsqlok(), dbsqlsend().
4088  */
4089 RETCODE
4090 dbsettime(int seconds)
4091 {
4092  TDSSOCKET **tds;
4093  int i;
4094  DBPROCESS *dbproc;
4095  tdsdump_log(TDS_DBG_FUNC, "dbsettime(%d)\n", seconds);
4096 
4097  tds_mutex_lock(&dblib_mutex);
4098  g_dblib_ctx.query_timeout = seconds;
4099 
4101  for (i = 0; i < TDS_MAX_CONN; i++) {
4102  if (tds[i]) {
4104  if (!dbisopt(dbproc, DBSETTIME, 0))
4105  tds[i]->query_timeout = seconds;
4106  }
4107  }
4108 
4109  tds_mutex_unlock(&dblib_mutex);
4110  return SUCCEED;
4111 }
4112 
4113 /**
4114  * \ingroup dblib_core
4115  * \brief Get maximum seconds db-lib waits for a server response to query.
4116  *
4117  * \retval query timeout limit, in seconds
4118  * \sa dberrhandle(), DBSETTIME(), dbsetlogintime(), dbsqlexec(), dbsqlok(), dbsqlsend().
4119  */
4120 int
4122 {
4123  tdsdump_log(TDS_DBG_FUNC, "dbgettime()\n");
4124 
4125  return g_dblib_ctx.query_timeout;
4126 }
4127 
4128 /**
4129  * \ingroup dblib_core
4130  * \brief Set maximum seconds db-lib waits for a server response to a login attempt.
4131  *
4132  * \param seconds New limit for application.
4133  * \retval SUCCEED Always.
4134  * \sa dberrhandle(), dbsettime()
4135  */
4136 RETCODE
4137 dbsetlogintime(int seconds)
4138 {
4139  tdsdump_log(TDS_DBG_FUNC, "dbsetlogintime(%d)\n", seconds);
4140 
4141  tds_mutex_lock(&dblib_mutex);
4142  g_dblib_ctx.login_timeout = seconds;
4143  tds_mutex_unlock(&dblib_mutex);
4144  return SUCCEED;
4145 }
4146 
4147 /** \internal
4148  * \ingroup dblib_internal
4149  * \brief See if the current command can return rows.
4150  *
4151  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4152  * \retval SUCCEED Yes, it can.
4153  * \retval FAIL No, it can't.
4154  * \remarks Use DBCMDROW() macro instead.
4155  * \sa DBCMDROW(), dbnextrow(), dbresults(), DBROWS(), DBROWTYPE().
4156  */
4157 RETCODE
4159 {
4160  TDSSOCKET *tds;
4161 
4162  tdsdump_log(TDS_DBG_FUNC, "dbcmdrow(%p)\n", dbproc);
4163  CHECK_CONN(FAIL);
4164 
4165  tds = dbproc->tds_socket;
4166  if (tds->res_info)
4167  return SUCCEED;
4168  return FAIL;
4169 }
4170 
4171 /**
4172  * \ingroup dblib_core
4173  * \brief Get column ID of a compute column.
4174  *
4175  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4176  * \param computeid of \c COMPUTE clause to which we're referring.
4177  * \param column Nth column in \a computeid, starting from 1.
4178  * \return Nth column in the base result set, on which \a column was computed.
4179  * \sa dbadata(), dbadlen(), dbaltlen(), dbgetrow(), dbnextrow(), dbnumalts(), dbprtype().
4180  */
4181 int
4182 dbaltcolid(DBPROCESS * dbproc, int computeid, int column)
4183 {
4184  TDSCOLUMN *curcol;
4185 
4186  tdsdump_log(TDS_DBG_FUNC, "dbaltcolid(%p, %d, %d)\n", dbproc, computeid, column);
4188 
4189  curcol = dbacolptr(dbproc, computeid, column, 0);
4190  if (!curcol)
4191  return -1;
4192 
4193  return curcol->column_operand;
4194 }
4195 
4196 /**
4197  * \ingroup dblib_core
4198  * \brief Get size of data in a compute column.
4199  *
4200  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4201  * \param computeid of \c COMPUTE clause to which we're referring.
4202  * \param column Nth column in \a computeid, starting from 1.
4203  * \return size of the data, in bytes.
4204  * \retval -1 no such \a column or \a computeid.
4205  * \retval 0 data are NULL.
4206  * \sa dbadata(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumalts().
4207  */
4208 DBINT
4209 dbadlen(DBPROCESS * dbproc, int computeid, int column)
4210 {
4211  TDSCOLUMN *colinfo;
4212  DBINT len;
4213 
4214  tdsdump_log(TDS_DBG_FUNC, "dbadlen(%p, %d, %d)\n", dbproc, computeid, column);
4216 
4217  colinfo = dbacolptr(dbproc, computeid, column, 0);
4218  if (!colinfo)
4219  return -1;
4220 
4221  len = colinfo->column_cur_size < 0? 0 : colinfo->column_cur_size;
4222 
4223  tdsdump_log(TDS_DBG_FUNC, "leaving dbadlen() type = %d, returning %d\n", colinfo->column_type, len);
4224 
4225  return len;
4226 }
4227 
4228 /**
4229  * \ingroup dblib_core
4230  * \brief Get datatype for a compute column.
4231  *
4232  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4233  * \param computeid of \c COMPUTE clause to which we're referring.
4234  * \param column Nth column in \a computeid, starting from 1.
4235  * \return \c SYB* dataype token.
4236  * \retval -1 no such \a column or \a computeid.
4237  * \sa dbadata(), dbadlen(), dbaltlen(), dbnextrow(), dbnumalts(), dbprtype().
4238  */
4239 int
4240 dbalttype(DBPROCESS * dbproc, int computeid, int column)
4241 {
4242  TDSCOLUMN *colinfo;
4243 
4244  tdsdump_log(TDS_DBG_FUNC, "dbalttype(%p, %d, %d)\n", dbproc, computeid, column);
4246 
4247  colinfo = dbacolptr(dbproc, computeid, column, 0);
4248  if (!colinfo)
4249  return -1;
4250 
4251  switch (colinfo->column_type) {
4252  case SYBVARCHAR:
4253  return SYBCHAR;
4254  case SYBVARBINARY:
4255  return SYBBINARY;
4256  default:
4257  return tds_get_conversion_type(colinfo->column_type,
4258  colinfo->column_size);
4259  }
4260 }
4261 
4262 /**
4263  * \ingroup dblib_core
4264  * \brief Bind a compute column to a program variable.
4265  *
4266  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4267  * \param computeid of \c COMPUTE clause to which we're referring.
4268  * \param column Nth column in \a computeid, starting from 1.
4269  * \param vartype datatype of the host variable that will receive the data
4270  * \param varlen size of host variable pointed to \a varaddr
4271  * \param varaddr address of host variable
4272  * \retval SUCCEED everything worked.
4273  * \retval FAIL no such \a computeid or \a column, or no such conversion possible, or target buffer too small.
4274  * \sa dbadata(), dbaltbind_ps(), dbanullbind(), dbbind(), dbbind_ps(), dbconvert(),
4275  * dbconvert_ps(), dbnullbind(), dbsetnull(), dbsetversion(), dbwillconvert().
4276  */
4277 RETCODE
4278 dbaltbind(DBPROCESS * dbproc, int computeid, int column, int vartype, DBINT varlen, BYTE * varaddr)
4279 {
4280  TDS_SERVER_TYPE srctype, desttype;
4281  TDSCOLUMN *colinfo = NULL;
4282 
4283  tdsdump_log(TDS_DBG_FUNC, "dbaltbind(%p, %d, %d, %d, %d, %p)\n", dbproc, computeid, column, vartype, varlen, varaddr);
4285 
4286  colinfo = dbacolptr(dbproc, computeid, column, 1);
4287  if (!colinfo)
4288  return FAIL;
4289  CHECK_PARAMETER(varaddr, SYBEABNV, FAIL);
4290 
4291  dbproc->avail_flag = FALSE;
4292 
4293  srctype = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
4294  desttype = dblib_bound_type(vartype);
4295  if (desttype == TDS_INVALID_TYPE) {
4296  dbperror(dbproc, SYBEBTYP, 0);
4297  return FAIL;
4298  }
4299 
4300  if (!dbwillconvert(srctype, desttype)) {
4301  dbperror(dbproc, SYBEAAMT, 0);
4302  return FAIL;
4303  }
4304 
4305  colinfo->column_varaddr = (char *) varaddr;
4306  colinfo->column_bindtype = vartype;
4307  colinfo->column_bindlen = varlen;
4308 
4309  return SUCCEED;
4310 }
4311 
4312 
4313 /**
4314  * \ingroup dblib_core
4315  * \brief Get address of compute column data.
4316  *
4317  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4318  * \param computeid of \c COMPUTE clause to which we're referring.
4319  * \param column Nth column in \a computeid, starting from 1.
4320  * \return pointer to columns's data buffer.
4321  * \retval NULL no such \a computeid or \a column.
4322  * \sa dbadlen(), dbaltbind(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumalts().
4323  */
4324 BYTE *
4325 dbadata(DBPROCESS * dbproc, int computeid, int column)
4326 {
4327  TDSCOLUMN *colinfo;
4328 
4329  tdsdump_log(TDS_DBG_FUNC, "dbadata(%p, %d, %d)\n", dbproc, computeid, column);
4331 
4332  colinfo = dbacolptr(dbproc, computeid, column, 0);
4333  if (!colinfo)
4334  return NULL;
4335 
4336  if (is_blob_col(colinfo)) {
4337  return (BYTE *) ((TDSBLOB *) colinfo->column_data)->textvalue;
4338  }
4339 
4340  return (BYTE *) colinfo->column_data;
4341 }
4342 
4343 /**
4344  * \ingroup dblib_core
4345  * \brief Get aggregation operator for a compute column.
4346  *
4347  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4348  * \param computeid of \c COMPUTE clause to which we're referring.
4349  * \param column Nth column in \a computeid, starting from 1.
4350  * \return token value for the type of the compute column's aggregation operator.
4351  * \retval -1 no such \a computeid or \a column.
4352  * \sa dbadata(), dbadlen(), dbaltlen(), dbnextrow(), dbnumalts(), dbprtype().
4353  */
4354 int
4355 dbaltop(DBPROCESS * dbproc, int computeid, int column)
4356 {
4357  TDSCOLUMN *curcol;
4358 
4359  tdsdump_log(TDS_DBG_FUNC, "dbaltop(%p, %d, %d)\n", dbproc, computeid, column);
4361 
4362  if ((curcol=dbacolptr(dbproc, computeid, column, 0)) == NULL)
4363  return -1;
4364 
4365  return curcol->column_operator;
4366 }
4367 
4368 /**
4369  * \ingroup dblib_core
4370  * \brief Set db-lib or server option.
4371  *
4372  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4373  * \param option option to set.
4374  * \param char_param value to set \a option to, if it wants a null-teminated ASCII string.
4375  * \param int_param value to set \a option to, if it wants an integer value.
4376  * \retval SUCCEED everything worked.
4377  * \retval FAIL no such \a option, or insufficient memory, or unimplemented.
4378  * \remarks Many are unimplemented.
4379  * \sa dbclropt(), dbisopt().
4380  * \todo Implement more options.
4381  */
4382 RETCODE
4383 dbsetopt(DBPROCESS * dbproc, int option, const char *char_param, int int_param)
4384 {
4385  char *cmd;
4386  RETCODE rc;
4387  int i;
4388 
4389  tdsdump_log(TDS_DBG_FUNC, "dbsetopt(%p, %d, %s, %d)\n", dbproc, option, char_param, int_param);
4390  CHECK_CONN(FAIL);
4391  CHECK_NULP(char_param, "dbsetopt", 3, FAIL);
4392 
4393  if ((option < 0) || (option >= DBNUMOPTIONS)) {
4394  dbperror(dbproc, SYBEUNOP, 0);
4395  return FAIL;
4396  }
4397  dbproc->dbopts[option].factive = 1;
4398  switch (option) {
4399  case DBARITHABORT:
4400  case DBARITHIGNORE:
4401  case DBCHAINXACTS:
4402  case DBFIPSFLAG:
4403  case DBISOLATION:
4404  case DBNOCOUNT:
4405  case DBNOEXEC:
4406  case DBPARSEONLY:
4407  case DBSHOWPLAN:
4408  case DBSTORPROCID:
4409  case DBQUOTEDIDENT:
4410  /* server options (on/off) */
4411  if (asprintf(&cmd, "set %s on\n", dbproc->dbopts[option].text) < 0) {
4412  return FAIL;
4413  }
4414  rc = dbstring_concat(&(dbproc->dboptcmd), cmd);
4415  free(cmd);
4416  return rc;
4417  break;
4418  case DBNATLANG:
4419  case DBDATEFIRST:
4420  case DBDATEFORMAT:
4421  /* server options (char_param) */
4422  if (asprintf(&cmd, "set %s %s\n", dbproc->dbopts[option].text, char_param) < 0) {
4423  return FAIL;
4424  }
4425  rc = dbstring_concat(&(dbproc->dboptcmd), cmd);
4426  free(cmd);
4427  return rc;
4428  break;
4429  case DBOFFSET:
4430  /* server option */
4431  /* requires param
4432  * "select", "from", "table", "order", "compute",
4433  * "statement", "procedure", "execute", or "param"
4434  */
4435  break;
4436  case DBROWCOUNT:
4437  /* server option */
4438  /* requires param "0" to "2147483647" */
4439  break;
4440  case DBSTAT:
4441  /* server option */
4442  /* requires param "io" or "time" */
4443  break;
4444  case DBTEXTLIMIT:
4445  /* dblib option */
4446  /* requires param "0" to "2147483647" */
4447  /* dblib do not return more than this length from text/image */
4448  /* TODO required for PHP */
4449  break;
4450  case DBTEXTSIZE:
4451  /* server option */
4452  /* requires param "0" to "2147483647" */
4453  /* limit text/image from network */
4454  if (!char_param)
4455  char_param = "0";
4456  i = atoi(char_param);
4457  if (i < 0 || i > 2147483647)
4458  return FAIL;
4459  if (asprintf(&cmd, "set textsize %d\n", i) < 0)
4460  return FAIL;
4461  rc = dbstring_concat(&(dbproc->dboptcmd), cmd);
4462  free(cmd);
4463  return rc;
4464 
4465  case DBAUTH:
4466  /* ??? */
4467  break;
4468  case DBNOAUTOFREE:
4469  /* dblib option */
4470  break;
4471  case DBBUFFER:
4472  /*
4473  * Requires param "2" to "2147483647"
4474  * (0 or 1 is an error, < 0 yields the default 100)
4475  */
4476  {
4477  int nrows;
4478 
4479  /* 100 is the default, according to Microsoft */
4480  if( !char_param )
4481  char_param = "100";
4482 
4483  nrows = atoi(char_param);
4484 
4485  nrows = (nrows < 0 )? 100 : nrows;
4486 
4487  if( 1 < nrows && nrows <= 2147483647 ) {
4488  buffer_set_capacity(dbproc, nrows);
4489  return SUCCEED;
4490  }
4491  }
4492  break;
4493  case DBPRCOLSEP:
4494  case DBPRLINELEN:
4495  case DBPRLINESEP:
4496  rc = dbstring_assign(&(dbproc->dbopts[option].param), char_param);
4497  return rc;
4498  case DBPRPAD:
4499  /*
4500  * "If the character is not specified, the ASCII space character is used."
4501  * A NULL pointer to the pad character signifies that padding is turned off.
4502  */
4503  if (int_param) {
4504  rc = dbstring_assign(&(dbproc->dbopts[option].param), char_param? char_param : " ");
4505  } else {
4507  }
4508  return rc;
4509  break;
4510  case DBSETTIME:
4511  if (char_param) {
4512  i = atoi(char_param);
4513  if (0 < i) {
4514  rc = dbstring_assign(&(dbproc->dbopts[option].param), char_param);
4515  if (rc == SUCCEED) {
4517  }
4518  return rc;
4519  }
4520  }
4521  break;
4522  default:
4523  break;
4524  }
4525  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsetopt(option = %d)\n", option);
4526  return FAIL;
4527 }
4528 
4529 /**
4530  * \ingroup dblib_core
4531  * \brief Set interrupt handler for db-lib to use while blocked against a read from the server.
4532  *
4533  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4534  * \param chkintr
4535  * \param hndlintr
4536  * \sa dbcancel(), dbgetuserdata(), dbsetuserdata(), dbsetbusy(), dbsetidle().
4537  */
4538 void
4540 {
4541  tdsdump_log(TDS_DBG_FUNC, "dbsetinterrupt(%p, %p, %p)\n", dbproc, chkintr, hndlintr);
4543 
4544  dbproc->chkintr = chkintr;
4546 }
4547 
4548 /**
4549  * \ingroup dblib_rpc
4550  * \brief Determine if query generated a return status number.
4551  *
4552  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4553  * \retval TRUE fetch return status with dbretstatus().
4554  * \retval FALSE no return status.
4555  * \sa dbnextrow(), dbresults(), dbretdata(), dbretstatus(), dbrpcinit(), dbrpcparam(), dbrpcsend().
4556  */
4557 DBBOOL
4559 {
4560  TDSSOCKET *tds;
4561 
4562  tdsdump_log(TDS_DBG_FUNC, "dbhasretstat(%p)\n", dbproc);
4564 
4565  tds = dbproc->tds_socket;
4566  if (tds->has_status) {
4567  return TRUE;
4568  } else {
4569  return FALSE;
4570  }
4571 }
4572 
4573 /**
4574  * \ingroup dblib_rpc
4575  * \brief Fetch status value returned by query or remote procedure call.
4576  *
4577  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4578  * \return return value
4579  * \sa dbhasretstat(), dbnextrow(), dbresults(), dbretdata(), dbrpcinit(), dbrpcparam(), dbrpcsend().
4580  */
4581 DBINT
4583 {
4584  tdsdump_log(TDS_DBG_FUNC, "dbretstatus(%p)\n", dbproc);
4586 
4587  return dbproc->tds_socket->ret_status;
4588 }
4589 
4590 /**
4591  * \ingroup dblib_rpc
4592  * \brief Get count of output parameters filled by a stored procedure.
4593  *
4594  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4595  * \return How many, possibly zero.
4596  * \remarks This name sounds funny.
4597  * \sa
4598  */
4599 int
4601 {
4602  TDSSOCKET *tds;
4603  TDS_INT result_type;
4604 
4605  tdsdump_log(TDS_DBG_FUNC, "dbnumrets(%p)\n", dbproc);
4607 
4608  tds = dbproc->tds_socket;
4609 
4610  tdsdump_log(TDS_DBG_FUNC, "dbnumrets() finds %d columns\n", (tds->param_info? tds->param_info->num_cols : 0));
4611 
4612  /* try to fetch output parameters and return status, if we have not already done so */
4613  if (!tds->param_info)
4614  tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
4615 
4616  if (!tds->param_info)
4617  return 0;
4618 
4619  return tds->param_info->num_cols;
4620 }
4621 
4622 /**
4623  * \ingroup dblib_rpc
4624  * \brief Get name of an output parameter filled by a stored procedure.
4625  *
4626  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4627  * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
4628  * \returns ASCII null-terminated string, \c NULL if no such \a retnum.
4629  * \sa dbnextrow(), dbnumrets(), dbresults(), dbretdata(), dbretlen(), dbrettype(), dbrpcinit(), dbrpcparam().
4630  */
4631 char *
4633 {
4634  TDSPARAMINFO *param_info;
4635 
4636  tdsdump_log(TDS_DBG_FUNC, "dbretname(%p, %d)\n", dbproc, retnum);
4638 
4639  if (!dbproc->tds_socket)
4640  return NULL;
4641 
4642  dbnumrets(dbproc);
4643 
4644  param_info = dbproc->tds_socket->param_info;
4645  if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
4646  return NULL;
4647  return tds_dstr_buf(&param_info->columns[retnum - 1]->column_name);
4648 }
4649 
4650 /**
4651  * \ingroup dblib_rpc
4652  * \brief Get value of an output parameter filled by a stored procedure.
4653  *
4654  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4655  * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
4656  * \returns Address of a return parameter value, or \c NULL if no such \a retnum.
4657  * \sa dbnextrow(), dbnumrets(), dbresults(), dbretlen(), dbretname(), dbrettype(), dbrpcinit(), dbrpcparam().
4658  * \todo Handle blobs.
4659  */
4660 BYTE *
4662 {
4663  TDSPARAMINFO *param_info;
4664 
4665  tdsdump_log(TDS_DBG_FUNC, "dbretdata(%p, %d)\n", dbproc, retnum);
4667 
4668  dbnumrets(dbproc);
4669 
4670  param_info = dbproc->tds_socket->param_info;
4671  if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
4672  return NULL;
4673 
4674  return _dbcoldata(param_info->columns[retnum - 1]);
4675 }
4676 
4677 /**
4678  * \ingroup dblib_rpc
4679  * \brief Get size of an output parameter filled by a stored procedure.
4680  *
4681  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4682  * \param retnum Nth parameter between \c 1 and the return value from \c dbnumrets().
4683  * \returns Size of a return parameter value, or \c NULL if no such \a retnum.
4684  * \sa dbnextrow(), dbnumrets(), dbresults(), dbretdata(), dbretname(), dbrettype(), dbrpcinit(), dbrpcparam().
4685  */
4686 int
4687 dbretlen(DBPROCESS * dbproc, int retnum)
4688 {
4689  TDSCOLUMN *column;
4690  TDSPARAMINFO *param_info;
4691  TDSSOCKET *tds;
4692 
4693  tdsdump_log(TDS_DBG_FUNC, "dbretlen(%p, %d)\n", dbproc, retnum);
4695 
4696  dbnumrets(dbproc);
4697 
4698  tds = dbproc->tds_socket;
4699  param_info = tds->param_info;
4700  if (!param_info || !param_info->columns || retnum < 1 || retnum > param_info->num_cols)
4701  return -1;
4702 
4703  column = param_info->columns[retnum - 1];
4704  if (column->column_cur_size < 0)
4705  return 0;
4706 
4707  return column->column_cur_size;
4708 }
4709 
4710 /**
4711  * \ingroup dblib_core
4712  * \brief Wait for results of a query from the server.
4713  *
4714  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4715  * \retval SUCCEED everything worked, fetch results with \c dbnextresults().
4716  * \retval FAIL SQL syntax error, typically.
4717  * \sa dbcmd(), dbfcmd(), DBIORDESC(), DBIOWDESC(), dbmoretext(), dbnextrow(),
4718  dbpoll(), DBRBUF(), dbresults(), dbretstatus(), dbrpcsend(), dbsettime(), dbsqlexec(),
4719  dbsqlsend(), dbwritetext().
4720  */
4721 RETCODE
4723 {
4724  TDSSOCKET *tds;
4725  TDS_INT result_type;
4726  RETCODE return_code = SUCCEED;
4727  prbuf_t prretbuf;
4728 
4729  tdsdump_log(TDS_DBG_FUNC, "dbsqlok(%p)\n", dbproc);
4730  CHECK_CONN(FAIL);
4731 
4732  tds = dbproc->tds_socket;
4733 
4734  /*
4735  * dbsqlok has been called after dbmoretext()
4736  * This is the trigger to send the text data.
4737  */
4738 
4739  if (dbproc->text_sent) {
4741  dbproc->text_sent = 0;
4742  }
4743 
4744  /*
4745  * See what the next packet from the server is.
4746  * We want to skip any messages which are not processable.
4747  * We're looking for a result token or a done token.
4748  */
4749  for (;;) {
4750  TDSRET tds_code;
4751  int done_flags = 0;
4752 
4753  /*
4754  * If we hit an end token -- e.g. if the command
4755  * submitted returned no data (like an insert) -- then
4756  * we process the end token to extract the status code.
4757  */
4758  tdsdump_log(TDS_DBG_FUNC, "dbsqlok() not done, calling tds_process_tokens()\n");
4759 
4760  tds_code = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS);
4761 
4762  /*
4763  * The error flag may be set for any intervening DONEINPROC packet, in particular
4764  * by a RAISERROR statement. Microsoft db-lib returns FAIL in that case.
4765  */
4766  if (done_flags & TDS_DONE_ERROR) {
4767  return_code = FAIL;
4768  }
4769 
4770  switch (tds_code) {
4771  case TDS_NO_MORE_RESULTS:
4772  return SUCCEED;
4773  break;
4774 
4775  case TDS_SUCCESS:
4776  switch (result_type) {
4777  case TDS_ROWFMT_RESULT:
4780  case TDS_COMPUTEFMT_RESULT:
4782  case TDS_COMPUTE_RESULT:
4783  case TDS_ROW_RESULT:
4784  tdsdump_log(TDS_DBG_FUNC, "dbsqlok() found result token\n");
4785  return SUCCEED;
4786  break;
4787  case TDS_DONEINPROC_RESULT:
4788  break;
4789  case TDS_DONE_RESULT:
4790  case TDS_DONEPROC_RESULT:
4791  tdsdump_log(TDS_DBG_FUNC, "dbsqlok() end status is %s\n", prdbretcode(return_code, prretbuf));
4792 #if 1
4793  if (done_flags & TDS_DONE_ERROR) {
4794 
4795  if (done_flags & TDS_DONE_MORE_RESULTS) {
4797  } else {
4799  }
4800 
4801  } else {
4802  tdsdump_log(TDS_DBG_FUNC, "dbsqlok() end status was success\n");
4803 
4805  }
4806 
4807  return return_code;
4808  break;
4809 #else
4810  int retcode = (done_flags & TDS_DONE_ERROR)? FAIL : SUCCEED;
4811  dbproc->dbresults_state = (done_flags & TDS_DONE_MORE_RESULTS)?
4813 
4814  tdsdump_log(TDS_DBG_FUNC, "dbsqlok: returning %s with %s (%#x)\n",
4815  prdbretcode(retcode), prdbresults_state(dbproc->dbresults_state), done_flags);
4816 
4817  if (retcode == SUCCEED && (done_flags & TDS_DONE_MORE_RESULTS))
4818  continue;
4819 
4820  return retcode;
4821 #endif
4822  default:
4823  tdsdump_log(TDS_DBG_FUNC, "%s %d: logic error: tds_process_tokens result_type %d\n",
4824  __FILE__, __LINE__, result_type);
4825  break;
4826  }
4827  break;
4828 
4829  default:
4830  assert(TDS_FAILED(tds_code));
4831  return FAIL;
4832  break;
4833  }
4834  }
4835 
4836  return SUCCEED;
4837 }
4838 
4839 /**
4840  * \ingroup dblib_core
4841  * \brief Get count of columns in a compute row.
4842  *
4843  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4844  * \param computeid of \c COMPUTE clause to which we're referring.
4845  * \return number of columns, else -1 if no such \a computeid.
4846  * \sa dbadata(), dbadlen(), dbaltlen(), dbalttype(), dbgetrow(), dbnextrow(), dbnumcols().
4847  */
4848 int
4849 dbnumalts(DBPROCESS * dbproc, int computeid)
4850 {
4851  TDSSOCKET *tds;
4853  TDS_SMALLINT compute_id;
4854  TDS_UINT i;
4855 
4856  tdsdump_log(TDS_DBG_FUNC, "dbnumalts(%p, %d)\n", dbproc, computeid);
4858 
4859  tds = dbproc->tds_socket;
4860  compute_id = computeid;
4861 
4862  for (i = 0;; ++i) {
4863  if (i >= tds->num_comp_info)
4864  return -1;
4865  info = tds->comp_info[i];
4866  if (info->computeid == compute_id)
4867  break;
4868  }
4869 
4870  return info->num_cols;
4871 }
4872 
4873 /**
4874  * \ingroup dblib_core
4875  * \brief Get count of \c COMPUTE clauses for a result set.
4876  *
4877  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4878  * \return number of compute clauses for the current query, possibly zero.
4879  * \sa dbnumalts(), dbresults().
4880  */
4881 int
4883 {
4884  TDSSOCKET *tds;
4885 
4886  tdsdump_log(TDS_DBG_FUNC, "dbnumcompute(%p)\n", dbproc);
4888 
4889  tds = dbproc->tds_socket;
4890 
4891  return tds->num_comp_info;
4892 }
4893 
4894 
4895 /**
4896  * \ingroup dblib_core
4897  * \brief Get \c bylist for a compute row.
4898  *
4899  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4900  * \param computeid of \c COMPUTE clause to which we're referring.
4901  * \param size \em output: size of \c bylist buffer whose address is returned, possibly zero.
4902  * \return address of \c bylist for \a computeid.
4903  * \retval NULL no such \a computeid.
4904  * \remarks Do not free returned pointer.
4905  * \sa dbadata(), dbadlen(), dbaltlen(), dbalttype(), dbcolname(), dbgetrow(), dbnextrow().
4906  */
4907 BYTE *
4908 dbbylist(DBPROCESS * dbproc, int computeid, int *size)
4909 {
4910  TDSSOCKET *tds;
4912  TDS_UINT i;
4913  const TDS_SMALLINT byte_flag = -0x8000;
4914 
4915  tdsdump_log(TDS_DBG_FUNC, "dbbylist(%p, %d, %p)\n", dbproc, computeid, size);
4917 
4918  tds = dbproc->tds_socket;
4919 
4920  for (i = 0;; ++i) {
4921  if (i >= tds->num_comp_info) {
4922  if (size)
4923  *size = 0;
4924  return NULL;
4925  }
4926  info = tds->comp_info[i];
4927  if (info->computeid == computeid)
4928  break;
4929  }
4930 
4931  if (size)
4932  *size = info->by_cols;
4933 
4934  /*
4935  * libtds stores this information using TDS_SMALLINT so we
4936  * have to convert it. We can do this because libtds just
4937  * stores these data.
4938  */
4939  if (info->by_cols > 0 && info->bycolumns[0] != byte_flag) {
4940  int n;
4941  TDS_TINYINT *p = (TDS_TINYINT*) malloc(sizeof(info->bycolumns[0]) + info->by_cols);
4942  if (!p) {
4943  dbperror(dbproc, SYBEMEM, errno);
4944  return NULL;
4945  }
4946  for (n = 0; n < info->by_cols; ++n)
4947  p[sizeof(info->bycolumns[0]) + n] = info->bycolumns[n] > 255 ? 255 : info->bycolumns[n];
4948  *((TDS_SMALLINT *)p) = byte_flag;
4949  free(info->bycolumns);
4950  info->bycolumns = (TDS_SMALLINT *) p;
4951  }
4952  return (BYTE *) (&info->bycolumns[1]);
4953 }
4954 
4955 /** \internal
4956  * \ingroup dblib_internal
4957  * \brief Check if \a dbproc is an ex-parrot.
4958  *
4959  * \param dbproc contains all information needed by db-lib to manage communications with the server.
4960  * \retval TRUE process has been marked \em dead.
4961  * \retval FALSE process is OK.
4962  * \remarks dbdead() does not communicate with the server.
4963  * Unless a previously db-lib marked \a dbproc \em dead, dbdead() returns \c FALSE.
4964  * \sa dberrhandle().
4965  */
4966 DBBOOL
4968 {
4969  tdsdump_log(TDS_DBG_FUNC, "dbdead(%p) [%s]\n", dbproc, dbproc? IS_TDSDEAD(dbproc->tds_socket)? "dead":"alive" : "quite dead");
4970 
4971  if( NULL == dbproc )
4972  return TRUE;
4973 
4975  return TRUE;
4976  else
4977  return FALSE;
4978 }
4979 
4980 /** \internal
4981  * \ingroup dblib_internal
4982  * \brief default error handler for db-lib (handles library-generated errors)
4983  *
4984  * The default error handler doesn't print anything. If you want to see your messages printed,
4985  * install an error handler. If you think that should be an optional compile- or run-time default,
4986  * submit a patch. It could be done.
4987  *
4988  * \sa DBDEAD(), dberrhandle().
4989  */
4990 /* Thus saith Sybase:
4991  * "If the user does not supply an error handler (or passes a NULL pointer to
4992  * dberrhandle), DB-Library will exhibit its default error-handling
4993  * behavior: It will abort the program if the error has made the affected
4994  * DBPROCESS unusable (the user can call DBDEAD to determine whether
4995  * or not a DBPROCESS has become unusable). If the error has not made the
4996  * DBPROCESS unusable, DB-Library will simply return an error code to its caller."
4997  *
4998  * It is not the error handler, however, that aborts anything. It is db-lib, cf. dbperror().
4999  */
5000 static int
5001 default_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
5002 {
5003  tdsdump_log(TDS_DBG_FUNC, "default_err_handler %p, %d, %d, %d, %p, %p", dbproc, severity, dberr, oserr, dberrstr, oserrstr);
5004 
5005  if (DBDEAD(dbproc) && (!dbproc || !dbproc->msdblib)) {
5006  return INT_EXIT;
5007  }
5008 
5009  if (!dbproc || !dbproc->msdblib) { /* i.e. Sybase behavior */
5010  switch(dberr) {
5011  case SYBETIME:
5012  return INT_EXIT;
5013  default:
5014  break;
5015  }
5016  }
5017  return INT_CANCEL;
5018 }
5019 
5020 /**
5021  * \ingroup dblib_core
5022  * \brief Set an error handler, for messages from db-lib.
5023  *
5024  * \param handler pointer to callback function that will handle errors.
5025  * Pass NULL to restore the default handler.
5026  * \return address of prior handler, or NULL if none was previously installed.
5027  * \sa DBDEAD(), dbmsghandle().
5028  */
5031 {
5032  EHANDLEFUNC old_handler = _dblib_err_handler;
5033 
5034  tdsdump_log(TDS_DBG_FUNC, "dberrhandle(%p)\n", handler);
5035 
5037 
5038  return (old_handler == default_err_handler)? NULL : old_handler;
5039 }
5040 
5041 /**
5042  * \ingroup dblib_core
5043  * \brief Set a message handler, for messages from the server.
5044  *
5045  * \param handler address of the function that will process the messages.
5046  * \sa DBDEAD(), dberrhandle().
5047  */
5050 {
5052 
5053  tdsdump_log(TDS_DBG_FUNC, "dbmsghandle(%p)\n", handler);
5054 
5056  return retFun;
5057 }
5058 
5059 #if defined(DBLIB_UNIMPLEMENTED)
5060 /**
5061  * \ingroup dblib_money
5062  * \brief Add two DBMONEY values.
5063  *
5064  * \param dbproc contains all information needed by db-lib to manage communications with the server.
5065  * \param m1 first operand.
5066  * \param m2 other operand.
5067  * \param sum \em output: result of computation.
5068  * \retval SUCCEED Always.
5069  * \sa dbmnyadd(), dbmnysub(), dbmnymul(), dbmnydivide(), dbmnyminus(), dbmny4add(), dbmny4sub(), dbmny4mul(), dbmny4divide(), dbmny4minus().
5070  * \todo Unimplemented.
5071  */
5072 RETCODE
5073 dbmnyadd(DBPROCESS * dbproc, DBMONEY * m1, DBMONEY * m2, DBMONEY * sum)
5074 {
5075  tdsdump_log(TDS_DBG_FUNC, "dbmnyadd(%p, %p, %p, %p)\n", dbproc, m1, m2, sum);
5076  CHECK_CONN(FAIL);
5077  CHECK_NULP(m1, "dbmnyadd", 2, FAIL);
5078  CHECK_NULP(m2, "dbmnyadd", 3, FAIL);
5079  CHECK_NULP(sum, "dbmnyadd", 4, FAIL);
5080 
5081  tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbmnyadd()\n");
5082  return