1/*
2 *  herr.c
3 *
4 *  $Id: herr.c,v 1.30 2007/10/07 14:09:10 source Exp $
5 *
6 *  Error stack management functions
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
12 *  All Rights Reserved.
13 *
14 *  This software is released under the terms of either of the following
15 *  licenses:
16 *
17 *      - GNU Library General Public License (see LICENSE.LGPL)
18 *      - The BSD License (see LICENSE.BSD).
19 *
20 *  Note that the only valid version of the LGPL license as far as this
21 *  project is concerned is the original GNU Library General Public License
22 *  Version 2, dated June 1991.
23 *
24 *  While not mandated by the BSD license, any patches you make to the
25 *  iODBC source code may be contributed back into the iODBC project
26 *  at your discretion. Contributions will benefit the Open Source and
27 *  Data Access community as a whole. Submissions may be made at:
28 *
29 *      http://www.iodbc.org
30 *
31 *
32 *  GNU Library Generic Public License Version 2
33 *  ============================================
34 *  This library is free software; you can redistribute it and/or
35 *  modify it under the terms of the GNU Library General Public
36 *  License as published by the Free Software Foundation; only
37 *  Version 2 of the License dated June 1991.
38 *
39 *  This library is distributed in the hope that it will be useful,
40 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
41 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42 *  Library General Public License for more details.
43 *
44 *  You should have received a copy of the GNU Library General Public
45 *  License along with this library; if not, write to the Free
46 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
47 *
48 *
49 *  The BSD License
50 *  ===============
51 *  Redistribution and use in source and binary forms, with or without
52 *  modification, are permitted provided that the following conditions
53 *  are met:
54 *
55 *  1. Redistributions of source code must retain the above copyright
56 *     notice, this list of conditions and the following disclaimer.
57 *  2. Redistributions in binary form must reproduce the above copyright
58 *     notice, this list of conditions and the following disclaimer in
59 *     the documentation and/or other materials provided with the
60 *     distribution.
61 *  3. Neither the name of OpenLink Software Inc. nor the names of its
62 *     contributors may be used to endorse or promote products derived
63 *     from this software without specific prior written permission.
64 *
65 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
68 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
69 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
70 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
71 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
72 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
73 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
74 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
75 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76 */
77
78
79#include <iodbc.h>
80
81#include <sql.h>
82#include <sqlext.h>
83#include <sqlucode.h>
84
85#include <unicode.h>
86
87#include <dlproc.h>
88
89#include <herr.h>
90#if (ODBCVER >= 0x0300)
91#include <hdesc.h>
92#endif
93#include <henv.h>
94#include <hdbc.h>
95#include <hstmt.h>
96
97#include <itrace.h>
98
99#include "herr.ci"
100#include "misc.h"
101
102static HERR
103_iodbcdm_popsqlerr (HERR herr)
104{
105  sqlerr_t *list = (sqlerr_t *) herr;
106  sqlerr_t *next;
107
108  if (herr == SQL_NULL_HERR)
109    {
110      return herr;
111    }
112
113  next = list->next;
114  list->next = NULL;
115
116  MEM_FREE (list);
117
118  return next;
119}
120
121
122void
123_iodbcdm_freesqlerrlist (HERR herrlist)
124{
125  HERR list = herrlist;
126
127  while (list != SQL_NULL_HERR)
128    {
129      list = _iodbcdm_popsqlerr (list);
130    }
131}
132
133
134HERR
135_iodbcdm_pushsqlerr (
136    HERR herr,
137    sqlstcode_t code,
138    void *msg)
139{
140  sqlerr_t *ebuf;
141  sqlerr_t *perr = (sqlerr_t *) herr;
142  int idx = 0;
143
144  if (herr != SQL_NULL_HERR)
145    {
146      idx = perr->idx + 1;
147    }
148
149  if (idx == 64)
150    /* overwrite the top entry to prevent error stack blow out */
151    {
152      perr->code = code;
153      perr->msg = (char *) msg;
154
155      return herr;
156    }
157
158  ebuf = (sqlerr_t *) MEM_ALLOC (sizeof (sqlerr_t));
159
160  if (ebuf == NULL)
161    {
162      return NULL;
163    }
164
165  ebuf->msg = (char *) msg;
166  ebuf->code = code;
167  ebuf->idx = idx;
168  ebuf->next = (sqlerr_t *) herr;
169  return (HERR) ebuf;
170}
171
172
173static char *
174_iodbcdm_getsqlstate (
175    HERR herr,
176    void * tab)
177{
178  sqlerr_t *perr = (sqlerr_t *) herr;
179  sqlerrmsg_t *ptr;
180  sqlstcode_t perr_code;
181
182  if (herr == SQL_NULL_HERR || tab == NULL)
183    {
184      return (char *) NULL;
185    }
186
187  perr_code = perr->code;
188#if (ODBCVER >= 0x0300)
189  switch (perr_code)
190    {
191    case en_S1009:
192      perr_code = en_HY009;
193      break;
194
195    default:
196      break;
197    }
198#endif
199  for (ptr = (sqlerrmsg_t *) tab; ptr->code != en_sqlstat_total; ptr++)
200    {
201      if (ptr->code == perr_code)
202	{
203	  return (char *) (ptr->stat);
204	}
205    }
206
207  return (char *) NULL;
208}
209
210
211static char *
212_iodbcdm_getsqlerrmsg (
213    HERR herr,
214    void * errtab)
215{
216  sqlerr_t *perr = (sqlerr_t *) herr;
217  sqlerrmsg_t *ptr;
218
219  if (herr == SQL_NULL_HERR)
220    {
221      return NULL;
222    }
223
224  if (perr->msg == NULL && errtab == NULL)
225    {
226      return NULL;
227    }
228
229  if (perr->msg != NULL)
230    {
231      return perr->msg;
232    }
233
234  for (ptr = (sqlerrmsg_t *) errtab;
235      ptr->code != en_sqlstat_total;
236      ptr++)
237    {
238      if (ptr->code == perr->code)
239	{
240	  return (char *) ptr->msg;
241	}
242    }
243
244  return (char *) NULL;
245}
246
247
248SQLRETURN SQL_API
249_iodbcdm_sqlerror (
250  SQLHENV		  henv,
251  SQLHDBC		  hdbc,
252  SQLHSTMT		  hstmt,
253  SQLPOINTER		  szSqlstate,
254  SQLINTEGER		* pfNativeError,
255  SQLPOINTER		  szErrorMsg,
256  SQLSMALLINT		  cbErrorMsgMax,
257  SQLSMALLINT 		* pcbErrorMsg,
258  int		  	  bDelete,
259  SQLCHAR		  waMode)
260{
261  GENV (genv, henv);
262  CONN (pdbc, hdbc);
263  STMT (pstmt, hstmt);
264  HDBC thdbc = SQL_NULL_HDBC;
265
266  HENV dhenv = SQL_NULL_HENV;
267  HDBC dhdbc = SQL_NULL_HDBC;
268  HSTMT dhstmt = SQL_NULL_HSTMT;
269
270  HERR herr = SQL_NULL_HERR;
271  HPROC hproc2 = SQL_NULL_HPROC;
272  HPROC hproc3 = SQL_NULL_HPROC;
273#if (ODBCVER >= 0x0300)
274  SQLINTEGER handleType = 0;
275  SQLHANDLE handle3;
276  SQLHANDLE dhandle3 = 0;
277  SQLSMALLINT *perr_rec = NULL;
278#endif
279  SWORD unicode_driver = 0;
280  SQLUINTEGER dodbc_ver = SQL_OV_ODBC2;
281  SQLUINTEGER odbc_ver = SQL_OV_ODBC2;
282  wchar_t _sqlState[6] = {L"\0"};
283  void *SqlstateOut = szSqlstate;
284  void *_ErrorMsg = NULL;
285  void *errorMsgOut = szErrorMsg;
286
287  void *errmsg = NULL;
288  void *ststr = NULL;
289
290  int handle = 0;
291  SQLRETURN retcode = SQL_SUCCESS;
292
293  if (IS_VALID_HSTMT (hstmt))	/* retrieve stmt err */
294    {
295      herr = pstmt->herr;
296      thdbc = pstmt->hdbc;
297
298      if (thdbc == SQL_NULL_HDBC)
299	{
300	  return SQL_INVALID_HANDLE;
301	}
302
303#if (ODBCVER >= 0x0300)
304      handleType = SQL_HANDLE_STMT;
305      handle3 = hstmt;
306      dhandle3 = pstmt->dhstmt;
307      perr_rec = &((STMT_t *)pstmt)->err_rec;
308#endif
309      dhstmt = pstmt->dhstmt;
310      handle = 3;
311    }
312  else if (IS_VALID_HDBC (hdbc))	/* retrieve dbc err */
313    {
314      herr = pdbc->herr;
315      thdbc = pdbc;
316      if (thdbc == SQL_NULL_HDBC)
317	{
318	  return SQL_INVALID_HANDLE;
319	}
320
321#if (ODBCVER >= 0x0300)
322      handleType = SQL_HANDLE_DBC;
323      handle3 = hdbc;
324      dhandle3 = pdbc->dhdbc;
325      perr_rec = &((DBC_t *)pdbc)->err_rec;
326#endif
327      dhdbc = pdbc->dhdbc;
328      handle = 2;
329
330      if (herr == SQL_NULL_HERR
331	  && pdbc->henv == SQL_NULL_HENV)
332	{
333	  return SQL_NO_DATA_FOUND;
334	}
335    }
336  else if (IS_VALID_HENV (henv))	/* retrieve env err */
337    {
338      herr = genv->herr;
339
340      /* Drivers shouldn't push error message
341       * on environment handle */
342
343      if (herr == SQL_NULL_HERR)
344	{
345	  return SQL_NO_DATA_FOUND;
346	}
347
348      handle = 1;
349    }
350  else
351    {
352      return SQL_INVALID_HANDLE;
353    }
354
355  if (szErrorMsg != NULL)
356    {
357      if (cbErrorMsgMax < 0)
358	{
359	  return SQL_ERROR;
360	  /* SQLError() doesn't post error for itself */
361	}
362    }
363
364  if (herr == SQL_NULL_HERR)	/* no err on drv mng */
365    {
366      if (((DBC_t *)hdbc)->genv)
367        odbc_ver = ((GENV_t *) ((DBC_t *)hdbc)->genv)->odbc_ver;
368
369      if (((DBC_t *)hdbc)->henv)
370        {
371          unicode_driver = ((ENV_t *) ((DBC_t *)hdbc)->henv)->unicode_driver;
372          dodbc_ver = ((ENV_t *) ((DBC_t *)hdbc)->henv)->dodbc_ver;
373        }
374
375      /* call driver */
376      if ((unicode_driver && waMode != 'W')
377          || (!unicode_driver && waMode == 'W'))
378        {
379          if (waMode != 'W')
380            {
381            /* ansi=>unicode*/
382              if ((_ErrorMsg = malloc(cbErrorMsgMax * sizeof(wchar_t) + 1)) == NULL)
383                return SQL_ERROR;
384            }
385          else
386            {
387            /* unicode=>ansi*/
388              if ((_ErrorMsg = malloc(cbErrorMsgMax + 1)) == NULL)
389                return SQL_ERROR;
390            }
391          errorMsgOut = _ErrorMsg;
392          SqlstateOut = _sqlState;
393        }
394
395      /* call driver */
396      if (unicode_driver)
397        {
398          /* SQL_XXX_W */
399          hproc2 = _iodbcdm_getproc (thdbc, en_ErrorW);
400#if (ODBCVER >= 0x300)
401          hproc3 = _iodbcdm_getproc (thdbc, en_GetDiagRecW);
402#endif
403        }
404      else
405        {
406          /* SQL_XXX */
407          /* SQL_XXX_A */
408          hproc2 = _iodbcdm_getproc (thdbc, en_Error);
409          if (hproc2 == SQL_NULL_HPROC)
410            hproc2 = _iodbcdm_getproc (thdbc, en_ErrorA);
411#if (ODBCVER >= 0x300)
412          hproc3 = _iodbcdm_getproc (thdbc, en_GetDiagRec);
413          if (hproc3 == SQL_NULL_HPROC)
414            hproc3 = _iodbcdm_getproc (thdbc, en_GetDiagRecA);
415#endif
416        }
417
418      if (odbc_ver == SQL_OV_ODBC2 &&
419          (  dodbc_ver == SQL_OV_ODBC2
420           || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
421        hproc3 = SQL_NULL_HPROC;
422
423#if (ODBCVER >= 0x300)
424      if (hproc3 != SQL_NULL_HPROC)
425        {
426          (*perr_rec) = (*perr_rec) + 1;
427          CALL_DRIVER (thdbc, NULL, retcode, hproc3, (
428                  handleType,
429                  dhandle3,
430                  (*perr_rec),
431                  SqlstateOut,
432                  pfNativeError,
433                  errorMsgOut,
434                  cbErrorMsgMax,
435                  pcbErrorMsg));
436        }
437      else
438#endif
439        {
440          if (hproc2 == SQL_NULL_HPROC)
441            {
442              MEM_FREE(_ErrorMsg);
443              return SQL_NO_DATA_FOUND;
444            }
445           CALL_DRIVER (thdbc, NULL, retcode, hproc2, (
446                   dhenv,
447                   dhdbc,
448                   dhstmt,
449                   SqlstateOut,
450                   pfNativeError,
451                   errorMsgOut,
452                   cbErrorMsgMax,
453                   pcbErrorMsg));
454        }
455
456      if (szErrorMsg
457          && SQL_SUCCEEDED (retcode)
458          && ((unicode_driver && waMode != 'W')
459              || (!unicode_driver && waMode == 'W')))
460        {
461          if (waMode != 'W')
462            {
463            /* ansi<=unicode*/
464              dm_StrCopyOut2_W2A ((SQLWCHAR *)errorMsgOut, (SQLCHAR *)szErrorMsg, cbErrorMsgMax, NULL);
465              dm_StrCopyOut2_W2A ((SQLWCHAR *)SqlstateOut, (SQLCHAR *)szSqlstate, 6, NULL);
466            }
467          else
468            {
469            /* unicode<=ansi*/
470              dm_StrCopyOut2_A2W ((SQLCHAR *)errorMsgOut, (SQLWCHAR *)szErrorMsg, cbErrorMsgMax, NULL);
471              dm_StrCopyOut2_A2W ((SQLCHAR *)SqlstateOut, (SQLWCHAR *)szSqlstate, 6, NULL);
472            }
473        }
474
475      MEM_FREE(_ErrorMsg);
476
477      return retcode;
478    }
479
480  if (szSqlstate != NULL)
481    {
482      int len;
483
484      /* get sql state  string */
485      ststr = (char *) _iodbcdm_getsqlstate (herr,
486	  (void *) sqlerrmsg_tab);
487
488      if (ststr == NULL)
489	{
490	  len = 0;
491	}
492      else
493	{
494	  len = (int) STRLEN (ststr);
495	}
496
497      /* buffer size of szSqlstate is not checked. Applications
498       * suppose provide enough ( not less than 6 bytes ) buffer
499       * or NULL for it.
500       */
501      if (waMode != 'W')
502        {
503          STRNCPY (szSqlstate, ststr, len);
504          ((char*)szSqlstate)[len] = 0;
505        }
506      else
507        {
508          dm_StrCopyOut2_A2W ((SQLCHAR *)ststr, (SQLWCHAR *)szSqlstate, 6, NULL);
509          ((wchar_t*)szSqlstate)[len] = 0;
510        }
511    }
512
513  if (pfNativeError != NULL)
514    {
515      /* native error code is specific to data source */
516      *pfNativeError = (SDWORD) 0L;
517    }
518
519  if (szErrorMsg == NULL || cbErrorMsgMax == 0)
520    {
521      if (pcbErrorMsg != NULL)
522	{
523	  *pcbErrorMsg = (SWORD) 0;
524	}
525    }
526  else
527    {
528      int len;
529      char msgbuf[256] = {'\0'};
530
531      /* get sql state message */
532      errmsg = _iodbcdm_getsqlerrmsg (herr, (void *) sqlerrmsg_tab);
533
534      if (errmsg == NULL)
535	{
536	  errmsg = (char *) "";
537	}
538
539#if defined(HAVE_SNPRINTF)
540      snprintf (msgbuf, sizeof(msgbuf), "%s%s", sqlerrhd, (char*)errmsg);
541#else
542      sprintf (msgbuf, "%s%s", sqlerrhd, (char*)errmsg);
543#endif
544
545      len = STRLEN (msgbuf);
546
547      if (len < cbErrorMsgMax - 1)
548	{
549	  retcode = SQL_SUCCESS;
550	}
551      else
552	{
553	  len = cbErrorMsgMax - 1;
554	  retcode = SQL_SUCCESS_WITH_INFO;
555	  /* and not posts error for itself */
556	}
557
558      if (waMode != 'W')
559        {
560          STRNCPY ((char *) szErrorMsg, msgbuf, len);
561          ((char*)szErrorMsg)[len] = 0;
562          if (pcbErrorMsg != NULL)
563	    *pcbErrorMsg = (SWORD) len;
564        }
565      else
566        {
567          dm_StrCopyOut2_A2W ((SQLCHAR *) msgbuf,
568	  	(SQLWCHAR *) szErrorMsg, cbErrorMsgMax, pcbErrorMsg);
569        }
570    }
571
572  if (bDelete)
573    switch (handle)		/* free this err */
574      {
575	case 1:
576	    genv->herr = _iodbcdm_popsqlerr (genv->herr);
577	    break;
578
579	case 2:
580	    pdbc->herr = _iodbcdm_popsqlerr (pdbc->herr);
581	    break;
582
583	case 3:
584	    pstmt->herr = _iodbcdm_popsqlerr (pstmt->herr);
585	    break;
586
587	default:
588	    break;
589      }
590
591  return retcode;
592}
593
594
595SQLRETURN SQL_API
596SQLError (
597  SQLHENV		  henv,
598  SQLHDBC		  hdbc,
599  SQLHSTMT		  hstmt,
600  SQLCHAR 		* szSqlstate,
601  SQLINTEGER 		* pfNativeError,
602  SQLCHAR 		* szErrorMsg,
603  SQLSMALLINT		  cbErrorMsgMax,
604  SQLSMALLINT 		* pcbErrorMsg)
605{
606  SQLRETURN retcode = SQL_SUCCESS;
607
608  ODBC_LOCK ();
609  TRACE (trace_SQLError (TRACE_ENTER,
610  	henv,
611	hdbc,
612	hstmt,
613	szSqlstate,
614	pfNativeError,
615        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
616
617  retcode = _iodbcdm_sqlerror (
618  	henv,
619	hdbc,
620	hstmt,
621	szSqlstate,
622	pfNativeError,
623        szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
624	1,
625	'A');
626
627  TRACE (trace_SQLError (TRACE_LEAVE,
628  	henv,
629	hdbc,
630	hstmt,
631	szSqlstate,
632	pfNativeError,
633        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
634
635  ODBC_UNLOCK ();
636  return retcode;
637}
638
639
640#if ODBCVER >= 0x0300
641SQLRETURN SQL_API
642SQLErrorA (
643  SQLHENV		  henv,
644  SQLHDBC 		  hdbc,
645  SQLHSTMT 		  hstmt,
646  SQLCHAR 		* szSqlstate,
647  SQLINTEGER 		* pfNativeError,
648  SQLCHAR 		* szErrorMsg,
649  SQLSMALLINT		  cbErrorMsgMax,
650  SQLSMALLINT 		* pcbErrorMsg)
651{
652  SQLRETURN retcode = SQL_SUCCESS;
653
654  ODBC_LOCK ();
655  TRACE (trace_SQLError (TRACE_ENTER,
656  	henv,
657	hdbc,
658	hstmt,
659	szSqlstate,
660	pfNativeError,
661        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
662
663  retcode = _iodbcdm_sqlerror (
664  	henv,
665	hdbc,
666	hstmt,
667	szSqlstate,
668	pfNativeError,
669        szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
670	1,
671	'A');
672
673  TRACE (trace_SQLError (TRACE_LEAVE,
674  	henv,
675	hdbc,
676	hstmt,
677	szSqlstate,
678	pfNativeError,
679        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
680
681  ODBC_UNLOCK ();
682  return retcode;
683}
684
685
686SQLRETURN SQL_API
687SQLErrorW (
688  SQLHENV		  henv,
689  SQLHDBC		  hdbc,
690  SQLHSTMT		  hstmt,
691  SQLWCHAR 		* szSqlstate,
692  SQLINTEGER 		* pfNativeError,
693  SQLWCHAR 		* szErrorMsg,
694  SQLSMALLINT		  cbErrorMsgMax,
695  SQLSMALLINT 		* pcbErrorMsg)
696{
697  SQLRETURN retcode = SQL_SUCCESS;
698
699  ODBC_LOCK ();
700  TRACE (trace_SQLErrorW (TRACE_ENTER,
701  	henv,
702	hdbc,
703	hstmt,
704	szSqlstate,
705	pfNativeError,
706        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
707
708  retcode = _iodbcdm_sqlerror (
709  	henv,
710	hdbc,
711	hstmt,
712	szSqlstate,
713	pfNativeError,
714	szErrorMsg, cbErrorMsgMax, pcbErrorMsg,
715	1,
716	'W');
717
718  TRACE (trace_SQLErrorW (TRACE_LEAVE,
719  	henv,
720	hdbc,
721	hstmt,
722	szSqlstate,
723	pfNativeError,
724        szErrorMsg, cbErrorMsgMax, pcbErrorMsg));
725
726  ODBC_UNLOCK ();
727  return retcode;
728}
729#endif
730
731
732#if (ODBCVER >= 0x0300)
733static int
734error_rec_count (HERR herr)
735{
736  sqlerr_t *err = (sqlerr_t *)herr;
737  if (err)
738    return err->idx + 1;
739  else
740    return 0;
741}
742
743
744static sqlerr_t *
745get_nth_error(HERR herr, int nIndex)
746{
747  sqlerr_t *err = (sqlerr_t *) herr;
748  while (err && err->idx != nIndex)
749      err = err->next;
750  return err;
751}
752
753
754RETCODE SQL_API
755SQLGetDiagRec_Internal (
756  SQLSMALLINT		  HandleType,
757  SQLHANDLE		  Handle,
758  SQLSMALLINT		  RecNumber,
759  SQLPOINTER		  Sqlstate,
760  SQLINTEGER		* NativeErrorPtr,
761  SQLPOINTER		  MessageText,
762  SQLSMALLINT		  BufferLength,
763  SQLSMALLINT		* TextLengthPtr,
764  SQLCHAR		  waMode)
765{
766  sqlerr_t *curr_err = NULL;
767  HERR err = NULL;
768  int nRecs;
769  HPROC hproc2 = SQL_NULL_HPROC;
770  HPROC hproc3 = SQL_NULL_HPROC;
771  HDBC hdbc = SQL_NULL_HDBC;
772  RETCODE retcode = SQL_SUCCESS;
773  SQLHANDLE dhandle = SQL_NULL_HANDLE;
774  SWORD unicode_driver = 0;
775  SQLUINTEGER dodbc_ver = SQL_OV_ODBC3;
776  SQLUINTEGER odbc_ver = SQL_OV_ODBC3;
777  wchar_t _sqlState[6] = {L"\0"};
778  void *_MessageText = NULL;
779  void *messageTextOut = MessageText;
780  void *SqlstateOut = Sqlstate;
781
782
783  if (RecNumber < 1)
784    return SQL_ERROR;
785
786  if (BufferLength < 0)
787    return SQL_ERROR;
788
789  switch (HandleType)
790    {
791    case SQL_HANDLE_ENV:
792      if (!IS_VALID_HENV (Handle))
793	{
794	  return SQL_INVALID_HANDLE;
795	}
796      err = ((GENV_t *) Handle)->herr;
797      break;
798
799    case SQL_HANDLE_DBC:
800      if (!IS_VALID_HDBC (Handle))
801	{
802	  return SQL_INVALID_HANDLE;
803	}
804      err = ((DBC_t *) Handle)->herr;
805      dhandle = ((DBC_t *) Handle)->dhdbc;
806      hdbc = Handle;
807      break;
808
809    case SQL_HANDLE_STMT:
810      if (!IS_VALID_HSTMT (Handle))
811	{
812	  return SQL_INVALID_HANDLE;
813	}
814      err = ((STMT_t *) Handle)->herr;
815      dhandle = ((STMT_t *) Handle)->dhstmt;
816      hdbc = ((STMT_t *) Handle)->hdbc;
817      break;
818
819    case SQL_HANDLE_DESC:
820      if (!IS_VALID_HDESC (Handle))
821	{
822	  return SQL_INVALID_HANDLE;
823	}
824      err = ((DESC_t *) Handle)->herr;
825      dhandle = ((DESC_t *) Handle)->dhdesc;
826      hdbc = ((DESC_t *) Handle)->hdbc;
827      break;
828
829    default:
830      return SQL_INVALID_HANDLE;
831    }
832
833  nRecs = error_rec_count (err);
834
835  if (nRecs >= RecNumber)
836    {				/* DM error range */
837      curr_err = get_nth_error (err, RecNumber - 1);
838
839      if (!curr_err)
840	{
841	  return (SQL_NO_DATA_FOUND);
842	}
843
844      retcode = SQL_SUCCESS;
845
846      if (Sqlstate != NULL)
847	{
848	  int len;
849	  char *ststr = (char *) _iodbcdm_getsqlstate (curr_err,
850	      (void *) sqlerrmsg_tab);
851
852	  if (ststr == NULL)
853	    {
854	      len = 0;
855	    }
856	  else
857	    {
858	      len = (int) STRLEN (ststr);
859	    }
860
861          /* buffer size of szSqlstate is not checked. Applications
862           * suppose provide enough ( not less than 6 bytes ) buffer
863           * or NULL for it.
864           */
865          if (waMode != 'W')
866            {
867              STRNCPY (Sqlstate, ststr, len);
868              ((char*)Sqlstate)[len] = 0;
869            }
870          else
871            {
872              dm_StrCopyOut2_A2W ((SQLCHAR *) ststr,
873			(SQLWCHAR *) Sqlstate, 6, NULL);
874              ((wchar_t*)Sqlstate)[len] = 0;
875            }
876	}
877
878      if (MessageText == NULL || BufferLength == 0)
879	{
880	  if (TextLengthPtr != NULL)
881	    {
882	      *TextLengthPtr = (SWORD) 0;
883	    }
884	}
885      else
886	{
887	  int len;
888	  char msgbuf[256] = { '\0' };
889	  char *errmsg;
890
891	  /* get sql state message */
892	  errmsg =
893	      _iodbcdm_getsqlerrmsg (curr_err, (void *) sqlerrmsg_tab);
894
895	  if (errmsg == NULL)
896	    {
897	      errmsg = (char *) "";
898	    }
899
900#if defined(HAVE_SNPRINTF)
901	  snprintf (msgbuf, sizeof (msgbuf), "%s%s", sqlerrhd, errmsg);
902#else
903	  sprintf (msgbuf, "%s%s", sqlerrhd, errmsg);
904#endif
905
906	  len = STRLEN (msgbuf);
907
908	  if (len < BufferLength - 1)
909	    {
910	      retcode = SQL_SUCCESS;
911	    }
912	  else
913	    {
914	      len = BufferLength - 1;
915	      retcode = SQL_SUCCESS_WITH_INFO;
916	      /* and not posts error for itself */
917	    }
918
919          if (waMode != 'W')
920            {
921              STRNCPY ((char *) MessageText, msgbuf, len);
922              ((char*)MessageText)[len] = 0;
923              if (TextLengthPtr != NULL)
924  	        *TextLengthPtr = (SWORD) len;
925            }
926          else
927            {
928              dm_StrCopyOut2_A2W ((SQLCHAR *) msgbuf,
929		    (SQLWCHAR *) MessageText, BufferLength, TextLengthPtr);
930            }
931	}
932      return retcode;
933    }
934  else
935    {				/* Driver errors */
936      if (hdbc == SQL_NULL_HDBC)
937	{
938	  return SQL_NO_DATA_FOUND;
939	}
940      RecNumber -= nRecs;
941
942      if (((DBC_t *)hdbc)->henv)
943        {
944          unicode_driver = ((ENV_t *) ((DBC_t *)hdbc)->henv)->unicode_driver;
945          dodbc_ver = ((ENV_t *) ((DBC_t *)hdbc)->henv)->dodbc_ver;
946        }
947
948      if (((DBC_t *)hdbc)->genv)
949        odbc_ver = ((GENV_t *) ((DBC_t *)hdbc)->genv)->odbc_ver;
950
951      if ((unicode_driver && waMode != 'W')
952          || (!unicode_driver && waMode == 'W'))
953        {
954          if (waMode != 'W')
955            {
956            /* ansi=>unicode*/
957              if ((_MessageText = malloc((BufferLength + 1) * sizeof(wchar_t))) == NULL)
958                {
959                  return SQL_ERROR;
960                }
961            }
962          else
963            {
964            /* unicode=>ansi*/
965              if ((_MessageText = malloc(BufferLength + 1)) == NULL)
966                {
967                  return SQL_ERROR;
968                }
969            }
970          messageTextOut = _MessageText;
971          SqlstateOut = _sqlState;
972        }
973
974      /* call driver */
975      if (unicode_driver)
976        {
977          /* SQL_XXX_W */
978          hproc2 = _iodbcdm_getproc (hdbc, en_ErrorW);
979#if (ODBCVER >= 0x300)
980          hproc3 = _iodbcdm_getproc (hdbc, en_GetDiagRecW);
981#endif
982        }
983      else
984        {
985          /* SQL_XXX */
986          /* SQL_XXX_A */
987          hproc2 = _iodbcdm_getproc (hdbc, en_Error);
988          if (hproc2 == SQL_NULL_HPROC)
989            hproc2 = _iodbcdm_getproc (hdbc, en_ErrorA);
990#if (ODBCVER >= 0x300)
991          hproc3 = _iodbcdm_getproc (hdbc, en_GetDiagRec);
992          if (hproc3 == SQL_NULL_HPROC)
993            hproc3 = _iodbcdm_getproc (hdbc, en_GetDiagRecA);
994#endif
995        }
996
997      if (odbc_ver == SQL_OV_ODBC2 &&
998          (  dodbc_ver == SQL_OV_ODBC2
999           || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
1000        hproc3 = SQL_NULL_HPROC;
1001
1002#if (ODBCVER >= 0x300)
1003      if (hproc3 != SQL_NULL_HPROC)
1004        {
1005          CALL_DRIVER (hdbc, Handle, retcode, hproc3, (
1006                  HandleType,
1007                  dhandle,
1008                  RecNumber,
1009                  SqlstateOut,
1010                  NativeErrorPtr,
1011                  messageTextOut,
1012                  BufferLength,
1013                  TextLengthPtr));
1014        }
1015      else
1016#endif
1017        {
1018          if (hproc2 == SQL_NULL_HPROC)
1019            {
1020              MEM_FREE(_MessageText);
1021              return SQL_ERROR;
1022            }
1023
1024   	  if (RecNumber > 1 || HandleType == SQL_HANDLE_DESC)
1025	    {
1026	       MEM_FREE(_MessageText);
1027	       return SQL_NO_DATA_FOUND;
1028	    }
1029          CALL_DRIVER (hdbc, Handle, retcode, hproc2, (
1030                  SQL_NULL_HENV,
1031                  HandleType == SQL_HANDLE_DBC ? dhandle : SQL_NULL_HDBC,
1032                  HandleType == SQL_HANDLE_STMT ? dhandle : SQL_NULL_HSTMT,
1033                  SqlstateOut,
1034                  NativeErrorPtr,
1035                  messageTextOut,
1036                  BufferLength,
1037                  TextLengthPtr));
1038        }
1039
1040      if (MessageText
1041          && SQL_SUCCEEDED (retcode)
1042          && ((unicode_driver && waMode != 'W')
1043              || (!unicode_driver && waMode == 'W')))
1044        {
1045          if (waMode != 'W')
1046            {
1047            /* ansi<=unicode*/
1048              dm_StrCopyOut2_W2A ((SQLWCHAR *)messageTextOut, (SQLCHAR *)MessageText, BufferLength, NULL);
1049              dm_StrCopyOut2_W2A ((SQLWCHAR *)SqlstateOut, (SQLCHAR *)Sqlstate, 6, NULL);
1050            }
1051          else
1052            {
1053            /* unicode<=ansi*/
1054              dm_StrCopyOut2_A2W ((SQLCHAR *) messageTextOut, (SQLWCHAR *) MessageText, BufferLength, NULL);
1055              dm_StrCopyOut2_A2W ((SQLCHAR *) SqlstateOut, (SQLWCHAR *) Sqlstate, 6, NULL);
1056            }
1057        }
1058
1059      MEM_FREE(_MessageText);
1060
1061      return retcode;
1062    }
1063}
1064
1065
1066RETCODE SQL_API
1067SQLGetDiagRec (
1068  SQLSMALLINT		  HandleType,
1069  SQLHANDLE		  Handle,
1070  SQLSMALLINT		  RecNumber,
1071  SQLCHAR		* Sqlstate,
1072  SQLINTEGER		* NativeErrorPtr,
1073  SQLCHAR		* MessageText,
1074  SQLSMALLINT		  BufferLength,
1075  SQLSMALLINT		* TextLengthPtr)
1076{
1077  SQLRETURN retcode = SQL_SUCCESS;
1078
1079  ODBC_LOCK ();
1080
1081  TRACE (trace_SQLGetDiagRec (TRACE_ENTER,
1082  	HandleType,
1083	Handle,
1084	RecNumber,
1085	Sqlstate,
1086	NativeErrorPtr,
1087	MessageText, BufferLength, TextLengthPtr));
1088
1089  retcode = SQLGetDiagRec_Internal (
1090  	HandleType,
1091	Handle,
1092	RecNumber,
1093	Sqlstate,
1094	NativeErrorPtr,
1095	MessageText, BufferLength, TextLengthPtr,
1096	'A');
1097
1098  TRACE (trace_SQLGetDiagRec (TRACE_LEAVE,
1099  	HandleType,
1100	Handle,
1101	RecNumber,
1102	Sqlstate,
1103	NativeErrorPtr,
1104	MessageText, BufferLength, TextLengthPtr));
1105
1106  ODBC_UNLOCK ();
1107
1108  return retcode;
1109}
1110
1111
1112RETCODE SQL_API
1113SQLGetDiagRecA (
1114  SQLSMALLINT		  HandleType,
1115  SQLHANDLE		  Handle,
1116  SQLSMALLINT		  RecNumber,
1117  SQLCHAR		* Sqlstate,
1118  SQLINTEGER		* NativeErrorPtr,
1119  SQLCHAR		* MessageText,
1120  SQLSMALLINT		  BufferLength,
1121  SQLSMALLINT		* TextLengthPtr)
1122{
1123  SQLRETURN retcode = SQL_SUCCESS;
1124
1125  ODBC_LOCK ();
1126
1127  TRACE (trace_SQLGetDiagRec (TRACE_ENTER,
1128  	HandleType,
1129	Handle,
1130	RecNumber,
1131	Sqlstate,
1132	NativeErrorPtr,
1133	MessageText, BufferLength, TextLengthPtr));
1134
1135  retcode = SQLGetDiagRec_Internal (
1136  	HandleType,
1137	Handle,
1138	RecNumber,
1139	Sqlstate,
1140	NativeErrorPtr,
1141	MessageText, BufferLength, TextLengthPtr,
1142	'A');
1143
1144  TRACE (trace_SQLGetDiagRec (TRACE_LEAVE,
1145  	HandleType,
1146	Handle,
1147	RecNumber,
1148	Sqlstate,
1149	NativeErrorPtr,
1150	MessageText, BufferLength, TextLengthPtr));
1151
1152  ODBC_UNLOCK ();
1153
1154  return retcode;
1155}
1156
1157
1158RETCODE SQL_API
1159SQLGetDiagRecW (
1160  SQLSMALLINT		  HandleType,
1161  SQLHANDLE		  Handle,
1162  SQLSMALLINT		  RecNumber,
1163  SQLWCHAR		* Sqlstate,
1164  SQLINTEGER		* NativeErrorPtr,
1165  SQLWCHAR		* MessageText,
1166  SQLSMALLINT		  BufferLength,
1167  SQLSMALLINT		* TextLengthPtr)
1168{
1169  SQLRETURN retcode = SQL_SUCCESS;
1170
1171  ODBC_LOCK ();
1172
1173  TRACE (trace_SQLGetDiagRecW (TRACE_ENTER,
1174  	HandleType,
1175	Handle,
1176	RecNumber,
1177	Sqlstate,
1178	NativeErrorPtr,
1179	MessageText, BufferLength, TextLengthPtr));
1180
1181  retcode = SQLGetDiagRec_Internal (
1182  	HandleType,
1183	Handle,
1184	RecNumber,
1185	Sqlstate,
1186	NativeErrorPtr,
1187	MessageText, BufferLength, TextLengthPtr,
1188	'W');
1189
1190  TRACE (trace_SQLGetDiagRecW (TRACE_LEAVE,
1191  	HandleType,
1192	Handle,
1193	RecNumber,
1194	Sqlstate,
1195	NativeErrorPtr,
1196	MessageText, BufferLength, TextLengthPtr));
1197
1198  ODBC_UNLOCK ();
1199
1200  return retcode;
1201}
1202
1203
1204RETCODE SQL_API
1205SQLGetDiagField_Internal (
1206  SQLSMALLINT		  nHandleType,
1207  SQLHANDLE		  Handle,
1208  SQLSMALLINT		  nRecNumber,
1209  SQLSMALLINT		  nDiagIdentifier,
1210  SQLPOINTER		  pDiagInfoPtr,
1211  SQLSMALLINT		  nBufferLength,
1212  SQLSMALLINT		* pnStringLengthPtr,
1213  SQLCHAR		  waMode)
1214{
1215  GENV (genv, Handle);
1216  CONN (con, Handle);
1217  STMT (stmt, Handle);
1218  DESC (desc, Handle);
1219  HERR err;
1220  HPROC hproc = SQL_NULL_HPROC;
1221  RETCODE retcode = SQL_SUCCESS;
1222  SQLHANDLE dhandle = SQL_NULL_HANDLE;
1223  SWORD unicode_driver = 0;
1224  void *_DiagInfoPtr = NULL;
1225  void *diagInfoPtr = pDiagInfoPtr;
1226
1227
1228  switch (nHandleType)
1229    {
1230    case SQL_HANDLE_ENV:
1231      if (!IS_VALID_HENV (Handle))
1232	{
1233	  return SQL_INVALID_HANDLE;
1234	}
1235      err = genv->herr;
1236      con = NULL;
1237      stmt = NULL;
1238      desc = NULL;
1239      break;
1240
1241    case SQL_HANDLE_DBC:
1242      if (!IS_VALID_HDBC (Handle))
1243	{
1244	  return SQL_INVALID_HANDLE;
1245	}
1246      err = con->herr;
1247      genv = (GENV_t *) con->genv;
1248      stmt = NULL;
1249      desc = NULL;
1250      dhandle = con->dhdbc;
1251      break;
1252
1253    case SQL_HANDLE_STMT:
1254      if (!IS_VALID_HSTMT (Handle))
1255	{
1256	  return SQL_INVALID_HANDLE;
1257	}
1258      err = stmt->herr;
1259      con = (DBC_t *) stmt->hdbc;
1260      genv = (GENV_t *) con->genv;
1261      desc = NULL;
1262      dhandle = stmt->dhstmt;
1263      break;
1264
1265    case SQL_HANDLE_DESC:
1266      if (!IS_VALID_HDESC (Handle))
1267	{
1268	  return SQL_INVALID_HANDLE;
1269	}
1270      err = desc->herr;
1271      stmt = (STMT_t *) desc->hstmt;
1272      con = (DBC_t *) desc->hdbc;
1273      genv = (GENV_t *) con->genv;
1274      dhandle = desc->dhdesc;
1275      break;
1276
1277    default:
1278      return SQL_INVALID_HANDLE;
1279    }
1280
1281  if (con != NULL && con->henv != SQL_NULL_HENV)
1282    unicode_driver = ((ENV_t *) con->henv)->unicode_driver;
1283
1284  switch (nRecNumber)
1285    {
1286
1287    case 0:			/* Header record */
1288      switch (nDiagIdentifier)
1289	{
1290	case SQL_DIAG_ROW_COUNT:
1291	  {
1292	    if (nHandleType != SQL_HANDLE_STMT || !stmt)
1293	      {
1294		return SQL_ERROR;
1295	      }
1296
1297	    if (stmt->state != en_stmt_executed_with_info &&
1298	    	stmt->state != en_stmt_executed &&
1299		stmt->state != en_stmt_cursoropen)
1300	      {
1301		return SQL_ERROR;
1302	      }
1303	    if (!con)
1304	      {
1305		return SQL_INVALID_HANDLE;
1306	      }
1307
1308            CALL_UDRIVER(con, stmt, retcode, hproc, unicode_driver, en_GetDiagField,
1309              (SQL_HANDLE_DBC, stmt->dhstmt, nRecNumber, nDiagIdentifier,
1310               pDiagInfoPtr, nBufferLength, pnStringLengthPtr ));
1311            if (hproc == SQL_NULL_HPROC)
1312              {
1313		if (!con)
1314		  {
1315		    return SQL_INVALID_HANDLE;
1316		  }
1317		hproc = _iodbcdm_getproc (con, en_RowCount);
1318		if (!hproc)
1319		  {
1320		    return SQL_ERROR;
1321		  }
1322		CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1323		    (stmt->dhstmt, pDiagInfoPtr));
1324              }
1325	    return retcode;
1326	  }
1327
1328	case SQL_DIAG_CURSOR_ROW_COUNT:
1329	case SQL_DIAG_DYNAMIC_FUNCTION:
1330	case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
1331
1332	  {
1333	    if (nHandleType != SQL_HANDLE_STMT || !stmt)
1334	      {
1335		return SQL_ERROR;
1336	      }
1337
1338	    if (stmt->state != en_stmt_executed_with_info &&
1339	    	stmt->state != en_stmt_executed &&
1340		stmt->state != en_stmt_cursoropen)
1341	      {
1342		return SQL_ERROR;
1343	      }
1344	    if (!con)
1345	      {
1346		return SQL_INVALID_HANDLE;
1347	      }
1348
1349            CALL_UDRIVER(con, stmt, retcode, hproc, unicode_driver, en_GetDiagField,
1350              (SQL_HANDLE_DBC, stmt->dhstmt, nRecNumber, nDiagIdentifier,
1351               pDiagInfoPtr, nBufferLength, pnStringLengthPtr ));
1352            if (hproc == SQL_NULL_HPROC)
1353              return SQL_ERROR;
1354            else
1355	      return retcode;
1356	  }
1357
1358	case SQL_DIAG_RETURNCODE:
1359
1360	  if (pDiagInfoPtr)
1361	    *((SQLRETURN *) pDiagInfoPtr) = ((GENV_t *) Handle)->rc;
1362	  {
1363	    return SQL_SUCCESS;
1364	  }
1365
1366	case SQL_DIAG_NUMBER:
1367
1368	  if (pDiagInfoPtr)
1369	    {
1370	      (*(SQLINTEGER *) pDiagInfoPtr) = 0;
1371	      /* get the number from the driver */
1372	      if (con)
1373		{
1374                  CALL_UDRIVER(con, Handle, retcode, hproc, unicode_driver, en_GetDiagField,
1375                    (nHandleType, dhandle, 0, nDiagIdentifier,
1376                     pDiagInfoPtr, nBufferLength, pnStringLengthPtr ));
1377                  if (hproc != SQL_NULL_HPROC)
1378                    {
1379		      if (retcode != SQL_SUCCESS)
1380			{
1381			  return retcode;
1382			}
1383
1384		      /* and add the DM's value */
1385		      (*(SQLINTEGER *) pDiagInfoPtr) += error_rec_count (err);
1386                    }
1387		  else if (((ENV_t *) con->henv)->dodbc_ver == SQL_OV_ODBC2 &&
1388		      ((GENV_t *) Handle)->rc)
1389		    {		/* ODBC2 drivers can only have one error */
1390		      (*(SQLINTEGER *) pDiagInfoPtr) = 1;
1391		    }
1392		}
1393	      else if (genv)
1394		{
1395		  (*(SQLINTEGER *) pDiagInfoPtr) = error_rec_count (err);
1396		}
1397
1398	    }
1399	  break;
1400
1401	default:
1402	  return SQL_ERROR;
1403	}
1404      break;
1405
1406    default:			/* status records */
1407      {
1408	int nRecs = 0;
1409
1410	if (nRecNumber < 1)
1411	  {
1412	    return SQL_ERROR;
1413	  }
1414	nRecs = error_rec_count (err);
1415	if (nRecNumber <= nRecs)
1416	  {			/* DM Errors */
1417	    char *szval = "";
1418	    int ival = 0;
1419	    int isInt = 0;
1420	    sqlerr_t *rec = NULL;
1421
1422	    rec = get_nth_error (err, nRecNumber - 1);
1423
1424	    if (!rec)
1425	      {
1426		return (SQL_NO_DATA_FOUND);
1427	      }
1428
1429	    switch (nDiagIdentifier)
1430	      {
1431
1432	      case SQL_DIAG_SUBCLASS_ORIGIN:
1433	      case SQL_DIAG_CLASS_ORIGIN:
1434		isInt = 0;
1435
1436		szval = (rec->code >= en_HY001
1437		    && rec->code <= en_IM014) ? (char *) "ODBC 3.0" : (char *) "ISO 9075";
1438		break;
1439
1440	      case SQL_DIAG_COLUMN_NUMBER:
1441
1442		if (nHandleType != SQL_HANDLE_STMT || !stmt)
1443		  {
1444		    return SQL_ERROR;
1445		  }
1446		if (!con)
1447		  {
1448		    return SQL_INVALID_HANDLE;
1449		  }
1450
1451		if (pDiagInfoPtr)
1452		  *((SQLINTEGER *) pDiagInfoPtr) = SQL_COLUMN_NUMBER_UNKNOWN;
1453
1454		return SQL_SUCCESS;
1455
1456	      case SQL_DIAG_CONNECTION_NAME:
1457	      case SQL_DIAG_SERVER_NAME:
1458
1459		isInt = 0;
1460		if (con)
1461		  {
1462		    if (waMode != 'W')
1463		       retcode = SQLGetInfo (con, SQL_DATA_SOURCE_NAME,
1464		          pDiagInfoPtr,	nBufferLength, pnStringLengthPtr);
1465		    else
1466		       retcode = SQLGetInfoW (con, SQL_DATA_SOURCE_NAME,
1467		          pDiagInfoPtr,	nBufferLength, pnStringLengthPtr);
1468
1469		    return retcode;
1470		  }
1471		else
1472		  break;
1473
1474	      case SQL_DIAG_MESSAGE_TEXT:
1475
1476		isInt = 0;
1477		szval =
1478		    _iodbcdm_getsqlerrmsg (rec, (void *) sqlerrmsg_tab);
1479		break;
1480
1481	      case SQL_DIAG_NATIVE:
1482
1483		isInt = 1;
1484		ival = 0;
1485		break;
1486
1487	      case SQL_DIAG_ROW_NUMBER:
1488
1489		isInt = 1;
1490		if (nHandleType != SQL_HANDLE_STMT || !stmt)
1491		  {
1492		    return SQL_ERROR;
1493		  }
1494		if (!con)
1495		  {
1496		    return SQL_INVALID_HANDLE;
1497		  }
1498                CALL_UDRIVER(con, Handle, retcode, hproc, unicode_driver, en_GetDiagField,
1499                  (nHandleType, dhandle, nRecNumber, nDiagIdentifier,
1500                   pDiagInfoPtr, nBufferLength, pnStringLengthPtr ));
1501               if (hproc != SQL_NULL_HPROC)
1502                 {
1503		    return retcode;
1504                 }
1505               else
1506                 {
1507		    ival = SQL_ROW_NUMBER_UNKNOWN;
1508		    break;
1509                 }
1510
1511	      case SQL_DIAG_SQLSTATE:
1512
1513		isInt = 0;
1514		szval = _iodbcdm_getsqlstate (rec, (void *) sqlerrmsg_tab);
1515		break;
1516
1517	      default:
1518		return SQL_ERROR;
1519	      }
1520	    if (isInt)
1521	      {
1522		if (pDiagInfoPtr)
1523		  *((SQLINTEGER *) pDiagInfoPtr) = ival;
1524	      }
1525	    else
1526	      {
1527	        if (waMode != 'W')
1528	          {
1529		    int len = strlen (szval), len1;
1530		    len1 = len > nBufferLength ? nBufferLength : len;
1531		    if (pnStringLengthPtr)
1532		      *pnStringLengthPtr = len;
1533		    if (pDiagInfoPtr)
1534		      {
1535		        STRNCPY (pDiagInfoPtr, szval, len1);
1536		        *(((SQLCHAR *) pDiagInfoPtr) + len1) = 0;
1537		      }
1538		  }
1539		else
1540		  {
1541		    dm_StrCopyOut2_A2W((SQLCHAR *) szval,
1542		    	(SQLWCHAR *) pDiagInfoPtr, nBufferLength, pnStringLengthPtr);
1543		  }
1544
1545	      }
1546	    break;
1547	  }
1548	else
1549	  {			/* Driver's errors */
1550	    nRecNumber -= nRecs;
1551
1552	    if (!con)
1553	      {
1554		return SQL_NO_DATA_FOUND;
1555	      }
1556
1557            if ((unicode_driver && waMode != 'W')
1558                || (!unicode_driver && waMode == 'W'))
1559              {
1560                switch(nDiagIdentifier)
1561                  {
1562                  case SQL_DIAG_DYNAMIC_FUNCTION:
1563                  case SQL_DIAG_CLASS_ORIGIN:
1564                  case SQL_DIAG_CONNECTION_NAME:
1565                  case SQL_DIAG_MESSAGE_TEXT:
1566                  case SQL_DIAG_SERVER_NAME:
1567                  case SQL_DIAG_SQLSTATE:
1568                  case SQL_DIAG_SUBCLASS_ORIGIN:
1569                    if (waMode != 'W')
1570                      {
1571                      /* ansi=>unicode*/
1572                        if ((_DiagInfoPtr = malloc((nBufferLength + 1) *
1573                               sizeof(wchar_t))) == NULL)
1574                          {
1575                            return SQL_ERROR;
1576                          }
1577                      }
1578                    else
1579                      {
1580                      /* unicode=>ansi*/
1581                        if ((_DiagInfoPtr = malloc(nBufferLength + 1)) == NULL)
1582                          {
1583                            return SQL_ERROR;
1584                          }
1585                      }
1586                    diagInfoPtr = _DiagInfoPtr;
1587                    break;
1588                  }
1589              }
1590
1591            CALL_UDRIVER(con, Handle, retcode, hproc, unicode_driver, en_GetDiagField,
1592              (nHandleType, dhandle, nRecNumber, nDiagIdentifier,
1593               diagInfoPtr, nBufferLength, pnStringLengthPtr ));
1594            if (hproc != SQL_NULL_HPROC)
1595              {
1596                if (pDiagInfoPtr
1597                    && SQL_SUCCEEDED (retcode)
1598                    && ((unicode_driver && waMode != 'W')
1599                        || (!unicode_driver && waMode == 'W')))
1600                  {
1601                    switch(nDiagIdentifier)
1602                      {
1603                      case SQL_DIAG_DYNAMIC_FUNCTION:
1604                      case SQL_DIAG_CLASS_ORIGIN:
1605                      case SQL_DIAG_CONNECTION_NAME:
1606                      case SQL_DIAG_MESSAGE_TEXT:
1607                      case SQL_DIAG_SERVER_NAME:
1608                      case SQL_DIAG_SQLSTATE:
1609                      case SQL_DIAG_SUBCLASS_ORIGIN:
1610                        if (waMode != 'W')
1611                          {
1612                          /* ansi<=unicode*/
1613                            dm_StrCopyOut2_W2A ((SQLWCHAR *) diagInfoPtr,
1614				(SQLCHAR *) pDiagInfoPtr,
1615				nBufferLength, pnStringLengthPtr);
1616                          }
1617                        else
1618                          {
1619                          /* unicode<=ansi*/
1620                            dm_StrCopyOut2_A2W ((SQLCHAR *)diagInfoPtr,
1621			    	(SQLWCHAR *) pDiagInfoPtr,
1622				nBufferLength, pnStringLengthPtr);
1623                          }
1624                      }
1625                  }
1626
1627                MEM_FREE(_DiagInfoPtr);
1628		return retcode;
1629              }
1630            else
1631	      {			/* an ODBC2->ODBC3 translation */
1632		char *szval = "";
1633		wchar_t szState[6];
1634		SQLINTEGER nNative;
1635
1636		if (nRecNumber > 1)
1637		  {
1638                    MEM_FREE(_DiagInfoPtr);
1639		    return SQL_NO_DATA_FOUND;
1640		  }
1641
1642		if (nHandleType == SQL_HANDLE_DESC)
1643		  {
1644                    MEM_FREE(_DiagInfoPtr);
1645		    return SQL_INVALID_HANDLE;
1646		  }
1647
1648		if (nDiagIdentifier != SQL_DIAG_MESSAGE_TEXT)
1649                   MEM_FREE(_DiagInfoPtr);
1650
1651		switch (nDiagIdentifier)
1652		  {
1653		  case SQL_DIAG_SUBCLASS_ORIGIN:
1654		  case SQL_DIAG_CLASS_ORIGIN:
1655
1656		    CALL_UDRIVER (con, Handle, retcode, hproc, unicode_driver,
1657		      en_Error, (SQL_NULL_HENV,
1658		       nHandleType == SQL_HANDLE_DBC ? dhandle : SQL_NULL_HDBC,
1659		       nHandleType == SQL_HANDLE_STMT ? dhandle : SQL_NULL_HSTMT,
1660 		       szState, &nNative, NULL, 0, NULL));
1661                    if (hproc == SQL_NULL_HPROC)
1662                      {
1663		        return SQL_INVALID_HANDLE;
1664                      }
1665		    if (retcode != SQL_SUCCESS)
1666		      {
1667			return SQL_NO_DATA_FOUND;
1668		      }
1669		    if (waMode != 'W')
1670                      {
1671		        szval = !STRNEQ (szState, "IM", 2) ? (char *) "ODBC 3.0" : (char *) "ISO 9075";
1672                      }
1673		    else
1674                      {
1675                        if (szState[0] != L'I' && szState[1] != L'M')
1676		          szval = (char *) "ODBC 3.0";
1677                        else
1678		          szval = (char *) "ISO 9075";
1679                      }
1680		    break;
1681
1682		  case SQL_DIAG_ROW_NUMBER:
1683		  case SQL_DIAG_COLUMN_NUMBER:
1684		    if (nHandleType != SQL_HANDLE_STMT || !stmt)
1685		      {
1686			return SQL_ERROR;
1687		      }
1688		    if (!con)
1689		      {
1690			return SQL_INVALID_HANDLE;
1691		      }
1692		    if (pDiagInfoPtr)
1693		      *((SQLINTEGER *) pDiagInfoPtr) =
1694			  SQL_COLUMN_NUMBER_UNKNOWN;
1695		    {
1696		      return SQL_SUCCESS;
1697		    }
1698
1699		  case SQL_DIAG_SERVER_NAME:
1700		  case SQL_DIAG_CONNECTION_NAME:
1701		    break;
1702
1703		  case SQL_DIAG_MESSAGE_TEXT:
1704		    CALL_UDRIVER (con, Handle, retcode, hproc, unicode_driver,
1705		      en_Error, (SQL_NULL_HENV,
1706		      nHandleType == SQL_HANDLE_DBC ? dhandle : SQL_NULL_HDBC,
1707		      nHandleType == SQL_HANDLE_STMT ? dhandle : SQL_NULL_HSTMT,
1708 		      szState, &nNative, diagInfoPtr, nBufferLength,
1709 		      pnStringLengthPtr));
1710                    if (hproc == SQL_NULL_HPROC)
1711                      {
1712                        MEM_FREE(_DiagInfoPtr);
1713		        return SQL_INVALID_HANDLE;
1714                      }
1715                    if (pDiagInfoPtr
1716                        && SQL_SUCCEEDED (retcode)
1717                        && ((unicode_driver && waMode != 'W')
1718                            || (!unicode_driver && waMode == 'W')))
1719                      {
1720                        if (waMode != 'W')
1721                          {
1722                          /* ansi<=unicode*/
1723                            dm_StrCopyOut2_W2A ((SQLWCHAR *) diagInfoPtr,
1724				(SQLCHAR *) pDiagInfoPtr,
1725		      		nBufferLength, pnStringLengthPtr);
1726                          }
1727                        else
1728                          {
1729                          /* unicode<=ansi*/
1730                            dm_StrCopyOut2_A2W ((SQLCHAR *)diagInfoPtr,
1731			    	(SQLWCHAR *) pDiagInfoPtr,
1732				nBufferLength, pnStringLengthPtr);
1733                          }
1734                      }
1735
1736                    MEM_FREE(_DiagInfoPtr);
1737		    return retcode;
1738
1739		  case SQL_DIAG_NATIVE:
1740		    CALL_UDRIVER (con, Handle, retcode, hproc, unicode_driver,
1741		      en_Error, (SQL_NULL_HENV,
1742		      nHandleType == SQL_HANDLE_DBC ? dhandle : SQL_NULL_HDBC,
1743		      nHandleType == SQL_HANDLE_STMT ? dhandle : SQL_NULL_HSTMT,
1744 		      szState, &nNative, NULL, 0, NULL));
1745                    if (hproc == SQL_NULL_HPROC)
1746                      {
1747		        return SQL_INVALID_HANDLE;
1748                      }
1749		    if (pDiagInfoPtr)
1750		      *((SQLINTEGER *) pDiagInfoPtr) = nNative;
1751		    return retcode;
1752
1753		  case SQL_DIAG_SQLSTATE:
1754		    CALL_UDRIVER (con, Handle, retcode, hproc, unicode_driver,
1755		      en_Error, (SQL_NULL_HENV,
1756		      nHandleType == SQL_HANDLE_DBC ? dhandle : SQL_NULL_HDBC,
1757		      nHandleType == SQL_HANDLE_STMT ? dhandle : SQL_NULL_HSTMT,
1758 		      szState, &nNative, NULL, 0, NULL));
1759                    if (hproc == SQL_NULL_HPROC)
1760                      {
1761		        return SQL_INVALID_HANDLE;
1762                      }
1763                    if (pDiagInfoPtr
1764                        && SQL_SUCCEEDED (retcode)
1765                        && ((unicode_driver && waMode != 'W')
1766                            || (!unicode_driver && waMode == 'W')))
1767                      {
1768                        if (waMode != 'W')
1769                          {
1770                          /* ansi<=unicode*/
1771                            dm_StrCopyOut2_W2A ((SQLWCHAR *) szState,
1772				(SQLCHAR *) pDiagInfoPtr,
1773		      		nBufferLength, pnStringLengthPtr);
1774                          }
1775                        else
1776                          {
1777                          /* unicode<=ansi*/
1778                            dm_StrCopyOut2_A2W ((SQLCHAR *)szState,
1779			    	(SQLWCHAR *) pDiagInfoPtr,
1780				nBufferLength, pnStringLengthPtr);
1781                          }
1782                      }
1783
1784		    return retcode;
1785
1786		  default:
1787		    return SQL_ERROR;
1788		  }
1789
1790	        if (waMode != 'W')
1791	          {
1792		    if (pDiagInfoPtr)
1793		      {
1794		        int len = strlen (szval);
1795		        if (len > nBufferLength)
1796		          len = nBufferLength;
1797		        if (len)
1798		          _iodbcdm_strlcpy ((char *) pDiagInfoPtr, szval, len);
1799		      }
1800		    if (pnStringLengthPtr)
1801		      *pnStringLengthPtr = strlen (szval);
1802		  }
1803		else
1804		  {
1805		    dm_StrCopyOut2_A2W((SQLCHAR *) szval,
1806		    	(SQLWCHAR *) pDiagInfoPtr,
1807			nBufferLength, pnStringLengthPtr);
1808		  }
1809	      }			/* ODBC3->ODBC2 */
1810	  }			/* driver's errors */
1811      }				/* status records */
1812    }				/* switch (nRecNumber */
1813  return (SQL_SUCCESS);
1814}
1815
1816
1817RETCODE SQL_API
1818SQLGetDiagField (
1819  SQLSMALLINT		  HandleType,
1820  SQLHANDLE		  Handle,
1821  SQLSMALLINT		  RecNumber,
1822  SQLSMALLINT		  DiagIdentifier,
1823  SQLPOINTER		  DiagInfoPtr,
1824  SQLSMALLINT		  BufferLength,
1825  SQLSMALLINT		* StringLengthPtr)
1826{
1827  SQLRETURN retcode = SQL_SUCCESS;
1828
1829  ODBC_LOCK ();
1830
1831  TRACE (trace_SQLGetDiagField (TRACE_ENTER,
1832  	HandleType,
1833	Handle,
1834	RecNumber,
1835	DiagIdentifier,
1836	DiagInfoPtr, BufferLength, StringLengthPtr));
1837
1838  retcode = SQLGetDiagField_Internal (
1839  	HandleType,
1840	Handle,
1841	RecNumber,
1842	DiagIdentifier,
1843	DiagInfoPtr, BufferLength, StringLengthPtr,
1844	'A');
1845
1846  TRACE (trace_SQLGetDiagField (TRACE_LEAVE,
1847  	HandleType,
1848	Handle,
1849	RecNumber,
1850	DiagIdentifier,
1851	DiagInfoPtr, BufferLength, StringLengthPtr));
1852
1853  ODBC_UNLOCK ();
1854
1855  return retcode;
1856}
1857
1858
1859RETCODE SQL_API
1860SQLGetDiagFieldA (
1861  SQLSMALLINT		  HandleType,
1862  SQLHANDLE		  Handle,
1863  SQLSMALLINT		  RecNumber,
1864  SQLSMALLINT		  DiagIdentifier,
1865  SQLPOINTER		  DiagInfoPtr,
1866  SQLSMALLINT		  BufferLength,
1867  SQLSMALLINT		* StringLengthPtr)
1868{
1869  SQLRETURN retcode = SQL_SUCCESS;
1870
1871  ODBC_LOCK ();
1872
1873  TRACE (trace_SQLGetDiagField (TRACE_ENTER,
1874  	HandleType,
1875	Handle,
1876	RecNumber,
1877	DiagIdentifier,
1878	DiagInfoPtr, BufferLength, StringLengthPtr));
1879
1880  retcode = SQLGetDiagField_Internal (
1881  	HandleType,
1882	Handle,
1883	RecNumber,
1884	DiagIdentifier,
1885	DiagInfoPtr, BufferLength, StringLengthPtr,
1886	'A');
1887
1888  TRACE (trace_SQLGetDiagField (TRACE_LEAVE,
1889  	HandleType,
1890	Handle,
1891	RecNumber,
1892	DiagIdentifier,
1893	DiagInfoPtr, BufferLength, StringLengthPtr));
1894
1895  ODBC_UNLOCK ();
1896
1897  return retcode;
1898}
1899
1900
1901RETCODE SQL_API
1902SQLGetDiagFieldW (
1903  SQLSMALLINT		  HandleType,
1904  SQLHANDLE		  Handle,
1905  SQLSMALLINT		  RecNumber,
1906  SQLSMALLINT		  DiagIdentifier,
1907  SQLPOINTER		  DiagInfoPtr,
1908  SQLSMALLINT		  BufferLength,
1909  SQLSMALLINT		* StringLengthPtr)
1910{
1911  SQLRETURN retcode = SQL_SUCCESS;
1912
1913  ODBC_LOCK ();
1914
1915  TRACE (trace_SQLGetDiagFieldW (TRACE_ENTER,
1916  	HandleType,
1917	Handle,
1918	RecNumber,
1919	DiagIdentifier,
1920	DiagInfoPtr, BufferLength, StringLengthPtr));
1921
1922  retcode = SQLGetDiagField_Internal (
1923  	HandleType,
1924	Handle,
1925	RecNumber,
1926	DiagIdentifier,
1927	DiagInfoPtr, BufferLength, StringLengthPtr,
1928	'W');
1929
1930  TRACE (trace_SQLGetDiagFieldW (TRACE_LEAVE,
1931  	HandleType,
1932	Handle,
1933	RecNumber,
1934	DiagIdentifier,
1935	DiagInfoPtr, BufferLength, StringLengthPtr));
1936
1937  ODBC_UNLOCK ();
1938
1939  return retcode;
1940}
1941#endif
1942