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 
43 static HERR
_iodbcdm_popsqlerr(HERR 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 
62 void
_iodbcdm_freesqlerrlist(HERR herrlist)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 
74 HERR
_iodbcdm_pushsqlerr(HERR herr,sqlstcode_t code,char * msg)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 
114 static char FAR *
_iodbcdm_getsqlstate(HERR herr,void FAR * tab)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 
141 static char FAR *
_iodbcdm_getsqlerrmsg(HERR herr,void FAR * errtab)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 
178 RETCODE SQL_API
SQLError(HENV henv,HDBC hdbc,HSTMT hstmt,UCHAR FAR * szSqlstate,SDWORD FAR * pfNativeError,UCHAR FAR * szErrorMsg,SWORD cbErrorMsgMax,SWORD FAR * pcbErrorMsg)179 SQLError (
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