1999-01-22 10:52:42 +00:00
|
|
|
/*
|
|
|
|
* herr.c
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Error stack management functions
|
|
|
|
*
|
|
|
|
* The iODBC driver manager.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1995 by Ke Jin <kejin@empress.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the Free
|
|
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <isql.h>
|
|
|
|
#include <isqlext.h>
|
|
|
|
|
|
|
|
#include <dlproc.h>
|
|
|
|
|
|
|
|
#include <herr.h>
|
|
|
|
#include <henv.h>
|
|
|
|
#include <hdbc.h>
|
|
|
|
#include <hstmt.h>
|
|
|
|
|
|
|
|
#include <itrace.h>
|
|
|
|
|
|
|
|
#include "herr.ci"
|
|
|
|
|
|
|
|
static HERR
|
|
|
|
_iodbcdm_popsqlerr (HERR herr)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
sqlerr_t *list = (sqlerr_t *) herr;
|
|
|
|
sqlerr_t *next;
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
if (herr == SQL_NULL_HERR)
|
|
|
|
{
|
|
|
|
return herr;
|
|
|
|
}
|
1998-07-18 00:57:32 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
next = list->next;
|
1998-07-18 00:57:32 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
MEM_FREE (list);
|
1998-07-18 00:57:32 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
return next;
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
_iodbcdm_freesqlerrlist (HERR herrlist)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
HERR list;
|
1998-07-18 00:57:32 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
for (list = herrlist; list != 0;)
|
|
|
|
{
|
|
|
|
list = _iodbcdm_popsqlerr (list);
|
|
|
|
}
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
|
|
|
|
HERR
|
|
|
|
_iodbcdm_pushsqlerr (
|
|
|
|
HERR herr,
|
|
|
|
sqlstcode_t code,
|
|
|
|
char *msg)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
sqlerr_t *ebuf;
|
|
|
|
sqlerr_t *perr = (sqlerr_t *) herr;
|
|
|
|
int idx = 0;
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
if (herr != SQL_NULL_HERR)
|
|
|
|
{
|
|
|
|
idx = perr->idx + 1;
|
|
|
|
}
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
if (idx == 64)
|
|
|
|
/* over wirte the top entry to prevent error stack blow out */
|
|
|
|
{
|
|
|
|
perr->code = code;
|
|
|
|
perr->msg = msg;
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
return herr;
|
|
|
|
}
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
ebuf = (sqlerr_t *) MEM_ALLOC (sizeof (sqlerr_t));
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
if (ebuf == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
ebuf->msg = msg;
|
|
|
|
ebuf->code = code;
|
|
|
|
ebuf->idx = idx;
|
|
|
|
ebuf->next = (sqlerr_t *) herr;
|
1998-12-30 23:30:49 +00:00
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
return (HERR) ebuf;
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
|
|
|
|
static char FAR *
|
|
|
|
_iodbcdm_getsqlstate (
|
|
|
|
HERR herr,
|
|
|
|
void FAR * tab)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
sqlerr_t *perr = (sqlerr_t *) herr;
|
|
|
|
sqlerrmsg_t *ptr;
|
|
|
|
|
|
|
|
if (herr == SQL_NULL_HERR || tab == NULL)
|
|
|
|
{
|
|
|
|
return (char FAR *) NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ptr = tab;
|
|
|
|
ptr->code != en_sqlstat_total;
|
|
|
|
ptr++)
|
|
|
|
{
|
|
|
|
if (ptr->code == perr->code)
|
|
|
|
{
|
|
|
|
return (char FAR *) (ptr->stat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (char FAR *) NULL;
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
|
|
|
|
static char FAR *
|
|
|
|
_iodbcdm_getsqlerrmsg (
|
|
|
|
HERR herr,
|
|
|
|
void FAR * errtab)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
sqlerr_t *perr = (sqlerr_t *) herr;
|
|
|
|
sqlerrmsg_t *ptr;
|
|
|
|
|
|
|
|
if (herr == SQL_NULL_HERR)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (perr->msg == NULL && errtab == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (perr->msg != NULL)
|
|
|
|
{
|
|
|
|
return perr->msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ptr = (sqlerrmsg_t *) errtab;
|
|
|
|
ptr->code != en_sqlstat_total;
|
|
|
|
ptr++)
|
|
|
|
{
|
|
|
|
if (ptr->code == perr->code)
|
|
|
|
{
|
|
|
|
return (char FAR *) ptr->msg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (char FAR *) NULL;
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|
|
|
|
|
1999-01-22 10:52:42 +00:00
|
|
|
|
|
|
|
RETCODE SQL_API
|
|
|
|
SQLError (
|
|
|
|
HENV henv,
|
|
|
|
HDBC hdbc,
|
|
|
|
HSTMT hstmt,
|
|
|
|
UCHAR FAR * szSqlstate,
|
|
|
|
SDWORD FAR * pfNativeError,
|
|
|
|
UCHAR FAR * szErrorMsg,
|
|
|
|
SWORD cbErrorMsgMax,
|
|
|
|
SWORD FAR * pcbErrorMsg)
|
1998-07-18 00:57:32 +00:00
|
|
|
{
|
1999-01-22 10:52:42 +00:00
|
|
|
GENV_t FAR *genv = (GENV_t FAR *) henv;
|
|
|
|
DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
|
|
|
|
STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
|
|
|
|
HDBC thdbc;
|
|
|
|
|
|
|
|
HENV dhenv = SQL_NULL_HENV;
|
|
|
|
HDBC dhdbc = SQL_NULL_HDBC;
|
|
|
|
HSTMT dhstmt = SQL_NULL_HSTMT;
|
|
|
|
|
|
|
|
HERR herr = SQL_NULL_HERR;
|
|
|
|
HPROC hproc = SQL_NULL_HPROC;
|
|
|
|
|
|
|
|
char FAR *errmsg = NULL;
|
|
|
|
char FAR *ststr = NULL;
|
|
|
|
|
|
|
|
int handle = 0;
|
|
|
|
RETCODE retcode = SQL_SUCCESS;
|
|
|
|
|
|
|
|
if (hstmt != SQL_NULL_HSTMT) /* retrive stmt err */
|
|
|
|
{
|
|
|
|
herr = pstmt->herr;
|
|
|
|
thdbc = pstmt->hdbc;
|
|
|
|
|
|
|
|
if (thdbc == SQL_NULL_HDBC)
|
|
|
|
{
|
|
|
|
return SQL_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
hproc = _iodbcdm_getproc (thdbc, en_Error);
|
|
|
|
dhstmt = pstmt->dhstmt;
|
|
|
|
handle = 3;
|
|
|
|
}
|
|
|
|
else if (hdbc != SQL_NULL_HDBC) /* retrive dbc err */
|
|
|
|
{
|
|
|
|
herr = pdbc->herr;
|
|
|
|
thdbc = hdbc;
|
|
|
|
if (thdbc == SQL_NULL_HDBC)
|
|
|
|
{
|
|
|
|
return SQL_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
hproc = _iodbcdm_getproc (thdbc, en_Error);
|
|
|
|
dhdbc = pdbc->dhdbc;
|
|
|
|
handle = 2;
|
|
|
|
|
|
|
|
if (herr == SQL_NULL_HERR
|
|
|
|
&& pdbc->henv == SQL_NULL_HENV)
|
|
|
|
{
|
|
|
|
return SQL_NO_DATA_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (henv != SQL_NULL_HENV) /* retrive env err */
|
|
|
|
{
|
|
|
|
herr = genv->herr;
|
|
|
|
|
|
|
|
/* Drivers shouldn't push error message
|
|
|
|
* on envoriment handle */
|
|
|
|
|
|
|
|
if (herr == SQL_NULL_HERR)
|
|
|
|
{
|
|
|
|
return SQL_NO_DATA_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return SQL_INVALID_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (szErrorMsg != NULL)
|
|
|
|
{
|
|
|
|
if (cbErrorMsgMax < 0
|
|
|
|
|| cbErrorMsgMax > SQL_MAX_MESSAGE_LENGTH - 1)
|
|
|
|
{
|
|
|
|
return SQL_ERROR;
|
|
|
|
/* SQLError() doesn't post error for itself */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (herr == SQL_NULL_HERR) /* no err on drv mng */
|
|
|
|
{
|
|
|
|
/* call driver */
|
|
|
|
if (hproc == SQL_NULL_HPROC)
|
|
|
|
{
|
|
|
|
PUSHSQLERR (herr, en_IM001);
|
|
|
|
|
|
|
|
return SQL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
CALL_DRIVER (thdbc, retcode, hproc, en_Error,
|
|
|
|
(dhenv, dhdbc, dhstmt, szSqlstate, pfNativeError, szErrorMsg,
|
|
|
|
cbErrorMsgMax, pcbErrorMsg))
|
|
|
|
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (szSqlstate != NULL)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
/* get sql state string */
|
|
|
|
ststr = (char FAR *) _iodbcdm_getsqlstate (herr,
|
|
|
|
(void FAR *) sqlerrmsg_tab);
|
|
|
|
|
|
|
|
if (ststr == NULL)
|
|
|
|
{
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = (int) STRLEN (ststr);
|
|
|
|
}
|
|
|
|
|
|
|
|
STRNCPY (szSqlstate, ststr, len);
|
|
|
|
szSqlstate[len] = 0;
|
|
|
|
/* buffer size of szSqlstate is not checked. Applications
|
|
|
|
* suppose provide enough ( not less than 6 bytes ) buffer
|
|
|
|
* or NULL for it.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pfNativeError != NULL)
|
|
|
|
{
|
|
|
|
/* native error code is specific to data source */
|
|
|
|
*pfNativeError = (SDWORD) 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (szErrorMsg == NULL || cbErrorMsgMax == 0)
|
|
|
|
{
|
|
|
|
if (pcbErrorMsg != NULL)
|
|
|
|
{
|
|
|
|
*pcbErrorMsg = (SWORD) 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char msgbuf[256] = {'\0'};
|
|
|
|
|
|
|
|
/* get sql state message */
|
|
|
|
errmsg = _iodbcdm_getsqlerrmsg (herr, (void FAR *) sqlerrmsg_tab);
|
|
|
|
|
|
|
|
if (errmsg == NULL)
|
|
|
|
{
|
|
|
|
errmsg = (char FAR *) "";
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf (msgbuf, "%s%s", sqlerrhd, errmsg);
|
|
|
|
|
|
|
|
len = STRLEN (msgbuf);
|
|
|
|
|
|
|
|
if (len < cbErrorMsgMax - 1)
|
|
|
|
{
|
|
|
|
retcode = SQL_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = cbErrorMsgMax - 1;
|
|
|
|
retcode = SQL_SUCCESS_WITH_INFO;
|
|
|
|
/* and not posts error for itself */
|
|
|
|
}
|
|
|
|
|
|
|
|
STRNCPY ((char *) szErrorMsg, msgbuf, len);
|
|
|
|
szErrorMsg[len] = 0;
|
|
|
|
|
|
|
|
if (pcbErrorMsg != NULL)
|
|
|
|
{
|
|
|
|
*pcbErrorMsg = (SWORD) len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (handle) /* free this err */
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
genv->herr = _iodbcdm_popsqlerr (genv->herr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
pdbc->herr = _iodbcdm_popsqlerr (pdbc->herr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
pstmt->herr = _iodbcdm_popsqlerr (pstmt->herr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retcode;
|
1998-07-18 00:57:32 +00:00
|
|
|
}
|