/*
    dberror.cpp

    Copyright (c) 1995, by picoSoft
    ALL RIGHTS RESERVED.

    Revision History:
    -----------------
*/

# include "dberror.h"
static char rcsid[] = "$Id: dberror.cpp 5.1 2001/03/14 11:28:29 picoSoft Exp $";
static char rcsidh[] = dberror_h;

extern "C" {
# ifdef MSDOS
# define strcpy lstrcpy
# define strncpy lstrcpyn
# define strlen lstrlen
# else
# include <string.h>
# endif
};
# include "environ.h"
# include "database.h"
# include "sqlpars.h"
static ErrDesc Errors[] = {
// Codice errore       Messaggio standard                    Odbc2   Odbc3
{E_UNKNOWN_ERROR,     "Unknown error",                       "IM000","IM000"},
{E_WARNING_000,       "Success with warning" ,               "01000","01000"},
{E_WARNING_004,       "Data truncated column" ,              "01004","01004"},
{E_WARNING_S02,       "Option value changed"  ,              "01S02","01S02"},
{E_DYN_SQL_002,       "Count field incorrect"  ,             "07002","07002"},
{E_DYN_SQL_009,       "Invalid descriptor index",            "S1002","07009"},
{E_CONN_EXCEPT_001,   "Unable to establish connection",      "08001","08001"},
{E_DATA_EXCEPT_003,   "Numeric value out of range"  ,        "08003","08003"},
{E_DATA_EXCEPT_018,   "Error in assignment",                 "08005","08018"},
{E_CARD_VIOL_000,     "Cardinality violation",               "21000","21000"},
{E_CARD_VIOL_S01,     "Insert value list does not macth column list",
                                                             "21S01","21S01"},
{E_INTEGRITY_VIOL_000,"Integrity constraint violation",      "23000","23000"},
{E_SYNTAX_ERROR_000,  "Syntax error",                        "37000","42000"},
{E_SYNTAX_ERROR_S01,  "Base table or view already exists",   "S0001","42S01"},
{E_SYNTAX_ERROR_S02,  "Base table or view not found",        "S0002","42S02"},
{E_SYNTAX_ERROR_S22,  "Column not found",                    "S0022","42S22"},
{E_GENERAL_ERROR_000, "General error"                        "S1000","HY000"}, 
{E_GENERAL_ERROR_001, "Memory allocation error",             "S1001","HY001"},
{E_GENERAL_ERROR_003, "Invalid application buffer type",     "S1003","HY003"},
{E_GENERAL_ERROR_007, "Associated statement is not prepared","S1010","HY007"},
{E_GENERAL_ERROR_010, "Function sequence error",             "S1010","HY010"},
{E_GENERAL_ERROR_011, "Attribute cannot be set now",         "S1011","HY011"},
{E_GENERAL_ERROR_024, "Invalid attribute value"              "ODBC3","HY024"},
{E_GENERAL_ERROR_090, "Invalid string or buffer length",     "S1090","HY090"},
{E_GENERAL_ERROR_091, "Invalid descriptor field identifier", "S1091","HY091"},
{E_GENERAL_ERROR_092, "Invalid attribute/option identifier", "S1092","HY092"},
{E_GENERAL_ERROR_096, "Invalid information type",            "S1096","HY096"},
{E_GENERAL_ERROR_100, "Uniqueness option type out of range", "S1100","HY100"},
{E_GENERAL_ERROR_101, "Accuracy option type out of range",   "S1101","HY101"},
{E_GENERAL_ERROR_106, "Fetch type out of range",             "S1106","HY106"}, 
{E_GENERAL_ERROR_110, "Invalid driver completion",           "S1110","HY110"},
{E_GENERAL_ERROR_C00, "Optional feature not implemented",    "S1C00","HYC00"},
{E_INTERNAL_ERROR_001,"Driver doesn't support this function","IM001","IM001"},
{E_INTERNAL_ERROR_002,"Data source name not found and no default driver specified",
                                                             "IM002","IM002"},
{E_INTERNAL_ERROR_007,"No data source or driver specified",  "IM007","IM007"}
};
PCLASSID(DBError);
static DBErrorList Errs;

DBError::DBError (Environment * hv, DataBase * hd, SqlParser *sp, ErrNum err,
                  const PString &desc, long sErr)
{
   Environment *myEnv;
   int i;

   henv = hv;
   hdbc = hd;
   hstmt = sp;
   systemErr = sErr;
   error = 0;
   for (i = 0; i < sizeof(Errors) / sizeof(Errors[0]); i++)
      if (err == Errors[i].num) {
         error = &Errors[i];
         break;
      }
   if (error == 0)
      error = &Errors[0];
   mess = error->stdDesc;
   if (desc.size() > 0) {
      mess += ": ";
      mess += desc;
   }
   if (systemErr != 0)
      mess += " (errno =" + ToPString (systemErr) + ")";
   if (hv)
      myEnv = hv;
   else if (hd)
      myEnv = hd->getEnvironment();
   else if (sp)
      myEnv = sp->GetDB()->getEnvironment();
   else
      myEnv = 0;
   if (myEnv && myEnv->getVersion() == SQL_OV_ODBC2)
      sqlstate = error->Odbc2SqlState;
   else
      sqlstate = error->Odbc3SqlState;
}

void
PrintError (Environment * hv, DataBase * hd, SqlParser *sp, ErrNum num,
            const PString & submess, int syserr)
{
   Errs.AddItem (new DBError ( hv, hd, sp, num, submess, syserr));
}

RETCODE
GetError (Environment *hv, DataBase * hd, SqlParser *sp,
          char * outSqlState, long & outNativeError,
          char * outErrorMsg, int cbErrorMsgMax,
          short & pcbErrorMsg)
{
   DBError *db;
   RETCODE Return = SQL_NO_DATA_FOUND;

   PString mess = "[picoSoft][picoSQL]";
   if (outSqlState != 0)
      strcpy(outSqlState, "00000");
   if (&outNativeError != 0)
      outNativeError = 0;
   if (outErrorMsg != 0)
      outErrorMsg[0] = 0;
   if (&pcbErrorMsg != 0)
      pcbErrorMsg = 0;

   if (sp != SQL_NULL_HSTMT) {
      hv = (Environment *) SQL_NULL_HENV;
      hd = (DataBase *) SQL_NULL_HDBC;
   } else if (hd != SQL_NULL_HDBC)
      hv = (Environment *) SQL_NULL_HENV;
   for (db = Errs.GetLast(); db != 0; db = Errs.GetPrevious())
      if ((hv == SQL_NULL_HENV || db->henv == hv) &&
          (hd == SQL_NULL_HDBC || db->hdbc == hd) &&
          (sp == SQL_NULL_HSTMT|| db->hstmt== sp)) {
        Return = SQL_SUCCESS;
        if (outSqlState != 0)
           strcpy(outSqlState, db->getState ());
        if (&outNativeError != 0)
           outNativeError = db->GetNative();
        if (outErrorMsg != 0) {
           mess += db->getMess();
           if (mess.size() < cbErrorMsgMax) {
              strcpy(outErrorMsg, mess.gets());
              if (&pcbErrorMsg != 0)
                 pcbErrorMsg = (short) mess.size();
           } else {
              strncpy(outErrorMsg, mess.gets(), cbErrorMsgMax - 1); 
              outErrorMsg[cbErrorMsgMax - 1] = 0;
              if (&pcbErrorMsg != 0)
                 pcbErrorMsg = cbErrorMsgMax - 1;
           }
        }
        delete(db);
        Errs.DeleteCurrent();
        break;
      }
   return Return;     
}

void
DelError (Environment * hv, DataBase * hd, SqlParser *sp)
{
   DBError *db;

   if (sp != SQL_NULL_HSTMT) {
      hv = (Environment *) SQL_NULL_HENV;
      hd = (DataBase *) SQL_NULL_HDBC;
   } else if (hd != SQL_NULL_HDBC)
      hv = (Environment *) SQL_NULL_HENV;
   for (db = Errs.GetFirst(); db != 0;)
      if ((hv == SQL_NULL_HENV || db->henv == hv) &&
          (hd == SQL_NULL_HDBC || db->hdbc == hd) &&
          (sp == SQL_NULL_HSTMT|| db->hstmt== sp)) {
        delete(db);
        db = Errs.DeleteCurrent(); 
      }
      else
         db = Errs.GetNext();
}

RETCODE
LookError (Environment * hv, DataBase * hd, SqlParser *sp)
{
   DBError *db;
   RETCODE Return = SQL_SUCCESS;

   if (sp != SQL_NULL_HSTMT) {
      hv = (Environment *) SQL_NULL_HENV;
      hd = (DataBase *) SQL_NULL_HDBC;
   } else if (hd != SQL_NULL_HDBC)
      hv = (Environment *) SQL_NULL_HENV;
   for (db = Errs.GetFirst(); db != 0; db = Errs.GetNext())
      if ((hv == SQL_NULL_HENV || db->henv == hv) &&
          (hd == SQL_NULL_HDBC || db->hdbc == hd) &&
          (sp == SQL_NULL_HSTMT|| db->hstmt== sp)) {
         if (db->isWarning() && Return != SQL_ERROR)
            Return = SQL_SUCCESS_WITH_INFO;
         else {
            Return = SQL_ERROR;
            break;
         }
      }
   return Return;
}

void
MoveStmtError (SqlParser *dst, SqlParser *src)
{
   DBError *db;

   for (db = Errs.GetFirst(); db != 0; db = Errs.GetNext())
      if (db->hstmt == src)
         db->hstmt = dst;
}
