home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / devtools / samples / ODBC / loaddata / odbcerr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-20  |  14.5 KB  |  464 lines

  1. // CODBCErr.cpp -- Error list and error object, used to report errors 
  2. //  returned on connection, statement handling, etc.
  3. //
  4. // Both objects inherit from CObject so that COBList, etc. collections
  5. //  can be used to hold collections of the objects.
  6.  
  7. // This file is part of Microsoft SQL Server online documentation.
  8. // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  9. //
  10. // This source code is an intended supplement to the Microsoft SQL
  11. // Server online references and related electronic documentation.
  12. #include "stdafx.h"
  13. #include "ODBCErr.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20.  
  21. #define STRSQL_SUCCESS              _T("SQL_SUCCESS")
  22. #define STRSQL_SUCCESS_WITH_INFO    _T("SQL_SUCCESS_WITH_INFO")
  23. #define STRSQL_ERROR                _T("SQL_ERROR")
  24. #define STRSQL_INVALID_HANDLE       _T("SQL_INVALID_HANDLE")
  25. #define STRSQL_NO_DATA              _T("SQL_NO_DATA")
  26. #define STRSQL_NEED_DATA            _T("SQL_NEED_DATA")
  27. #define HEADERFMTDBC                _T("SQLReturn: %s\nRecords: %d")
  28. #define HEADERFMTSTMT               _T("SQLReturn: %s\nRecords: %d\nFunction code: %x, Function: %s")
  29. #define LISTNOTINIT                 _T("Error record list not initialized.")
  30. #define BADERRORRECNUM              _T("Invalid error record number requested: %lu.")
  31. #define ERRORNOTINIT                _T("Error encountered on SQLGetError call.")
  32. #define STRODBCBASICS               _T("Datasource %s, Connection: %s\nNative Error: %d,SQLState: %s\nMessage text:\n%s")
  33. #define STRODBCEXT                  _T("Row: %ld, Column: %ld")
  34. #define STRSSBASICS                 _T("SQL Server: %s, SS Severity %d, RAISERROR state: %d")
  35. #define STRSSPROC                   _T("Error on line %d of stored procedure: %s")
  36.  
  37. IMPLEMENT_DYNAMIC(CODBCErr, CObject)
  38.  
  39. /////////////////////////////////////////////////////////////////////////////
  40. // Construct an error record using SQLGetDiagRec and SQLGetDiagField
  41. //  to retrieve values
  42. CODBCErr::CODBCErr
  43.     (
  44.     SQLSMALLINT eHandleType,
  45.     SQLHANDLE hODBC,
  46.     SQLINTEGER nRow
  47.     )
  48.     {
  49.     SQLSMALLINT     cbRet;
  50.  
  51.     ASSERT (eHandleType == SQL_HANDLE_ENV || eHandleType == SQL_HANDLE_DBC
  52.         || eHandleType == SQL_HANDLE_STMT);
  53.     ASSERT (hODBC != SQL_NULL_HANDLE);
  54.     ASSERT ((SQLSMALLINT) nRow > 0);
  55.     
  56.     // Diagnostic record detail defaults
  57.     m_nRow              = -1;
  58.     m_nCol              = -1;
  59.     m_nNativeErr        = -1;
  60.     *m_acOrigin         = (TCHAR) NULL;
  61.     *m_acConnectName    = (TCHAR) NULL;
  62.     *m_acMessage        = (TCHAR) NULL;
  63.     *m_acServer         = (TCHAR) NULL;
  64.     *m_acSQLState       = (TCHAR) NULL;
  65.     *m_acSubclass       = (TCHAR) NULL;
  66.  
  67.     // SQL Server specific record detail defaults
  68.     m_iSProcLine        = -1;
  69.     m_iRaiseErrorState  = -1;
  70.     m_iSeverity         = -1;
  71.     *m_acProcName       = (TCHAR) NULL;
  72.     *m_acSServer        = (TCHAR) NULL;
  73.  
  74.     // ODBC diagnostics record detail
  75.     if (!SQL_SUCCEEDED(SQLGetDiagRec(eHandleType, hODBC, (SQLSMALLINT) nRow,
  76.         (SQLTCHAR*) m_acSQLState, &m_nNativeErr,
  77.         (SQLTCHAR*) m_acMessage, SQL_MAX_MESSAGE_LENGTH + 1, &cbRet)))
  78.         {
  79.         return;
  80.         }
  81.  
  82.     SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  83.         SQL_DIAG_CONNECTION_NAME, (SQLPOINTER) m_acConnectName,
  84.         SQL_MAX_DSN_LENGTH + 1, &cbRet);
  85.     SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  86.         SQL_DIAG_SERVER_NAME, (SQLPOINTER) m_acServer,
  87.         SERVERNAME_MAX + 1, &cbRet);
  88.     SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  89.         SQL_DIAG_CLASS_ORIGIN, (SQLPOINTER) m_acOrigin, SQL_SQLSTATE_SIZE + 1,
  90.         &cbRet);
  91.     SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  92.         SQL_DIAG_SUBCLASS_ORIGIN, (SQLPOINTER) m_acSubclass,
  93.         SQL_SQLSTATE_SIZE + 1, &cbRet);
  94.  
  95.     if (eHandleType == SQL_HANDLE_STMT)
  96.         {
  97.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  98.             SQL_DIAG_COLUMN_NUMBER, (SQLPOINTER) &m_nCol, SQL_IS_INTEGER,
  99.             &cbRet);
  100.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  101.             SQL_DIAG_ROW_NUMBER, (SQLPOINTER) &m_nRow, SQL_IS_INTEGER,
  102.             &cbRet);
  103.  
  104.         // SQL Server diagnostics record detail
  105.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  106.             SQL_DIAG_SS_LINE, (SQLPOINTER) &m_iSProcLine,
  107.             SQL_IS_SMALLINT, &cbRet);
  108.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  109.             SQL_DIAG_SS_MSGSTATE, (SQLPOINTER) &m_iRaiseErrorState,
  110.             SQL_IS_INTEGER, &cbRet);
  111.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  112.             SQL_DIAG_SS_PROCNAME, (SQLPOINTER) m_acProcName,
  113.             SSPROCNAME_MAX, &cbRet);
  114.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  115.             SQL_DIAG_SS_SEVERITY, (SQLPOINTER) &m_iSeverity,
  116.             SQL_IS_INTEGER, &cbRet);
  117.         SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
  118.             SQL_DIAG_SS_SRVNAME, (SQLPOINTER) m_acSServer,
  119.             SERVERNAME_MAX + 1, &cbRet);
  120.         }
  121.     }
  122.  
  123. /////////////////////////////////////////////////////////////////////////////
  124. // Format -- Formats an error. The format is in four parts based on
  125. //  the type of error. The basic components of a SQL Server ODBC error
  126. //  appear in all errors. Basic information includes: the error
  127. //  message, the native error number, the SQL Server-specific severity,
  128. //  etc. If the error occurred while processing parameters or in an
  129. //  array of bound data, then the ODBC row and column number are also
  130. //  returned. If the error originated in a SQL Server stored procedure,
  131. //  then the procedure name and line number are returned as well.
  132. void CODBCErr::Format
  133.     (
  134.     CString& strError
  135.     )
  136.     {
  137.     CString strODBCBasics = _T("");
  138.     CString strODBCExt = _T("");
  139.     CString strSSBasics = _T("");
  140.     CString strSSProc = _T("");
  141.  
  142.     strError = _T("");
  143.  
  144.     if (m_nNativeErr == -1)
  145.         {
  146.         strError = ERRORNOTINIT;
  147.         }
  148.     else
  149.         {
  150.         strODBCBasics.Format(STRODBCBASICS, m_acServer, m_acConnectName,
  151.             m_nNativeErr, m_acSQLState, m_acMessage);
  152.  
  153.         if (_tcslen(m_acSServer))
  154.             {
  155.             strSSBasics.Format(STRSSBASICS, m_acSServer, m_iSeverity,
  156.                 m_iRaiseErrorState);
  157.             }
  158.  
  159.         if (m_nRow != -1)
  160.             {
  161.             strODBCExt.Format(STRODBCEXT, m_nRow, m_nCol);
  162.             }
  163.         if (_tcslen(m_acProcName))
  164.             {
  165.             strSSProc.Format(STRSSPROC, m_iSProcLine, m_acProcName);
  166.             }
  167.         
  168.         strError = strODBCBasics;
  169.         if (strODBCExt.GetLength())
  170.             {
  171.             strError += _T("\n");
  172.             strError += strODBCExt;
  173.             }
  174.         if (strSSBasics.GetLength())
  175.             {
  176.             strError += _T("\n");
  177.             strError += strSSBasics;
  178.             }
  179.         if (strSSProc.GetLength())
  180.             {
  181.             strError += _T("\n");
  182.             strError += strSSProc;
  183.             }
  184.         }
  185.     }
  186.  
  187. /////////////////////////////////////////////////////////////////////////////
  188. // One and only destructor
  189. CODBCErr::~CODBCErr()
  190.     {
  191.     }
  192.  
  193. #ifdef _DEBUG
  194. // Dump the important parts of a column object
  195. void CODBCErr::Dump(CDumpContext& dc) const
  196.     {
  197.     // call the base object
  198.     CObject::Dump(dc);
  199.     }
  200.  
  201. void CODBCErr::AssertValid() const
  202.     {
  203.     }
  204. #endif
  205.  
  206. IMPLEMENT_DYNAMIC(CODBCErrList, CObject)
  207.  
  208. /////////////////////////////////////////////////////////////////////////////
  209. // Construction -- set defaults
  210. CODBCErrList::CODBCErrList()
  211.     {
  212.     // Set defaults
  213.     m_nErrors       = 0;
  214.     m_hODBC         = SQL_NULL_HANDLE;
  215.  
  216.     // Diagnostic header data
  217.     *m_acDynFunc    = (TCHAR) NULL;
  218.     m_iDynFunc      = -1;
  219.     m_sRet          = INVALID_OBJECT;
  220.     }
  221.  
  222. /////////////////////////////////////////////////////////////////////////////
  223. // Construct from an existing error
  224. CODBCErrList::CODBCErrList
  225.     (
  226.     SQLSMALLINT eHandleType,
  227.     SQLHANDLE hODBC
  228.     )
  229.     {
  230.     ASSERT(eHandleType == SQL_HANDLE_DBC || eHandleType == SQL_HANDLE_STMT ||
  231.         eHandleType == SQL_HANDLE_ENV);
  232.  
  233.     // Set defaults
  234.     m_nErrors       = 0;
  235.     m_hODBC         = SQL_NULL_HANDLE;
  236.  
  237.     // Diagnostic header data
  238.     *m_acDynFunc    = (TCHAR) NULL;
  239.     m_iDynFunc      = -1;
  240.     m_sRet          = INVALID_OBJECT;
  241.     
  242.     this->Load(eHandleType, hODBC);
  243.     }
  244.  
  245. /////////////////////////////////////////////////////////////////////////////
  246. // Load -- Get errors for the handle type and return the number of errors.
  247. UINT CODBCErrList::Load
  248.     (
  249.     SQLSMALLINT eHandleType,
  250.     SQLHANDLE hODBC
  251.     )
  252.     {
  253.     ASSERT (eHandleType == SQL_HANDLE_ENV || eHandleType == SQL_HANDLE_DBC
  254.         || eHandleType == SQL_HANDLE_STMT);
  255.     ASSERT (hODBC != SQL_NULL_HANDLE);
  256.  
  257.     CODBCErr*   pODBCErr;
  258.     SQLINTEGER  nErr;
  259.     SQLRETURN   sRet;
  260.     SQLSMALLINT cbRet;
  261.  
  262.     if (m_nErrors)
  263.         {
  264.         for (nErr = 0; nErr < m_nErrors; nErr++)
  265.             {
  266.             pODBCErr =
  267.                 (CODBCErr*) (m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr)));
  268.             delete pODBCErr;
  269.             }
  270.         m_listErrors.RemoveAll();
  271.         }
  272.     
  273.     m_nErrors = 0;
  274.  
  275.     // Get the number of errors from the header record. We'll get the header
  276.     //  later anyway.
  277.     sRet = SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_NUMBER,
  278.         (SQLPOINTER) &m_nErrors, SQL_IS_INTEGER, &cbRet);
  279.     if (sRet == SQL_INVALID_HANDLE || sRet == SQL_ERROR)
  280.         {
  281.         m_hODBC = SQL_NULL_HANDLE;
  282.         return (0);
  283.         }
  284.  
  285.     // Get header data.
  286.     SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_RETURNCODE,
  287.         (SQLPOINTER) &m_sRet, SQL_IS_SMALLINT, &cbRet);
  288.     
  289.     // Diagnostic code and text only available to statement handles.
  290.     if (eHandleType == SQL_HANDLE_STMT)
  291.         {
  292.         SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE,
  293.             (SQLPOINTER) &m_iDynFunc, SQL_IS_INTEGER, &cbRet);
  294.         SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE,
  295.             (SQLPOINTER) m_acDynFunc, DYNFUNC_MAX + 1, &cbRet);
  296.         }
  297.     else
  298.         {
  299.         *m_acDynFunc = (TCHAR) NULL;
  300.         m_iDynFunc = -1;
  301.         }
  302.  
  303.     for (nErr = 0; nErr < m_nErrors; nErr++)
  304.         {
  305.         pODBCErr = new CODBCErr(eHandleType, hODBC, (UINT) nErr + 1);
  306.         m_listErrors.AddTail(pODBCErr);
  307.         }
  308.  
  309.     return ((UINT) m_nErrors);
  310.     }
  311.  
  312. /////////////////////////////////////////////////////////////////////////////
  313. // FormatHeader -- Set the value of the string received to a formatted 
  314. //  representation of the header data.
  315. void CODBCErrList::FormatHeader
  316.     (
  317.     CString& strHeader
  318.     )
  319.     {
  320.     PTSTR       szRetCode;
  321.  
  322.     strHeader = _T("");
  323.  
  324.     if (m_sRet == INVALID_OBJECT)
  325.         {
  326.         strHeader = LISTNOTINIT;
  327.         }
  328.     else
  329.         {
  330.         switch (m_sRet)
  331.             {
  332.             case (SQL_SUCCESS):
  333.                 {
  334.                 szRetCode = STRSQL_SUCCESS;
  335.                 break;
  336.                 }
  337.             case (SQL_SUCCESS_WITH_INFO):
  338.                 {
  339.                 szRetCode = STRSQL_SUCCESS_WITH_INFO;
  340.                 break;
  341.                 }
  342.             case (SQL_INVALID_HANDLE):
  343.                 {
  344.                 szRetCode = STRSQL_INVALID_HANDLE;
  345.                 break;
  346.                 }
  347.             case (SQL_NO_DATA):
  348.                 {
  349.                 szRetCode = STRSQL_NO_DATA;
  350.                 break;
  351.                 }
  352.             case (SQL_NEED_DATA):
  353.                 {
  354.                 szRetCode = STRSQL_NEED_DATA;
  355.                 break;
  356.                 }
  357.  
  358.             default:
  359.                 {
  360.                 szRetCode = STRSQL_ERROR;
  361.                 }
  362.             }
  363.  
  364.         if (m_eHandleType == SQL_HANDLE_STMT)
  365.             {
  366.             strHeader.Format(HEADERFMTSTMT, szRetCode, m_nErrors,
  367.                 m_iDynFunc, m_acDynFunc);
  368.             }
  369.         else
  370.             {
  371.             strHeader.Format(HEADERFMTDBC, szRetCode, m_nErrors);
  372.             }
  373.         }
  374.     }
  375.  
  376. /////////////////////////////////////////////////////////////////////////////
  377. // FormatErr -- Use the error object's Format member function to set the
  378. //  string value for the number of the error received.
  379. void CODBCErrList::FormatErr
  380.     (
  381.     CString& strError,
  382.     UINT nErr = 1
  383.     )
  384.     {
  385.     if ((SQLINTEGER) nErr <= m_nErrors)
  386.         {
  387.         ((CODBCErr*) 
  388.             m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr-1)))->Format(strError);
  389.         }
  390.     else
  391.         {
  392.         strError.Format(BADERRORRECNUM, nErr);
  393.         }
  394.     }
  395.  
  396. /////////////////////////////////////////////////////////////////////////////
  397. // Log -- Write the header and any errors to the file received. Log creates
  398. //  a new file if needed, appends to an existing file.
  399. void CODBCErrList::Log
  400.     (
  401.     LPCTSTR szLogFile
  402.     )
  403.     {
  404.     CString str;
  405.     UINT    nErr;
  406.     DWORD   cbWritten;
  407.     HANDLE  hFile = CreateFile(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  408.         FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  409.  
  410.     if (hFile == INVALID_HANDLE_VALUE)
  411.         {
  412.         return;
  413.         }
  414.     
  415.     SetFilePointer(hFile, 0, NULL, FILE_END);
  416.  
  417.     FormatHeader(str);
  418.     str += _T("\n");
  419.     WriteFile(hFile, (LPCTSTR) str, str.GetLength(), &cbWritten, NULL);
  420.  
  421.     for (nErr = 0; nErr < (UINT) m_nErrors; nErr++)
  422.         {
  423.         FormatErr(str, nErr + 1);
  424.         str += _T("\n");
  425.         WriteFile(hFile, (LPCTSTR) str, str.GetLength(), &cbWritten, NULL);
  426.         }
  427.  
  428.     CloseHandle(hFile);
  429.     }
  430.  
  431. /////////////////////////////////////////////////////////////////////////////
  432. // One and only destructor.
  433. CODBCErrList::~CODBCErrList()
  434.     {
  435.     SQLINTEGER  nErr;
  436.     CODBCErr*   pODBCErr;
  437.  
  438.     if (m_nErrors)
  439.         {
  440.         for (nErr = 0; nErr < m_nErrors; nErr++)
  441.             {
  442.             pODBCErr =
  443.                 (CODBCErr*) (m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr)));
  444.             delete pODBCErr;
  445.             }
  446.         m_listErrors.RemoveAll();
  447.         }
  448.     }
  449.  
  450. #ifdef _DEBUG
  451. // Dump the important parts of a column object
  452. void CODBCErrList::Dump(CDumpContext& dc) const
  453.     {
  454.     // call the base object
  455.     CObject::Dump(dc);
  456.     }
  457.  
  458. // ASSERT that the first call to SQLGetDiagField succeeded
  459. void CODBCErrList::AssertValid() const
  460.     {
  461.     ASSERT(m_sRet != INVALID_OBJECT);
  462.     }
  463. #endif
  464.