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