1/*
2 *  herr.c
3 *
4 *  $Id: herr.c 2613 1999-06-01 15:32:12Z VZ $
5 *
6 *  Error stack management functions
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11 *
12 *  This library is free software; you can redistribute it and/or
13 *  modify it under the terms of the GNU Library General Public
14 *  License as published by the Free Software Foundation; either
15 *  version 2 of the License, or (at your option) any later version.
16 *
17 *  This library is distributed in the hope that it will be useful,
18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 *  Library General Public License for more details.
21 *
22 *  You should have received a copy of the GNU Library General Public
23 *  License along with this library; if not, write to the Free
24 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include	"config.h"
28
29#include	"isql.h"
30#include	"isqlext.h"
31
32#include        "dlproc.h"
33
34#include        "herr.h"
35#include	"henv.h"
36#include	"hdbc.h"
37#include	"hstmt.h"
38
39#include	"itrace.h"
40
41#include	"herr.ci"
42
43static HERR
44_iodbcdm_popsqlerr (HERR herr)
45{
46  sqlerr_t *list = (sqlerr_t *) herr;
47  sqlerr_t *next;
48
49  if (herr == SQL_NULL_HERR)
50    {
51      return herr;
52    }
53
54  next = list->next;
55
56  MEM_FREE (list);
57
58  return next;
59}
60
61
62void
63_iodbcdm_freesqlerrlist (HERR herrlist)
64{
65  HERR list;
66
67  for (list = herrlist; list != 0;)
68    {
69      list = _iodbcdm_popsqlerr (list);
70    }
71}
72
73
74HERR
75_iodbcdm_pushsqlerr (
76    HERR herr,
77    sqlstcode_t code,
78    char *msg)
79{
80  sqlerr_t *ebuf;
81  sqlerr_t *perr = (sqlerr_t *) herr;
82  int idx = 0;
83
84  if (herr != SQL_NULL_HERR)
85    {
86      idx = perr->idx + 1;
87    }
88
89  if (idx == 64)
90    /* over wirte the top entry to prevent error stack blow out */
91    {
92      perr->code = code;
93      perr->msg = msg;
94
95      return herr;
96    }
97
98  ebuf = (sqlerr_t *) MEM_ALLOC (sizeof (sqlerr_t));
99
100  if (ebuf == NULL)
101    {
102      return NULL;
103    }
104
105  ebuf->msg = msg;
106  ebuf->code = code;
107  ebuf->idx = idx;
108  ebuf->next = (sqlerr_t *) herr;
109
110  return (HERR) ebuf;
111}
112
113
114static char FAR *
115_iodbcdm_getsqlstate (
116    HERR herr,
117    void FAR * tab)
118{
119  sqlerr_t *perr = (sqlerr_t *) herr;
120  sqlerrmsg_t *ptr;
121
122  if (herr == SQL_NULL_HERR || tab == NULL)
123    {
124      return (char FAR *) NULL;
125    }
126
127  for (ptr = tab;
128      ptr->code != en_sqlstat_total;
129      ptr++)
130    {
131      if (ptr->code == perr->code)
132	{
133	  return (char FAR *) (ptr->stat);
134	}
135    }
136
137  return (char FAR *) NULL;
138}
139
140
141static char FAR *
142_iodbcdm_getsqlerrmsg (
143    HERR herr,
144    void FAR * errtab)
145{
146  sqlerr_t *perr = (sqlerr_t *) herr;
147  sqlerrmsg_t *ptr;
148
149  if (herr == SQL_NULL_HERR)
150    {
151      return NULL;
152    }
153
154  if (perr->msg == NULL && errtab == NULL)
155    {
156      return NULL;
157    }
158
159  if (perr->msg != NULL)
160    {
161      return perr->msg;
162    }
163
164  for (ptr = (sqlerrmsg_t *) errtab;
165      ptr->code != en_sqlstat_total;
166      ptr++)
167    {
168      if (ptr->code == perr->code)
169	{
170	  return (char FAR *) ptr->msg;
171	}
172    }
173
174  return (char FAR *) NULL;
175}
176
177
178RETCODE SQL_API
179SQLError (
180    HENV henv,
181    HDBC hdbc,
182    HSTMT hstmt,
183    UCHAR FAR * szSqlstate,
184    SDWORD FAR * pfNativeError,
185    UCHAR FAR * szErrorMsg,
186    SWORD cbErrorMsgMax,
187    SWORD FAR * pcbErrorMsg)
188{
189  GENV_t FAR *genv = (GENV_t FAR *) henv;
190  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
191  STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
192  HDBC thdbc;
193
194  HENV dhenv = SQL_NULL_HENV;
195  HDBC dhdbc = SQL_NULL_HDBC;
196  HSTMT dhstmt = SQL_NULL_HSTMT;
197
198  HERR herr = SQL_NULL_HERR;
199  HPROC hproc = SQL_NULL_HPROC;
200
201  char FAR *errmsg = NULL;
202  char FAR *ststr = NULL;
203
204  int handle = 0;
205  RETCODE retcode = SQL_SUCCESS;
206
207  if (hstmt != SQL_NULL_HSTMT)	/* retrive stmt err */
208    {
209      herr = pstmt->herr;
210      thdbc = pstmt->hdbc;
211
212      if (thdbc == SQL_NULL_HDBC)
213	{
214	  return SQL_INVALID_HANDLE;
215	}
216      hproc = _iodbcdm_getproc (thdbc, en_Error);
217      dhstmt = pstmt->dhstmt;
218      handle = 3;
219    }
220  else if (hdbc != SQL_NULL_HDBC)	/* retrive dbc err */
221    {
222      herr = pdbc->herr;
223      thdbc = hdbc;
224      if (thdbc == SQL_NULL_HDBC)
225	{
226	  return SQL_INVALID_HANDLE;
227	}
228      hproc = _iodbcdm_getproc (thdbc, en_Error);
229      dhdbc = pdbc->dhdbc;
230      handle = 2;
231
232      if (herr == SQL_NULL_HERR
233	  && pdbc->henv == SQL_NULL_HENV)
234	{
235	  return SQL_NO_DATA_FOUND;
236	}
237    }
238  else if (henv != SQL_NULL_HENV)	/* retrive env err */
239    {
240      herr = genv->herr;
241
242      /* Drivers shouldn't push error message
243       * on envoriment handle */
244
245      if (herr == SQL_NULL_HERR)
246	{
247	  return SQL_NO_DATA_FOUND;
248	}
249
250      handle = 1;
251    }
252  else
253    {
254      return SQL_INVALID_HANDLE;
255    }
256
257  if (szErrorMsg != NULL)
258    {
259      if (cbErrorMsgMax < 0
260	  || cbErrorMsgMax > SQL_MAX_MESSAGE_LENGTH - 1)
261	{
262	  return SQL_ERROR;
263	  /* SQLError() doesn't post error for itself */
264	}
265    }
266
267  if (herr == SQL_NULL_HERR)	/* no err on drv mng */
268    {
269      /* call driver */
270      if (hproc == SQL_NULL_HPROC)
271	{
272	  PUSHSQLERR (herr, en_IM001);
273
274	  return SQL_ERROR;
275	}
276
277      CALL_DRIVER (thdbc, retcode, hproc, en_Error,
278	  (dhenv, dhdbc, dhstmt, szSqlstate, pfNativeError, szErrorMsg,
279	      cbErrorMsgMax, pcbErrorMsg))
280
281      return retcode;
282    }
283
284  if (szSqlstate != NULL)
285    {
286      int len;
287
288      /* get sql state  string */
289      ststr = (char FAR *) _iodbcdm_getsqlstate (herr,
290	  (void FAR *) sqlerrmsg_tab);
291
292      if (ststr == NULL)
293	{
294	  len = 0;
295	}
296      else
297	{
298	  len = (int) STRLEN (ststr);
299	}
300
301      STRNCPY (szSqlstate, ststr, len);
302      szSqlstate[len] = 0;
303      /* buffer size of szSqlstate is not checked. Applications
304       * suppose provide enough ( not less than 6 bytes ) buffer
305       * or NULL for it.
306       */
307    }
308
309  if (pfNativeError != NULL)
310    {
311      /* native error code is specific to data source */
312      *pfNativeError = (SDWORD) 0L;
313    }
314
315  if (szErrorMsg == NULL || cbErrorMsgMax == 0)
316    {
317      if (pcbErrorMsg != NULL)
318	{
319	  *pcbErrorMsg = (SWORD) 0;
320	}
321    }
322  else
323    {
324      int len;
325      char msgbuf[256] = {'\0'};
326
327      /* get sql state message */
328      errmsg = _iodbcdm_getsqlerrmsg (herr, (void FAR *) sqlerrmsg_tab);
329
330      if (errmsg == NULL)
331	{
332	  errmsg = (char FAR *) "";
333	}
334
335      sprintf (msgbuf, "%s%s", sqlerrhd, errmsg);
336
337      len = STRLEN (msgbuf);
338
339      if (len < cbErrorMsgMax - 1)
340	{
341	  retcode = SQL_SUCCESS;
342	}
343      else
344	{
345	  len = cbErrorMsgMax - 1;
346	  retcode = SQL_SUCCESS_WITH_INFO;
347	  /* and not posts error for itself */
348	}
349
350      STRNCPY ((char *) szErrorMsg, msgbuf, len);
351      szErrorMsg[len] = 0;
352
353      if (pcbErrorMsg != NULL)
354	{
355	  *pcbErrorMsg = (SWORD) len;
356	}
357    }
358
359  switch (handle)		/* free this err */
360     {
361     case 1:
362       genv->herr = _iodbcdm_popsqlerr (genv->herr);
363       break;
364
365     case 2:
366       pdbc->herr = _iodbcdm_popsqlerr (pdbc->herr);
367       break;
368
369     case 3:
370       pstmt->herr = _iodbcdm_popsqlerr (pstmt->herr);
371       break;
372
373     default:
374       break;
375     }
376
377  return retcode;
378}
379