1/*
2 *  trace.c
3 *
4 *  $Id: trace.c,v 1.21 2007/10/07 10:48:35 source Exp $
5 *
6 *  Trace functions
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
11 *  All Rights Reserved.
12 *
13 *  This software is released under the terms of either of the following
14 *  licenses:
15 *
16 *      - GNU Library General Public License (see LICENSE.LGPL)
17 *      - The BSD License (see LICENSE.BSD).
18 *
19 *  Note that the only valid version of the LGPL license as far as this
20 *  project is concerned is the original GNU Library General Public License
21 *  Version 2, dated June 1991.
22 *
23 *  While not mandated by the BSD license, any patches you make to the
24 *  iODBC source code may be contributed back into the iODBC project
25 *  at your discretion. Contributions will benefit the Open Source and
26 *  Data Access community as a whole. Submissions may be made at:
27 *
28 *      http://www.iodbc.org
29 *
30 *
31 *  GNU Library Generic Public License Version 2
32 *  ============================================
33 *  This library is free software; you can redistribute it and/or
34 *  modify it under the terms of the GNU Library General Public
35 *  License as published by the Free Software Foundation; only
36 *  Version 2 of the License dated June 1991.
37 *
38 *  This library is distributed in the hope that it will be useful,
39 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 *  Library General Public License for more details.
42 *
43 *  You should have received a copy of the GNU Library General Public
44 *  License along with this library; if not, write to the Free
45 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46 *
47 *
48 *  The BSD License
49 *  ===============
50 *  Redistribution and use in source and binary forms, with or without
51 *  modification, are permitted provided that the following conditions
52 *  are met:
53 *
54 *  1. Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 *  2. Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in
58 *     the documentation and/or other materials provided with the
59 *     distribution.
60 *  3. Neither the name of OpenLink Software Inc. nor the names of its
61 *     contributors may be used to endorse or promote products derived
62 *     from this software without specific prior written permission.
63 *
64 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77
78#ifdef HAVE_CONFIG_H
79#include "config.h"
80#endif
81
82#include <stdlib.h>
83#include <stdio.h>
84#include <stdarg.h>
85#include <ctype.h>
86#include <pwd.h>
87#include <unistd.h>
88#include <fcntl.h>
89
90#include <time.h>
91#ifdef TIME_WITH_SYS_TIME
92#include <sys/time.h>
93#endif
94
95#include <sql.h>
96#include <sqlext.h>
97#include <sqlucode.h>
98
99#include "herr.h"
100#include "henv.h"
101#include "ithread.h"
102#include "trace.h"
103#include "unicode.h"
104
105#define NO_CARBON 1
106#if defined(macintosh)
107# include       <Errors.h>
108# include       <OSUtils.h>
109# include       <Processes.h>
110#elif defined(__APPLE__) && !defined(NO_CARBON)
111# include       <Carbon/Carbon.h>
112#endif
113
114
115/*
116 *  Limit the size of the tracefile, to avoid a core dump when the
117 *  the RLIMIT_FSIZE is reached.
118 */
119#define	MAX_TRACEFILE_LEN	1000000000L	/* about 1GB */
120
121
122/*
123 *  Global trace flag
124 */
125int ODBCSharedTraceFlag = SQL_OPT_TRACE_OFF;
126
127static char *trace_appname = NULL;
128static char *trace_fname = NULL;
129static FILE *trace_fp = NULL;
130static int   trace_fp_close = 0;
131
132void trace_emit (char *fmt, ...);
133
134#ifdef HAVE_GETTIMEOFDAY
135static struct timeval starttime = {0};
136#endif
137
138
139/*
140 * Internal functions
141 */
142void
143trace_set_appname (char *appname)
144{
145  MEM_FREE (trace_appname);
146  trace_appname = STRDUP (appname);
147}
148
149
150char *
151trace_get_filename (void)
152{
153  return STRDUP (trace_fname);
154}
155
156
157static void
158trace_strftime_now (char *buf, size_t buflen, char *format)
159{
160  time_t now;
161  struct tm *timeNow;
162#ifdef HAVE_LOCALTIME_R
163  struct tm keeptime;
164#endif
165
166  tzset ();
167  time (&now);
168
169#ifdef HAVE_LOCALTIME_R
170  timeNow = localtime_r (&now, &keeptime);
171#else
172  timeNow = localtime (&now);
173#endif
174
175  strftime (buf, buflen, format, timeNow);
176}
177
178
179
180
181void
182trace_set_filename (char *fname)
183{
184  char *s, *p;
185  struct passwd *pwd;
186  char *buf;
187  size_t buf_len, buf_pos;
188  char tmp[255];
189
190  /*  Initialize */
191  MEM_FREE (trace_fname);
192  trace_fname = NULL;
193  buf = (char *) malloc (buf_len = strlen (fname) + sizeof (tmp) + 1);
194  if (!buf)
195    return;			/* No more memory */
196  buf_pos = 0;
197  buf[0] = '\0';
198
199  for (s = fname; *s;)
200    {
201      /*
202       *  Make sure we can fit at least 1 more tmp buffer inside
203       */
204      if (buf_len - buf_pos < sizeof (tmp))
205	buf = realloc (buf, buf_len += sizeof (tmp) + 1);
206      if (!buf)
207	return;			/* No more memory */
208
209      if (*s != '$')
210	{
211	  buf[buf_pos++] = *s++;
212	}
213      else
214	{
215	  /* Handle Escape sequences */
216	  switch (*(s + 1))
217	    {
218	    case '$':
219	      {
220		buf[buf_pos++] = '$';
221		break;
222	      }
223
224	    case 'p':
225	    case 'P':
226	      {
227#if defined (HAVE_SNPRINTF)
228		snprintf (tmp, sizeof (tmp), "%ld", (long) getpid ());
229#else
230		sprintf (tmp, "%ld", (long) getpid ());
231#endif
232		strcpy (&buf[buf_pos], tmp);
233		buf_pos += strlen (tmp);
234		break;
235	      }
236
237	    case 'u':
238	    case 'U':
239	      {
240		if ((pwd = getpwuid (getuid ())) != NULL)
241		  {
242#if defined (HAVE_SNPRINTF)
243		    snprintf (tmp, sizeof (tmp), "%s", pwd->pw_name);
244#else
245		    sprintf (tmp, "%s", pwd->pw_name);
246#endif
247		    strcpy (&buf[buf_pos], tmp);
248		    buf_pos += strlen (tmp);
249		  }
250		break;
251	      }
252
253	    case 'h':
254	    case 'H':
255	      {
256		p = NULL;
257		if ((p = getenv ("HOME")) == NULL)
258		  {
259		    if ((pwd = getpwuid (getuid ())) != NULL)
260		      p = pwd->pw_dir;
261		  }
262
263		if (p)
264		  {
265#if defined (HAVE_SNPRINTF)
266		    snprintf (tmp, sizeof (tmp), "%s", p);
267#else
268		    sprintf (tmp, "%s", p);
269#endif
270		    strcpy (&buf[buf_pos], tmp);
271		    buf_pos += strlen (tmp);
272		  }
273		break;
274	      }
275
276	    case 't':
277	    case 'T':
278	      {
279		trace_strftime_now (tmp, sizeof (tmp), "%Y%m%d-%H%M%S");
280		strcpy (&buf[buf_pos], tmp);
281		buf_pos += strlen (tmp);
282		break;
283	      }
284
285	    default:
286	      /* Skip unknown escapes */
287	      break;
288	    }
289	  s += 2;
290	}
291    }
292
293  buf[buf_pos] = '\0';
294  trace_fname = buf;
295
296  return;
297}
298
299
300void
301trace_start(void)
302{
303  /*
304   *  First stop any previous trace
305   */
306  trace_stop ();
307
308#ifdef HAVE_GETTIMEOFDAY
309  gettimeofday (&starttime, NULL);
310#endif
311
312  /*
313   *  If no trace filename is specified, use the default
314   */
315  if (!trace_fname)
316    trace_fname = STRDUP (SQL_OPT_TRACE_FILE_DEFAULT);
317
318#if defined (stderr)
319  else if (STRCASEEQ (trace_fname, "stderr"))
320    {
321      trace_fp = stderr;
322    }
323#endif
324
325  else
326    {
327      int fd;
328      int fd_flags = O_WRONLY | O_CREAT | O_TRUNC;
329      int fd_mode = 0644;
330
331
332#if defined (unix)
333      /*
334       *  As this is a security risk, we do not allow root to overwrite a file
335       */
336      if (geteuid () == 0)
337	{
338	  fd_flags |= O_EXCL;
339	}
340#endif
341
342      fd = open (trace_fname, fd_flags, fd_mode);
343      if (fd < 0 || (trace_fp = fdopen (fd, "w")) == NULL)
344	{
345	  return;		/* no tracing */
346	}
347
348      trace_fp_close = 1;
349
350      /*
351       *  Set trace stream to line buffered
352       */
353      setvbuf (trace_fp, NULL, _IOLBF, 0);
354    }
355
356  /*
357   *  Initialize the debug stream
358   */
359  if (trace_fp == NULL)
360    {
361      return;
362    }
363  else
364    {
365      char mesgBuf[200];
366
367      trace_emit ("** iODBC Trace file\n");
368
369      /*
370       *  Show start time
371       */
372      trace_strftime_now (mesgBuf, sizeof (mesgBuf),
373	  "** Trace started on %a %b %d %H:%M:%S %Y");
374      trace_emit ("%s\n", mesgBuf);
375
376      /*
377       *  Show Driver Manager version similar to SQLGetInfo (SQL_DM_VER)
378       */
379      sprintf ((char *) mesgBuf, "%02d.%02d.%04d.%04d",
380	  SQL_SPEC_MAJOR,
381	  SQL_SPEC_MINOR, IODBC_BUILD / 10000, IODBC_BUILD % 10000);
382      trace_emit ("** Driver Manager: %s\n\n", mesgBuf);
383    }
384
385#if defined (linux)
386  {
387    extern char *__progname;
388    trace_set_appname (__progname);
389  }
390#elif defined(macintosh) || (defined(__APPLE__) && !defined(NO_CARBON))
391  {
392    ProcessSerialNumber PSN;
393    ProcessInfoRec prec;
394    unsigned char processName[40];
395
396    GetCurrentProcess (&PSN);
397
398    prec.processInfoLength = sizeof (ProcessInfoRec);
399    prec.processName = processName;
400    prec.processAppSpec = NULL;
401
402    if (GetProcessInformation (&PSN, &prec) == noErr)
403      {
404	processName[processName[0] + 1] = '\0';
405	trace_set_appname (processName + 1);
406      }
407    else
408      trace_set_appname ("{No Application Name}");
409  }
410#elif defined(__APPLE__)
411#ifdef MACOSX102
412  {
413    trace_set_appname ("{No Application Name}");
414  }
415#else
416  {
417    trace_set_appname ((char *) getprogname ());
418  }
419#endif
420#endif
421
422  /*
423   *  Turn on tracing flag
424   */
425  ODBCSharedTraceFlag = SQL_OPT_TRACE_ON;
426
427  return;
428}
429
430
431void
432trace_stop(void)
433{
434  char mesgBuf[200];
435  time_t now;
436  struct tm *timeNow;
437
438  if (trace_fp)
439    {
440      /*
441       * Show end time
442       */
443      trace_strftime_now (mesgBuf, sizeof (mesgBuf),
444	  "** Trace finished on %a %b %d %H:%M:%S %Y");
445      trace_emit ("\n%s\n", mesgBuf);
446
447      if (trace_fp_close)
448	fclose (trace_fp);
449    }
450
451  ODBCSharedTraceFlag = SQL_OPT_TRACE_OFF;
452  trace_fp = NULL;
453  trace_fp_close = 0;
454}
455
456
457void
458trace_emitc (char c)
459{
460  /*
461   * Make sure tracing is enabled
462   */
463  if (!trace_fp)
464    {
465      ODBCSharedTraceFlag = SQL_OPT_TRACE_OFF;
466      return;
467    }
468
469  fputc (c, trace_fp);
470}
471
472
473void
474trace_emit (char *fmt, ...)
475{
476  va_list ap;
477
478  /*
479   * Make sure tracing is enabled
480   */
481  if (!trace_fp)
482    {
483      ODBCSharedTraceFlag = SQL_OPT_TRACE_OFF;
484      return;
485    }
486
487  va_start (ap, fmt);
488  vfprintf (trace_fp, fmt, ap);
489  va_end (ap);
490}
491
492
493void
494trace_emit_string (SQLCHAR *str, int len, int is_utf8)
495{
496  ssize_t length = len;
497  int i, j;
498  long col;
499  SQLCHAR *ptr;
500  int bytes;
501  int truncated = 0;
502
503  if (!str)
504    return;
505
506  if (len == SQL_NTS)
507    length = strlen ((char *) str);
508  else if (len <= 0)
509    return;
510
511  /*
512   *  Guard against very long strings
513   */
514  if (length > MAX_EMIT_STRING)
515    {
516      length = MAX_EMIT_STRING;
517      truncated = 1;
518    }
519
520  /*
521   *  Dump the (optional UTF-8) string in chunks of 40 characters
522   */
523  ptr = str;
524  col = 0;
525  for (i = 0; i < length; i += bytes)
526    {
527      register int c = *ptr;
528
529      /*
530       *   Assume this is a nul-terminated string
531       */
532      if (!c)
533        break;
534
535      /*
536       *  Print prefix
537       */
538      if (col == 0)
539	trace_emit ("\t\t\t\t  | ");
540
541      /*
542       *  Take care of UTF-8 encoding
543       */
544      if (!is_utf8)
545	bytes = 1;
546      else if (c < 128)
547	bytes = 1;
548      else if ((c & 0xE0) == 0xC0)
549	bytes = 2;
550      else if ((c & 0xF0) == 0xE0)
551	bytes = 3;
552      else if ((c & 0xF8) == 0xF0)
553	bytes = 4;
554      else if ((c & 0xFC) == 0xF8)
555        bytes = 5;
556      else if ((c & 0xFE) == 0xFC)
557        bytes = 6;
558      else
559	bytes = -1;	/* Wrong UTF8 character */
560
561      if (bytes > 0)
562        {
563	  /*
564	   *  Emit the number of bytes calculated
565	   */
566	  for (j = 0; j < bytes; j++)
567	    trace_emitc (*ptr++);
568	}
569      else
570        {
571	  /*
572	   *  Skip this bogus UTF8 character sequence and emit a single #
573	   */
574	  for (bytes = 1, ptr++; (*ptr & 0xC0) == 0x80; bytes++)
575	    ptr++;
576	  trace_emitc ('#');
577	}
578
579      /*
580       *  After 40 characters, start a new line
581       */
582      if (++col >= 40)
583	{
584	  trace_emit (" |\n");
585	  col = 0;
586	}
587    }
588
589  /*
590   *  Pad the last part of the string with spaces
591   */
592  if (col > 0)
593    {
594      for (i = col; i < 40; i++)
595	trace_emitc (' ');
596      trace_emit (" |\n");
597    }
598
599  if (truncated)
600    trace_emit ("\t\t\t\t  | %-40.40s |\n", "(truncated)");
601}
602
603
604void
605trace_emit_binary (unsigned char *str, int len)
606{
607  long length = len;
608  int i;
609  long col;
610  unsigned char *ptr;
611  int truncated = 0;
612  char buf[80];
613  char *HEX = "0123456789ABCDEF";
614
615  if (!str || len <= 0)
616    return;
617
618  /*
619   *  Guard against very long binary buffers
620   */
621  if (length > MAX_EMIT_BINARY)
622    {
623      length = MAX_EMIT_BINARY;
624      truncated = 1;
625    }
626
627  ptr = str;
628  col = 0;
629  memset (buf, ' ', sizeof (buf));
630  buf[40] = '\0';
631  for (i = 0; i < length; i++)
632    {
633      unsigned char c = *ptr++;
634
635      /*
636       *  Put data into buffer
637       */
638      buf[3 * col] = HEX[(c >> 4) & 0xF];
639      buf[3 * col + 1] = HEX[c & 0xF];
640      if (isprint (c))
641	buf[30 + col] = c;
642      else
643	buf[30 + col] = '.';
644
645      /*
646       *  After 10 bytes, start a new line
647       */
648      if (++col > 9)
649	{
650	  trace_emit_string ((SQLCHAR *) buf, 40, 0);
651	  col = 0;
652	  memset (buf, ' ', sizeof (buf));
653	}
654    }
655
656  /*
657   *  Pad the last part of the string with spaces
658   */
659  if (col > 0)
660    trace_emit_string ((SQLCHAR *) buf, 40, 0);
661
662  if (truncated)
663    trace_emit ("\t\t\t\t  | %-40.40s |\n", "(truncated)");
664}
665
666
667void
668_trace_print_function (int func, int trace_leave, int retcode)
669{
670  extern char *odbcapi_symtab[];
671  char *ptr = "invalid retcode";
672#ifdef HAVE_GETTIMEOFDAY
673  struct timeval tv;
674#endif
675
676  /*
677   * Guard against tracefile getting too big
678   */
679  if (trace_fp && ftell (trace_fp) > MAX_TRACEFILE_LEN)
680    {
681 	trace_emit ("\n*** TRACEFILE LIMIT REACHED ***\n");
682	trace_stop ();
683 	return;
684    }
685
686  /*
687   * Calculate timestamp
688   */
689#ifdef HAVE_GETTIMEOFDAY
690  gettimeofday (&tv, NULL);
691  tv.tv_sec -= starttime.tv_sec;
692  tv.tv_usec -= starttime.tv_usec;
693  if (tv.tv_usec < 0)
694    {
695      tv.tv_sec--;
696      tv.tv_usec += 1000000L;
697    }
698  trace_emit ("\n[%06ld.%06ld]\n", tv.tv_sec, tv.tv_usec);
699#else
700  trace_emit ("\n");
701#endif
702
703  switch (retcode)
704    {
705      _S (SQL_SUCCESS);
706      _S (SQL_SUCCESS_WITH_INFO);
707      _S (SQL_NO_DATA_FOUND);
708      _S (SQL_NEED_DATA);
709      _S (SQL_INVALID_HANDLE);
710      _S (SQL_ERROR);
711      _S (SQL_STILL_EXECUTING);
712    }
713
714#ifndef THREAD_IDENT
715#define THREAD_IDENT 0UL
716#endif
717
718  if (trace_leave == TRACE_LEAVE)
719    trace_emit ("%-15.15s %08lX EXIT  %s with return code %d (%s)\n",
720	trace_appname ? trace_appname : "Application",
721	THREAD_IDENT, odbcapi_symtab[func], retcode, ptr);
722  else
723    trace_emit ("%-15.15s %08lX ENTER %s\n",
724	trace_appname ? trace_appname : "Application",
725	THREAD_IDENT, odbcapi_symtab[func]);
726}
727
728
729static char *_trace_sym_handletype[] = {
730  "SQLHANDLE",
731  "SQLHENV",
732  "SQLHDBC",
733  "SQLHSTMT",
734  "SQLDESC",
735  "SQLSENV"
736};
737
738
739void
740_trace_handletype (SQLSMALLINT type)
741{
742  char *ptr = "invalid handle type";
743  switch (type)
744    {
745      _S (SQL_HANDLE_ENV);
746      _S (SQL_HANDLE_DBC);
747      _S (SQL_HANDLE_STMT);
748#if ODBCVER >= 0x0300
749      _S (SQL_HANDLE_DESC);
750      _S (SQL_HANDLE_SENV);
751#endif
752    }
753
754  trace_emit ("\t\t%-15.15s   %d (%s)\n", "SQLSMALLINT", (int) type, ptr);
755}
756
757
758void
759_trace_handle_p (SQLSMALLINT type, SQLHANDLE * handle, int output)
760{
761  if (!handle)
762    trace_emit ("\t\t%-15.15s * 0x0 (%s)\n",
763	_trace_sym_handletype[type], "SQL_NULL_HANDLE");
764  else if (output)
765    trace_emit ("\t\t%-15.15s * %p (%p)\n",
766	_trace_sym_handletype[type], handle, *handle);
767  else
768    trace_emit ("\t\t%-15.15s * %p\n", _trace_sym_handletype[type], handle);
769}
770
771
772void
773_trace_handle (SQLSMALLINT type, SQLHANDLE handle)
774{
775  if (!handle)
776    trace_emit ("\t\t%-15.15s   0x0 (%s)\n",
777	_trace_sym_handletype[type], "SQL_NULL_HANDLE");
778  else
779    trace_emit ("\t\t%-15.15s   %p\n", _trace_sym_handletype[type], handle);
780}
781
782
783/*
784 *  Trace basic data types
785 */
786void
787_trace_smallint (SQLSMALLINT i)
788{
789  trace_emit ("\t\t%-15.15s   %ld\n", "SQLSMALLINT", (long) i);
790}
791
792
793void
794_trace_usmallint (SQLUSMALLINT i)
795{
796  trace_emit ("\t\t%-15.15s   %lu\n", "SQLUSMALLINT", (unsigned long) i);
797}
798
799
800void
801_trace_integer (SQLINTEGER i)
802{
803  trace_emit ("\t\t%-15.15s   %ld\n", "SQLINTEGER", (long) i);
804}
805
806
807void
808_trace_uinteger (SQLUINTEGER i)
809{
810  trace_emit ("\t\t%-15.15s   %lu\n", "SQLUINTEGER", (unsigned long) i);
811}
812
813
814void
815_trace_pointer (SQLPOINTER p)
816{
817  if (!p)
818    trace_emit ("\t\t%-15.15s   0x0\n", "SQLPOINTER");
819  else
820    trace_emit ("\t\t%-15.15s   %p\n", "SQLPOINTER", p);
821}
822
823
824void
825_trace_smallint_p (SQLSMALLINT *p, int output)
826{
827  if (!p)
828    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLSMALLINT");
829  else if (output)
830    trace_emit ("\t\t%-15.15s * %p (%ld)\n", "SQLSMALLINT", p, (long) *p);
831  else
832    trace_emit ("\t\t%-15.15s * %p\n", "SQLSMALLINT", p);
833}
834
835
836void
837_trace_usmallint_p (SQLUSMALLINT *p, int output)
838{
839  if (!p)
840    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLUSMALLINT");
841  else if (output)
842    trace_emit ("\t\t%-15.15s * %p (%lu)\n", "SQLUSMALLINT", p, (unsigned long) *p);
843  else
844    trace_emit ("\t\t%-15.15s * %p\n", "SQLUSMALLINT", p);
845}
846
847
848void
849_trace_integer_p (SQLINTEGER *p, int output)
850{
851  if (!p)
852    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLINTEGER");
853  else if (output)
854    trace_emit ("\t\t%-15.15s * %p (%ld)\n", "SQLINTEGER", p, (long) *p);
855  else
856    trace_emit ("\t\t%-15.15s * %p\n", "SQLINTEGER", p);
857}
858
859
860void
861_trace_uinteger_p (SQLUINTEGER *p, int output)
862{
863  if (!p)
864    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLUINTEGER");
865  else if (output)
866    trace_emit ("\t\t%-15.15s * %p (%lu)\n", "SQLUINTEGER", p, (unsigned long) *p);
867  else
868    trace_emit ("\t\t%-15.15s * %p\n", "SQLUINTEGER", p);
869}
870
871
872void
873_trace_stringlen (char *type, SQLINTEGER len)
874{
875  if (len == SQL_NTS)
876    trace_emit ("\t\t%-15.15s   %ld (SQL_NTS)\n", type, (long) len);
877  else
878    trace_emit ("\t\t%-15.15s   %ld\n", type, (long) len);
879}
880
881void
882_trace_len (SQLLEN i)
883{
884#ifdef _WIN64
885  trace_emit ("\t\t%-15.15s   %I64d\n", "SQLLEN", (INT64) i);
886#else
887  trace_emit ("\t\t%-15.15s   %ld\n", "SQLLEN", (long) i);
888#endif
889}
890
891
892void
893_trace_ulen (SQLULEN i)
894{
895#ifdef _WIN64
896  trace_emit ("\t\t%-15.15s   %I64u\n", "SQLLEN", (UINT64) i);
897#else
898  trace_emit ("\t\t%-15.15s   %ld\n", "SQLLEN", (unsigned long) i);
899#endif
900}
901
902
903void
904_trace_len_p (SQLLEN *p, int output)
905{
906  if (!p)
907    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLLEN");
908  else if (output)
909#ifdef _WIN64
910    trace_emit ("\t\t%-15.15s * %p (%I64d)\n", "SQLLEN", p, (INT64) *p);
911#else
912    trace_emit ("\t\t%-15.15s * %p (%ld)\n", "SQLLEN", p, (long) *p);
913#endif
914  else
915    trace_emit ("\t\t%-15.15s * %p\n", "SQLLEN", p);
916}
917
918
919void
920_trace_ulen_p (SQLULEN *p, int output)
921{
922  if (!p)
923    trace_emit ("\t\t%-15.15s * 0x0\n", "SQLULEN");
924  else if (output)
925#ifdef _WIN64
926    trace_emit ("\t\t%-15.15s * %p (%I64u)\n", "SQLULEN", p, (UINT64) *p);
927#else
928    trace_emit ("\t\t%-15.15s * %p (%lu)\n", "SQLULEN", p, (unsigned long) *p);
929#endif
930  else
931    trace_emit ("\t\t%-15.15s * %p\n", "SQLULEN", p);
932}
933
934
935void
936_trace_string (SQLCHAR * str, SQLSMALLINT len, SQLSMALLINT * lenptr, int output)
937{
938  long length;
939
940  if (!str)
941    {
942      trace_emit ("\t\t%-15.15s * 0x0\n", "SQLCHAR");
943      return;
944    }
945
946  trace_emit ("\t\t%-15.15s * %p\n", "SQLCHAR", str);
947
948  if (!output)
949    return;
950
951  /*
952   *  Calculate length of string
953   */
954  if (lenptr)
955    length = *lenptr;
956  else
957    length = len;
958
959  if (length == SQL_NTS)
960    length = STRLEN (str);
961
962  if (*str && length)
963    trace_emit_string (str, length, 0);
964  else
965    trace_emit_string ( (SQLCHAR *) "(empty string)", SQL_NTS, 0);
966
967  return;
968}
969
970
971void
972_trace_string_w (SQLWCHAR * str, SQLSMALLINT len, SQLSMALLINT * lenptr,
973    int output)
974{
975  long length;
976
977  if (!str)
978    {
979      trace_emit ("\t\t%-15.15s * 0x0\n", "SQLWCHAR");
980      return;
981    }
982
983  trace_emit ("\t\t%-15.15s * %p\n", "SQLWCHAR", str);
984
985  if (!output)
986    return;
987
988  /*
989   *  Calculate length of string
990   */
991  if (lenptr)
992    length = *lenptr;
993  else
994    length = len;
995
996  if (length == SQL_NTS)
997    length = wcslen (str);
998
999  /*
1000   *  Translate wide string into UTF-8 format and print it
1001   */
1002  if (*str && length)
1003    {
1004      SQLCHAR *str_u8 = dm_SQL_W2A (str, length);
1005      trace_emit_string (str_u8, SQL_NTS, 1);
1006      free (str_u8);
1007    }
1008  else
1009    trace_emit_string ((SQLCHAR *)"(empty string)", SQL_NTS, 0);
1010
1011  return;
1012}
1013
1014
1015void
1016_trace_c_type (SQLSMALLINT type)
1017{
1018  char *ptr = "unknown C type";
1019
1020  switch (type)
1021    {
1022      _S (SQL_C_BINARY);
1023      _S (SQL_C_BIT);
1024      /* _S (SQL_C_BOOKMARK); */
1025      _S (SQL_C_CHAR);
1026      _S (SQL_C_DATE);
1027      _S (SQL_C_DEFAULT);
1028      _S (SQL_C_DOUBLE);
1029      _S (SQL_C_FLOAT);
1030#if (ODBCVER >= 0x0350)
1031      _S (SQL_C_GUID);
1032#endif
1033#if ODBCVER >= 0x0300
1034      _S (SQL_C_INTERVAL_DAY);
1035      _S (SQL_C_INTERVAL_DAY_TO_HOUR);
1036      _S (SQL_C_INTERVAL_DAY_TO_MINUTE);
1037      _S (SQL_C_INTERVAL_DAY_TO_SECOND);
1038      _S (SQL_C_INTERVAL_HOUR);
1039      _S (SQL_C_INTERVAL_HOUR_TO_MINUTE);
1040      _S (SQL_C_INTERVAL_HOUR_TO_SECOND);
1041      _S (SQL_C_INTERVAL_MINUTE);
1042      _S (SQL_C_INTERVAL_MINUTE_TO_SECOND);
1043      _S (SQL_C_INTERVAL_MONTH);
1044      _S (SQL_C_INTERVAL_SECOND);
1045      _S (SQL_C_INTERVAL_YEAR);
1046      _S (SQL_C_INTERVAL_YEAR_TO_MONTH);
1047#endif
1048      _S (SQL_C_LONG);
1049#if ODBCVER >= 0x0300
1050      _S (SQL_C_NUMERIC);
1051      _S (SQL_C_SBIGINT);
1052#endif
1053      _S (SQL_C_SHORT);
1054      _S (SQL_C_SLONG);
1055      _S (SQL_C_SSHORT);
1056      _S (SQL_C_STINYINT);
1057      _S (SQL_C_TIME);
1058      _S (SQL_C_TIMESTAMP);
1059      _S (SQL_C_TINYINT);
1060#if ODBCVER >= 0x0300
1061      _S (SQL_C_TYPE_DATE);
1062      _S (SQL_C_TYPE_TIME);
1063      _S (SQL_C_TYPE_TIMESTAMP);
1064      _S (SQL_C_UBIGINT);
1065#endif
1066      _S (SQL_C_ULONG);
1067      _S (SQL_C_USHORT);
1068      _S (SQL_C_UTINYINT);
1069      /* _S (SQL_C_VARBOOKMARK); */
1070      _S (SQL_C_WCHAR);
1071
1072#if ODBCVER >= 0x0300
1073      _S (SQL_ARD_TYPE);
1074#endif
1075    }
1076
1077  trace_emit ("\t\t%-15.15s   %d (%s)\n", "SQLSMALLINT ", type, ptr);
1078}
1079
1080
1081void
1082_trace_inouttype (SQLSMALLINT type)
1083{
1084  char *ptr = "unknown Input/Output type";
1085
1086  switch (type)
1087    {
1088    	_S (SQL_PARAM_INPUT);
1089	_S (SQL_PARAM_OUTPUT);
1090	_S (SQL_PARAM_INPUT_OUTPUT);
1091    }
1092
1093  trace_emit ("\t\t%-15.15s   %d (%s)\n", "SQLSMALLINT ", type, ptr);
1094}
1095
1096
1097void
1098_trace_sql_type (SQLSMALLINT type)
1099{
1100  char *ptr = "unknown SQL type";
1101
1102  switch (type)
1103    {
1104      _S (SQL_UNKNOWN_TYPE);
1105      _S (SQL_BIGINT);
1106      _S (SQL_BINARY);
1107      _S (SQL_BIT);
1108      _S (SQL_CHAR);
1109#if (ODBCVER < 0x0300)
1110      _S (SQL_DATE);
1111#else
1112      _S (SQL_DATETIME);
1113#endif
1114      _S (SQL_DECIMAL);
1115      _S (SQL_DOUBLE);
1116      _S (SQL_FLOAT);
1117#if (ODBCVER >= 0x0350)
1118      _S (SQL_GUID);
1119#endif
1120      _S (SQL_INTEGER);
1121      _S (SQL_LONGVARBINARY);
1122      _S (SQL_LONGVARCHAR);
1123      _S (SQL_NUMERIC);
1124      _S (SQL_REAL);
1125      _S (SQL_SMALLINT);
1126#if (ODBCVER < 0x0300)
1127      _S (SQL_TIME);
1128#else
1129      _S (SQL_INTERVAL);
1130#endif
1131      _S (SQL_TIMESTAMP);
1132      _S (SQL_TINYINT);
1133#if ODBCVER >= 0x0300
1134      _S (SQL_TYPE_DATE);
1135      _S (SQL_TYPE_TIME);
1136      _S (SQL_TYPE_TIMESTAMP);
1137#endif
1138      _S (SQL_VARBINARY);
1139      _S (SQL_VARCHAR);
1140      _S (SQL_WCHAR);
1141      _S (SQL_WLONGVARCHAR);
1142      _S (SQL_WVARCHAR);
1143    }
1144
1145  trace_emit ("\t\t%-15.15s   %d (%s)\n", "SQLSMALLINT", (int) type, ptr);
1146}
1147
1148
1149void
1150_trace_sql_type_p (SQLSMALLINT *p, int output)
1151{
1152  char *ptr = "unknown SQL type";
1153
1154  if (!p)
1155    {
1156      trace_emit ("\t\t%-15.15s * 0x0\n", "SQLSMALLINT");
1157      return;
1158    }
1159
1160  if (!output)
1161    {
1162      trace_emit ("\t\t%-15.15s * %p\n", "SQLSMALLINT", p);
1163      return;
1164    }
1165
1166  switch (*p)
1167    {
1168      _S (SQL_UNKNOWN_TYPE);
1169      _S (SQL_BIGINT);
1170      _S (SQL_BINARY);
1171      _S (SQL_BIT);
1172      _S (SQL_CHAR);
1173#if (ODBCVER < 0x0300)
1174      _S (SQL_DATE);
1175#else
1176      _S (SQL_DATETIME);
1177#endif
1178      _S (SQL_DECIMAL);
1179      _S (SQL_DOUBLE);
1180      _S (SQL_FLOAT);
1181
1182#if (ODBCVER >= 0x0350)
1183      _S (SQL_GUID);
1184#endif
1185      _S (SQL_INTEGER);
1186      _S (SQL_LONGVARBINARY);
1187      _S (SQL_LONGVARCHAR);
1188      _S (SQL_NUMERIC);
1189      _S (SQL_REAL);
1190      _S (SQL_SMALLINT);
1191#if (ODBCVER < 0x0300)
1192      _S (SQL_TIME);
1193#else
1194      _S (SQL_INTERVAL);
1195#endif
1196      _S (SQL_TIMESTAMP);
1197      _S (SQL_TINYINT);
1198#if ODBCVER >= 0x0300
1199      _S (SQL_TYPE_DATE);
1200      _S (SQL_TYPE_TIME);
1201      _S (SQL_TYPE_TIMESTAMP);
1202#endif
1203      _S (SQL_VARBINARY);
1204      _S (SQL_VARCHAR);
1205      _S (SQL_WCHAR);
1206      _S (SQL_WLONGVARCHAR);
1207      _S (SQL_WVARCHAR);
1208    }
1209
1210  trace_emit ("\t\t%-15.15s * %p (%s)\n", "SQLSMALLINT", p, ptr);
1211}
1212
1213
1214#if ODBCVER >= 0x0300
1215void
1216_trace_sql_subtype (SQLSMALLINT *type, SQLSMALLINT *sub, int output)
1217{
1218  char *ptr = NULL;
1219
1220  if (!type || !sub)
1221    {
1222      trace_emit ("\t\t%-15.15s * 0x0\n", "SQLSMALLINT");
1223      return;
1224    }
1225
1226  if (!output)
1227    {
1228      trace_emit ("\t\t%-15.15s * %p\n", "SQLSMALLINT", sub);
1229      return;
1230    }
1231
1232  if (*type == SQL_DATETIME)
1233    {
1234      switch (*sub)
1235	{
1236	  _S (SQL_CODE_DATE);
1237	  _S (SQL_CODE_TIME);
1238	  _S (SQL_CODE_TIMESTAMP);
1239	}
1240    }
1241  else if (*type == SQL_INTERVAL)
1242    {
1243      switch (*sub)
1244	{
1245	  _S (SQL_CODE_YEAR);
1246	  _S (SQL_CODE_MONTH);
1247	  _S (SQL_CODE_DAY);
1248	  _S (SQL_CODE_HOUR);
1249	  _S (SQL_CODE_MINUTE);
1250	  _S (SQL_CODE_SECOND);
1251	  _S (SQL_CODE_YEAR_TO_MONTH);
1252	  _S (SQL_CODE_DAY_TO_HOUR);
1253	  _S (SQL_CODE_DAY_TO_MINUTE);
1254	  _S (SQL_CODE_DAY_TO_SECOND);
1255	  _S (SQL_CODE_HOUR_TO_MINUTE);
1256	  _S (SQL_CODE_HOUR_TO_SECOND);
1257	  _S (SQL_CODE_MINUTE_TO_SECOND);
1258	}
1259    }
1260
1261  if (ptr)
1262    trace_emit ("\t\t%-15.15s * %p (%s)\n", "SQLSMALLINT", sub, ptr);
1263  else
1264    trace_emit ("\t\t%-15.15s * %p (%d)\n", "SQLSMALLINT", sub, *sub);
1265}
1266#endif
1267
1268
1269void
1270_trace_bufferlen (SQLINTEGER length)
1271{
1272  char buf[255];
1273  char *ptr = NULL;
1274
1275  switch (length)
1276   {
1277	_S (SQL_NTS);
1278#if ODBCVER >= 0x0300
1279	_S (SQL_IS_POINTER);
1280	_S (SQL_IS_UINTEGER);
1281	_S (SQL_IS_INTEGER);
1282	_S (SQL_IS_USMALLINT);
1283	_S (SQL_IS_SMALLINT);
1284#endif
1285   }
1286
1287  /*
1288   *  Translate binary buffer length
1289   */
1290  if (length <= SQL_LEN_BINARY_ATTR_OFFSET)
1291    {
1292        sprintf (buf, "SQL_LEN_BINARY_ATTR(%ld)", (long) SQL_LEN_BINARY_ATTR(length));
1293	ptr = buf;
1294    }
1295
1296  if (ptr)
1297    trace_emit ("\t\t%-15.15s * %ld (%s)\n", "SQLINTEGER", length, ptr);
1298  else
1299    trace_emit ("\t\t%-15.15s * %ld\n", "SQLINTEGER", (long) length);
1300}
1301