Logo Search packages:      
Sourcecode: unixodbc version File versions  Download package

error.c

/***************************************************************************  
 * Copyright (C) 1995-2002 MySQL AB, www.mysql.com                         *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 2 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program 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 General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program; if not, write to the Free Software Foundation  *
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA           *
****************************************************************************/

/*************************************************************************** 
 * ERROR.C                                                                 *
 *                                                                         *
 * @description: MyODBC 3.51 error handling                                *
 *                                                                         *
 * @author     : MySQL AB(monty@mysql.com, venu@mysql.com)                 *
 * @date       : 2001-Aug-15                                               *
 * @product    : myodbc3                                                   *
 *                                                                         *
****************************************************************************/

/*************************************************************************** 
 * The following ODBC APIs are implemented in this file:                   *
 *                                                                         *
 *   SQLGetDiagField     (ISO 92)                                          *
 *   SQLGetDiagRec       (ISO 92)                                          *
 *   SQLError            (ODBC, Deprecated)                                *
 *                                                                         *
****************************************************************************/

#include "myodbc3.h"
#include "mysqld_error.h"
#include "errmsg.h"

/*
  @type    : myodbc3 internal error structure
  @purpose : set of internal errors, in the following order
       - SQLSTATE2 (when version is SQL_OV_ODBC2)
       - SQLSTATE3 (when version is SQL_OV_ODBC3)
       - error message text
       - return code
*/

static const MYODBC3_ERR_STR myodbc3_errors[]={

  {"01000","01000","General warning",1 },
  {"01004","01004","String data, right truncated",1 },
  {"01S02","01S02","Option value changed",1 },
  {"01S03","01S03","No rows updated/deleted",1 },
  {"01S04","01S04","More than one row updated/deleted",1 },
  {"01S06","01S06","Attempt to fetch before the result set returned the first rowset",1 },
  {"07001","07002","SQLBindParameter not used for all parameters",-1 },
  {"07005","07005","Prepared statement not a cursor-specification",-1 },
  {"07009","07009","Invalid descriptor index",-1 },
  {"08002","08002","Connection name in use",-1 },
  {"08003","08003","Connection does not exist",-1 },
  {"24000","24000","Invalid cursor state",-1 },
  {"25000","25000","Invalid transaction state",-1 },
  {"25S01","25S01","Transaction state unknown",-1 },
  {"34000","34000","Invalid cursor name",-1 },
  {"S1000","HY000","General driver defined error",-1 },
  {"S1001","HY001","Memory allocation error",-1 },
  {"S1002","HY002","Invalid column number",-1 },
  {"S1003","HY003","Invalid application buffer type",-1 },
  {"S1004","HY004","Invalid SQL data type",-1 },
  {"S1009","HY009","Invalid use of null pointer",-1 },
  {"S1010","HY010","Function sequence error",-1 },
  {"S1011","HY011","Attribute can not be set now",-1 },
  {"S1012","HY012","Invalid transaction operation code",-1 },
  {"S1013","HY013","Memory management error",-1 },
  {"S1015","HY015","No cursor name available",-1 },
  {"S1024","HY024","Invalid attribute value",-1 },
  {"S1090","HY090","Invalid string or buffer length",-1 },
  {"S1091","HY091","Invalid descriptor field identifier",-1 },
  {"S1092","HY092","Invalid attribute/option identifier",-1 },
  {"S1093","HY093","Invalid parameter number",-1 },
  {"S1095","HY095","Function type out of range",-1 },
  {"S1106","HY106","Fetch type out of range",-1 },
  {"S1107","HY107","Row value out of range",-1 },
  {"S1109","HY109","Invalid cursor position",-1 },
  {"S1C00","HYC00","Optional feature not implemented",-1 },
  /* server related..*/
  {"21S01","21S01","Column count does not match value count",-1},
  {"23000","23000","Integrity constraint violation",-1},
  {"42000","42000","Syntax error or access violation",-1},
  {"42S02","42S02","Base table or view not found",-1},
  {"42S12","42S12","Index not found",-1},
  {"42S21","42S21","Column already exists",-1},
  {"42S22","42S22","Column not found",-1},
  {"08S01","08S01","Communication link failure",-1},
};

/*
  @type    : myodbc3 internal
  @purpose : copies error from one handdle to other
*/

SQLRETURN copy_stmt_error(STMT FAR *dst,STMT FAR *src)
{
  strmov(dst->error.sqlstate,src->error.sqlstate);
  strmov(dst->error.message, src->error.message);
  dst->error.native_error = src->error.native_error;
  dst->error.retcode = src->error.retcode;

  return(SQL_SUCCESS);
}

/*
  @type    : myodbc3 internal
  @purpose : sets the connection level errors, which doesn't need any
       conversion
*/

SQLRETURN set_dbc_error(DBC FAR *dbc,char *state,char *message,uint errcode)
{
  DBUG_ENTER("set_dbc_error");
  DBUG_PRINT("error",("message: %s",message));
  strmov(dbc->error.sqlstate,state);
  strxmov(dbc->error.message,MYODBC3_ERROR_PREFIX,message,NullS);
  dbc->error.native_error=errcode;
  DBUG_RETURN(SQL_ERROR);
}

/*
  @type    : myodbc3 internal
  @purpose : sets the statement level errors, which doesn't need any
       conversion
*/

SQLRETURN set_stmt_error(STMT FAR *stmt,char *state,char *message,uint errcode)
{
  DBUG_ENTER("set_stmt_error");
  DBUG_PRINT("error",("message: %s",message));
  strmov(stmt->error.sqlstate,state);
  strxmov(stmt->error.message,MYODBC3_ERROR_PREFIX,
          "[mysqld-",stmt->dbc->mysql.server_version,"]",
          message,NullS);
  stmt->error.native_error=errcode;
  DBUG_RETURN(SQL_ERROR);
}

/*
  @type    : myodbc3 internal
  @purpose : translates SQL error to ODBC error
*/

void translate_error(char *save_state,char *default_state,uint mysql_err)
{
  char *state=default_state;
  DBUG_ENTER("translate_error");
  switch (mysql_err) {
  case ER_WRONG_VALUE_COUNT:    state= "21S01"; break;
  case ER_DUP_KEY:      state= "23000"; break;
  case ER_PARSE_ERROR:      state= "42000"; break;
  case ER_FILE_NOT_FOUND:
  case ER_CANT_OPEN_FILE:   state= "42S02"; break;
  case ER_CANT_DROP_FIELD_OR_KEY: state= "42S12"; break;
  case ER_DUP_FIELDNAME:    state= "42S21"; break;
  case ER_BAD_FIELD_ERROR:    state= "42S22"; break;
  case CR_SERVER_HANDSHAKE_ERR:
  case CR_CONNECTION_ERROR:   state= "08S01"; break;
  default: break;
  }
  strmov(save_state,state);
  DBUG_VOID_RETURN;
}

/*
  @type    : myodbc3 internal
  @purpose : sets the error information to appropriate handle.
       it also sets the SQLSTATE based on the ODBC VERSION
*/

SQLRETURN
set_handle_error(SQLSMALLINT HandleType, SQLHANDLE handle,
     myodbc_errid errid, SQLCHAR *errtext,
     SQLINTEGER mysql_err)
{
  SQLRETURN  sqlreturn = SQL_ERROR;
  SQLINTEGER my_version;
  MYERROR    *error;
  SQLCHAR    mystate[6];
  SQLCHAR    *errmsg;
  SQLINTEGER native_code;
  SQLCHAR    my_error_prefix[256];

  DBUG_ENTER("set_handle_error");
  DBUG_PRINT("values",("type:%d, handle:%x, errid:%d, err:%s,myerr:%d",
          HandleType,handle,errid,errtext,mysql_err));

  switch (HandleType) {

  case SQL_HANDLE_STMT:
    my_version = ((STMT FAR *) handle)->dbc->env->odbc_ver;
    error      = &((STMT FAR *) handle)->error;

    /*
      If stmt handle, include server version also in the error prefix
      ex: [MySQL][ODBC 3.51 Driver][mysqld-3.23.45-max], this helps
      a lot for users..
    */
    strxmov(my_error_prefix,MYODBC3_ERROR_PREFIX,"[mysqld-",
      ((STMT FAR *)handle)->dbc->mysql.server_version,"]",NullS);
    break;

  case SQL_HANDLE_DBC:
    my_version = ((DBC FAR *)handle)->env->odbc_ver;
    error      = &((DBC FAR *)handle)->error;
    strxmov(my_error_prefix,MYODBC3_ERROR_PREFIX,NullS);
    break;

  default:
    my_version = ((ENV FAR *)handle)->odbc_ver;
    error      = &((ENV FAR *)handle)->error;
    strxmov(my_error_prefix,MYODBC3_ERROR_PREFIX,NullS);
    break;
  }
  errmsg = errtext ? errtext : (SQLCHAR *)myodbc3_errors[errid].message;

  if (my_version == SQL_OV_ODBC2)
    strmov(mystate, myodbc3_errors[errid].sqlstate2);
  else
    strmov(mystate, myodbc3_errors[errid].sqlstate3);

  native_code = mysql_err ? mysql_err : errid + 500;

  DBUG_PRINT("intern-error",("[%d@%s:%s]",native_code,mystate,errmsg));
  sqlreturn = error->retcode = myodbc3_errors[errid].retcode;
  strxmov(error->message, my_error_prefix, errmsg, NullS);
  error->native_error = native_code;
  strmov(error->sqlstate , mystate);

  DBUG_RETURN(sqlreturn);
}

/*
  @type    : myodbc3 internal
  @purpose : returns the current values of multiple fields of a diagnostic
       record that contains error, warning, and status information.
       Unlike SQLGetDiagField, which returns one diagnostic field
       per call, SQLGetDiagRec returns several commonly used fields
       of a diagnostic record, including the SQLSTATE, the native
       error code, and the diagnostic message text
*/

SQLRETURN
my_SQLGetDiagRec(SQLSMALLINT HandleType,
      SQLHANDLE Handle,
      SQLSMALLINT RecNumber,
      SQLCHAR *Sqlstate,
      SQLINTEGER  *NativeErrorPtr,
      SQLCHAR *MessageText,
      SQLSMALLINT BufferLength,
      SQLSMALLINT *TextLengthPtr)
{
  SQLCHAR     *errmsg;
  SQLRETURN   result = SQL_SUCCESS;
  SQLSMALLINT tmp_size;
  SQLCHAR     tmp_state[6];
  SQLINTEGER  tmp_error;
  DBUG_ENTER("SQLGetDiagRec");
  DBUG_PRINT("values",("%d,%x,%d,%x,%x,%x,%d,%x",HandleType,Handle,
           RecNumber,Sqlstate,NativeErrorPtr,MessageText,
           BufferLength,TextLengthPtr));

  if (!TextLengthPtr)
    TextLengthPtr= &tmp_size;

  if (!Sqlstate)
    Sqlstate= tmp_state;

  if (!NativeErrorPtr)
    NativeErrorPtr= &tmp_error;

  if (RecNumber <= 0 || BufferLength < 0 || !Handle)
    DBUG_RETURN(SQL_ERROR);

  /*
    Currently we are not supporting error list, so
    if RecNumber > 1, return no data found
  */

  if (RecNumber > 1)
    DBUG_RETURN(SQL_NO_DATA_FOUND);

  switch(HandleType) {
  case SQL_HANDLE_STMT:
    errmsg=((STMT FAR*) Handle)->error.message;
    strmov((char*) Sqlstate,((STMT FAR*) Handle)->error.sqlstate);
    *NativeErrorPtr=((STMT FAR*) Handle)->error.native_error;
    break;

  case SQL_HANDLE_DBC:
    errmsg=((DBC FAR*) Handle)->error.message;
    strmov((char*) Sqlstate,((DBC FAR*) Handle)->error.sqlstate);
    *NativeErrorPtr=((DBC FAR*) Handle)->error.native_error;

    break;

  case SQL_HANDLE_ENV:
    errmsg=((ENV FAR*) Handle)->error.message;
    strmov((char*) Sqlstate,((ENV FAR*) Handle)->error.sqlstate);
    *NativeErrorPtr=((ENV FAR*) Handle)->error.native_error;
    break;

  default:
    DBUG_RETURN(SQL_INVALID_HANDLE);
  }
  if (!errmsg || !errmsg[0])
  {
    *TextLengthPtr=0;
    strmov(Sqlstate,"00000");
    DBUG_RETURN(SQL_NO_DATA_FOUND);
  }
  DBUG_RETURN(copy_str_data(HandleType,Handle,MessageText,BufferLength,
                            TextLengthPtr, errmsg));
}

/*
  @type    : ODBC 3.0 API
  @purpose : returns the current value of a field of a record of the
       diagnostic data structure (associated with a specified handle)
       that contains error, warning, and status information
*/

SQLRETURN SQL_API
SQLGetDiagField(SQLSMALLINT HandleType,
    SQLHANDLE   Handle,
    SQLSMALLINT RecNumber,
    SQLSMALLINT DiagIdentifier,
    SQLPOINTER  DiagInfoPtr,
    SQLSMALLINT BufferLength,
    SQLSMALLINT *StringLengthPtr)
{
  SQLRETURN   error = SQL_SUCCESS;
  SQLPOINTER  szDiagInfo=NULL;
  SQLSMALLINT tmp_size;
  DBUG_ENTER("SQLGetDiagField");
  DBUG_PRINT("values",("%d,%x,%d,%d,%x,%d,%x",HandleType,Handle,
           RecNumber,DiagIdentifier,DiagInfoPtr,
           BufferLength,StringLengthPtr));

  if (!StringLengthPtr)
    StringLengthPtr= &tmp_size;

  if (!DiagInfoPtr)
    DiagInfoPtr= szDiagInfo;

  if (!Handle ||
      !(HandleType == SQL_HANDLE_STMT ||
        HandleType == SQL_HANDLE_DBC ||
        HandleType == SQL_HANDLE_ENV ))
    DBUG_RETURN(SQL_ERROR);

  if (RecNumber > 1)
    DBUG_RETURN(SQL_NO_DATA_FOUND);

  /* If record number is 0 and if it is not a
     diag header field request, return error
  */
  if (RecNumber == 0 && DiagIdentifier > 0)
    DBUG_RETURN(SQL_ERROR);

  switch(DiagIdentifier ) {

    /* DIAG HEADER FIELDS SECTION */
  case SQL_DIAG_DYNAMIC_FUNCTION:
    if (HandleType != SQL_HANDLE_STMT)
      DBUG_RETURN(SQL_ERROR);

    error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
      StringLengthPtr, "");
    break;

  case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
    *(SQLINTEGER *) DiagInfoPtr = 0;
    break;

  case SQL_DIAG_ROW_NUMBER:
    *(SQLINTEGER *) DiagInfoPtr = SQL_ROW_NUMBER_UNKNOWN;
    break;

  case SQL_DIAG_NUMBER:
    *(SQLINTEGER *) DiagInfoPtr = 1;
    break;

  case SQL_DIAG_RETURNCODE:
    if (HandleType == SQL_HANDLE_STMT)
      *(SQLRETURN *) DiagInfoPtr = ((STMT FAR *)Handle)->error.retcode;

    else if (HandleType == SQL_HANDLE_DBC)
      *(SQLRETURN *) DiagInfoPtr = ((DBC FAR *)Handle)->error.retcode;

    else
      *(SQLRETURN *) DiagInfoPtr = ((ENV FAR *)Handle)->error.retcode;
    break;

  case SQL_DIAG_CURSOR_ROW_COUNT:/* at present, return total rows in rs */
    if (HandleType != SQL_HANDLE_STMT)
      DBUG_RETURN(SQL_ERROR);

    if (!((STMT FAR *)Handle)->result)
      *(SQLINTEGER *) DiagInfoPtr=0;

    else
      *(SQLINTEGER *) DiagInfoPtr = (SQLINTEGER)
  mysql_num_rows(((STMT FAR *) Handle)->result);
    break;

  case SQL_DIAG_ROW_COUNT:
    if (HandleType != SQL_HANDLE_STMT)
      DBUG_RETURN(SQL_ERROR);

    *(SQLINTEGER *) DiagInfoPtr = (SQLINTEGER)
      ((STMT FAR *) Handle)->affected_rows;
    break;

    /* DIAG RECORD FIELDS SECTION */

  case SQL_DIAG_CLASS_ORIGIN:
  case SQL_DIAG_SUBCLASS_ORIGIN:
    error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
      StringLengthPtr, "ISO 9075");
    break;

  case SQL_DIAG_COLUMN_NUMBER:

    *(SQLINTEGER *) DiagInfoPtr = SQL_COLUMN_NUMBER_UNKNOWN;
    break;

  case SQL_DIAG_CONNECTION_NAME:
    /*
      When the connection fails, ODBC DM calls this function, so don't
      return dbc->dsn as the connection name instead return empty string
    */

    if (HandleType == SQL_HANDLE_STMT)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,((STMT FAR *)Handle)->dbc->dsn ?
        ((STMT FAR *)Handle)->dbc->dsn:"");

    else if (HandleType == SQL_HANDLE_DBC)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,((DBC FAR *)Handle)->dsn ?
        ((DBC FAR *)Handle)->dsn:"");

    else
    {
      *(SQLCHAR *) DiagInfoPtr = 0;
      *StringLengthPtr = 0;
    }
    break;

  case SQL_DIAG_MESSAGE_TEXT:
    if (HandleType == SQL_HANDLE_STMT)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,((STMT FAR *)Handle)->error.message);

    else if (HandleType == SQL_HANDLE_DBC)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
                          StringLengthPtr,((DBC FAR *)Handle)->error.message);
    else
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,((ENV FAR *)Handle)->error.message);
    break;

  case SQL_DIAG_NATIVE:
    if (HandleType == SQL_HANDLE_STMT)
      *(SQLINTEGER *) DiagInfoPtr = ((STMT FAR *)Handle)->error.native_error;

    else if (HandleType == SQL_HANDLE_DBC)
      *(SQLINTEGER *) DiagInfoPtr = ((DBC FAR *)Handle)->error.native_error;

    else
      *(SQLINTEGER *) DiagInfoPtr = ((ENV FAR *)Handle)->error.native_error;
    break;

  case SQL_DIAG_SERVER_NAME:
    if (HandleType == SQL_HANDLE_STMT)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,
        ((STMT FAR *)Handle)->dbc->server ?
        ((STMT FAR *)Handle)->dbc->server : "");

    else if (HandleType == SQL_HANDLE_DBC)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,((DBC FAR *)Handle)->server ?
        ((DBC FAR *)Handle)->server : "");
    else
    {
      *(SQLCHAR *) DiagInfoPtr = 0;
      *StringLengthPtr = 0;
    }
    break;

  case SQL_DIAG_SQLSTATE:
    if (HandleType == SQL_HANDLE_STMT)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,
        ((STMT FAR *)Handle)->error.sqlstate);

    else if (HandleType == SQL_HANDLE_DBC)
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,
        ((DBC FAR *)Handle)->error.sqlstate);

    else
      error=copy_str_data(HandleType, Handle, DiagInfoPtr, BufferLength,
        StringLengthPtr,
        ((ENV FAR *)Handle)->error.sqlstate);
    break;

  default:
    DBUG_RETURN(SQL_ERROR);
  }
  DBUG_RETURN(error);
}

/*
  @type    : ODBC 3.0 API
  @purpose : returns the current diagnostic record information
*/

SQLRETURN SQL_API
SQLGetDiagRec(SQLSMALLINT HandleType,
        SQLHANDLE   Handle,
        SQLSMALLINT RecNumber,
        SQLCHAR     *Sqlstate,
        SQLINTEGER  *NativeErrorPtr,
        SQLCHAR     *MessageText,
        SQLSMALLINT BufferLength,
        SQLSMALLINT *TextLengthPtr)
{
  return my_SQLGetDiagRec(HandleType,Handle,RecNumber,Sqlstate,
        NativeErrorPtr,MessageText,
        BufferLength,TextLengthPtr);
}

/*
  @type    : ODBC 1.0 API - depricated
  @purpose : returns error or status information
*/

SQLRETURN SQL_API
SQLError(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt,
         SQLCHAR FAR    *szSqlState,
         SQLINTEGER FAR *pfNativeError,
         SQLCHAR FAR    *szErrorMsg,
         SQLSMALLINT    cbErrorMsgMax,
         SQLSMALLINT FAR *pcbErrorMsg)
{
  SQLRETURN error=SQL_INVALID_HANDLE;
  DBUG_ENTER("SQLError");

  if (hstmt){
    error = my_SQLGetDiagRec(SQL_HANDLE_STMT,hstmt,1,szSqlState,
                             pfNativeError, szErrorMsg,
                             cbErrorMsgMax,pcbErrorMsg);
    if(error == SQL_SUCCESS)
      ((STMT FAR*)hstmt)->error.message[0]='\0';
  }
  else if (hdbc){
    error = my_SQLGetDiagRec(SQL_HANDLE_DBC,hdbc,1,szSqlState,
                             pfNativeError, szErrorMsg,
                             cbErrorMsgMax,pcbErrorMsg);
    if(error == SQL_SUCCESS)
      ((DBC FAR*)hdbc)->error.message[0]='\0';
  }
  else if (henv){
    error = my_SQLGetDiagRec(SQL_HANDLE_ENV,henv,1,szSqlState,
                             pfNativeError, szErrorMsg,
                             cbErrorMsgMax,pcbErrorMsg);
    if(error == SQL_SUCCESS)
      ((ENV FAR*)henv)->error.message[0]='\0';  
  }
  DBUG_RETURN(error);
}

Generated by  Doxygen 1.6.0   Back to index