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