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