home *** CD-ROM | disk | FTP | other *** search
- // CODBCErr.cpp -- Error list and error object, used to report errors
- // returned on connection, statement handling, etc.
- //
- // Both objects inherit from CObject so that COBList, etc. collections
- // can be used to hold collections of the objects.
-
- // This file is part of Microsoft SQL Server online documentation.
- // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
- //
- // This source code is an intended supplement to the Microsoft SQL
- // Server online references and related electronic documentation.
- #include "stdafx.h"
- #include "ODBCErr.h"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #define STRSQL_SUCCESS _T("SQL_SUCCESS")
- #define STRSQL_SUCCESS_WITH_INFO _T("SQL_SUCCESS_WITH_INFO")
- #define STRSQL_ERROR _T("SQL_ERROR")
- #define STRSQL_INVALID_HANDLE _T("SQL_INVALID_HANDLE")
- #define STRSQL_NO_DATA _T("SQL_NO_DATA")
- #define STRSQL_NEED_DATA _T("SQL_NEED_DATA")
- #define HEADERFMTDBC _T("SQLReturn: %s\nRecords: %d")
- #define HEADERFMTSTMT _T("SQLReturn: %s\nRecords: %d\nFunction code: %x, Function: %s")
- #define LISTNOTINIT _T("Error record list not initialized.")
- #define BADERRORRECNUM _T("Invalid error record number requested: %lu.")
- #define ERRORNOTINIT _T("Error encountered on SQLGetError call.")
- #define STRODBCBASICS _T("Datasource %s, Connection: %s\nNative Error: %d,SQLState: %s\nMessage text:\n%s")
- #define STRODBCEXT _T("Row: %ld, Column: %ld")
- #define STRSSBASICS _T("SQL Server: %s, SS Severity %d, RAISERROR state: %d")
- #define STRSSPROC _T("Error on line %d of stored procedure: %s")
-
- IMPLEMENT_DYNAMIC(CODBCErr, CObject)
-
- /////////////////////////////////////////////////////////////////////////////
- // Construct an error record using SQLGetDiagRec and SQLGetDiagField
- // to retrieve values
- CODBCErr::CODBCErr
- (
- SQLSMALLINT eHandleType,
- SQLHANDLE hODBC,
- SQLINTEGER nRow
- )
- {
- SQLSMALLINT cbRet;
-
- ASSERT (eHandleType == SQL_HANDLE_ENV || eHandleType == SQL_HANDLE_DBC
- || eHandleType == SQL_HANDLE_STMT);
- ASSERT (hODBC != SQL_NULL_HANDLE);
- ASSERT ((SQLSMALLINT) nRow > 0);
-
- // Diagnostic record detail defaults
- m_nRow = -1;
- m_nCol = -1;
- m_nNativeErr = -1;
- *m_acOrigin = (TCHAR) NULL;
- *m_acConnectName = (TCHAR) NULL;
- *m_acMessage = (TCHAR) NULL;
- *m_acServer = (TCHAR) NULL;
- *m_acSQLState = (TCHAR) NULL;
- *m_acSubclass = (TCHAR) NULL;
-
- // SQL Server specific record detail defaults
- m_iSProcLine = -1;
- m_iRaiseErrorState = -1;
- m_iSeverity = -1;
- *m_acProcName = (TCHAR) NULL;
- *m_acSServer = (TCHAR) NULL;
-
- // ODBC diagnostics record detail
- if (!SQL_SUCCEEDED(SQLGetDiagRec(eHandleType, hODBC, (SQLSMALLINT) nRow,
- (SQLTCHAR*) m_acSQLState, &m_nNativeErr,
- (SQLTCHAR*) m_acMessage, SQL_MAX_MESSAGE_LENGTH + 1, &cbRet)))
- {
- return;
- }
-
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_CONNECTION_NAME, (SQLPOINTER) m_acConnectName,
- SQL_MAX_DSN_LENGTH + 1, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SERVER_NAME, (SQLPOINTER) m_acServer,
- SERVERNAME_MAX + 1, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_CLASS_ORIGIN, (SQLPOINTER) m_acOrigin, SQL_SQLSTATE_SIZE + 1,
- &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SUBCLASS_ORIGIN, (SQLPOINTER) m_acSubclass,
- SQL_SQLSTATE_SIZE + 1, &cbRet);
-
- if (eHandleType == SQL_HANDLE_STMT)
- {
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_COLUMN_NUMBER, (SQLPOINTER) &m_nCol, SQL_IS_INTEGER,
- &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_ROW_NUMBER, (SQLPOINTER) &m_nRow, SQL_IS_INTEGER,
- &cbRet);
-
- // SQL Server diagnostics record detail
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SS_LINE, (SQLPOINTER) &m_iSProcLine,
- SQL_IS_SMALLINT, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SS_MSGSTATE, (SQLPOINTER) &m_iRaiseErrorState,
- SQL_IS_INTEGER, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SS_PROCNAME, (SQLPOINTER) m_acProcName,
- SSPROCNAME_MAX, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SS_SEVERITY, (SQLPOINTER) &m_iSeverity,
- SQL_IS_INTEGER, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, (SQLSMALLINT) nRow,
- SQL_DIAG_SS_SRVNAME, (SQLPOINTER) m_acSServer,
- SERVERNAME_MAX + 1, &cbRet);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Format -- Formats an error. The format is in four parts based on
- // the type of error. The basic components of a SQL Server ODBC error
- // appear in all errors. Basic information includes: the error
- // message, the native error number, the SQL Server-specific severity,
- // etc. If the error occurred while processing parameters or in an
- // array of bound data, then the ODBC row and column number are also
- // returned. If the error originated in a SQL Server stored procedure,
- // then the procedure name and line number are returned as well.
- void CODBCErr::Format
- (
- CString& strError
- )
- {
- CString strODBCBasics = _T("");
- CString strODBCExt = _T("");
- CString strSSBasics = _T("");
- CString strSSProc = _T("");
-
- strError = _T("");
-
- if (m_nNativeErr == -1)
- {
- strError = ERRORNOTINIT;
- }
- else
- {
- strODBCBasics.Format(STRODBCBASICS, m_acServer, m_acConnectName,
- m_nNativeErr, m_acSQLState, m_acMessage);
-
- if (_tcslen(m_acSServer))
- {
- strSSBasics.Format(STRSSBASICS, m_acSServer, m_iSeverity,
- m_iRaiseErrorState);
- }
-
- if (m_nRow != -1)
- {
- strODBCExt.Format(STRODBCEXT, m_nRow, m_nCol);
- }
- if (_tcslen(m_acProcName))
- {
- strSSProc.Format(STRSSPROC, m_iSProcLine, m_acProcName);
- }
-
- strError = strODBCBasics;
- if (strODBCExt.GetLength())
- {
- strError += _T("\n");
- strError += strODBCExt;
- }
- if (strSSBasics.GetLength())
- {
- strError += _T("\n");
- strError += strSSBasics;
- }
- if (strSSProc.GetLength())
- {
- strError += _T("\n");
- strError += strSSProc;
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // One and only destructor
- CODBCErr::~CODBCErr()
- {
- }
-
- #ifdef _DEBUG
- // Dump the important parts of a column object
- void CODBCErr::Dump(CDumpContext& dc) const
- {
- // call the base object
- CObject::Dump(dc);
- }
-
- void CODBCErr::AssertValid() const
- {
- }
- #endif
-
- IMPLEMENT_DYNAMIC(CODBCErrList, CObject)
-
- /////////////////////////////////////////////////////////////////////////////
- // Construction -- set defaults
- CODBCErrList::CODBCErrList()
- {
- // Set defaults
- m_nErrors = 0;
- m_hODBC = SQL_NULL_HANDLE;
-
- // Diagnostic header data
- *m_acDynFunc = (TCHAR) NULL;
- m_iDynFunc = -1;
- m_sRet = INVALID_OBJECT;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Construct from an existing error
- CODBCErrList::CODBCErrList
- (
- SQLSMALLINT eHandleType,
- SQLHANDLE hODBC
- )
- {
- ASSERT(eHandleType == SQL_HANDLE_DBC || eHandleType == SQL_HANDLE_STMT ||
- eHandleType == SQL_HANDLE_ENV);
-
- // Set defaults
- m_nErrors = 0;
- m_hODBC = SQL_NULL_HANDLE;
-
- // Diagnostic header data
- *m_acDynFunc = (TCHAR) NULL;
- m_iDynFunc = -1;
- m_sRet = INVALID_OBJECT;
-
- this->Load(eHandleType, hODBC);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Load -- Get errors for the handle type and return the number of errors.
- UINT CODBCErrList::Load
- (
- SQLSMALLINT eHandleType,
- SQLHANDLE hODBC
- )
- {
- ASSERT (eHandleType == SQL_HANDLE_ENV || eHandleType == SQL_HANDLE_DBC
- || eHandleType == SQL_HANDLE_STMT);
- ASSERT (hODBC != SQL_NULL_HANDLE);
-
- CODBCErr* pODBCErr;
- SQLINTEGER nErr;
- SQLRETURN sRet;
- SQLSMALLINT cbRet;
-
- if (m_nErrors)
- {
- for (nErr = 0; nErr < m_nErrors; nErr++)
- {
- pODBCErr =
- (CODBCErr*) (m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr)));
- delete pODBCErr;
- }
- m_listErrors.RemoveAll();
- }
-
- m_nErrors = 0;
-
- // Get the number of errors from the header record. We'll get the header
- // later anyway.
- sRet = SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_NUMBER,
- (SQLPOINTER) &m_nErrors, SQL_IS_INTEGER, &cbRet);
- if (sRet == SQL_INVALID_HANDLE || sRet == SQL_ERROR)
- {
- m_hODBC = SQL_NULL_HANDLE;
- return (0);
- }
-
- // Get header data.
- SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_RETURNCODE,
- (SQLPOINTER) &m_sRet, SQL_IS_SMALLINT, &cbRet);
-
- // Diagnostic code and text only available to statement handles.
- if (eHandleType == SQL_HANDLE_STMT)
- {
- SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE,
- (SQLPOINTER) &m_iDynFunc, SQL_IS_INTEGER, &cbRet);
- SQLGetDiagField(eHandleType, hODBC, 0, SQL_DIAG_DYNAMIC_FUNCTION_CODE,
- (SQLPOINTER) m_acDynFunc, DYNFUNC_MAX + 1, &cbRet);
- }
- else
- {
- *m_acDynFunc = (TCHAR) NULL;
- m_iDynFunc = -1;
- }
-
- for (nErr = 0; nErr < m_nErrors; nErr++)
- {
- pODBCErr = new CODBCErr(eHandleType, hODBC, (UINT) nErr + 1);
- m_listErrors.AddTail(pODBCErr);
- }
-
- return ((UINT) m_nErrors);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // FormatHeader -- Set the value of the string received to a formatted
- // representation of the header data.
- void CODBCErrList::FormatHeader
- (
- CString& strHeader
- )
- {
- PTSTR szRetCode;
-
- strHeader = _T("");
-
- if (m_sRet == INVALID_OBJECT)
- {
- strHeader = LISTNOTINIT;
- }
- else
- {
- switch (m_sRet)
- {
- case (SQL_SUCCESS):
- {
- szRetCode = STRSQL_SUCCESS;
- break;
- }
- case (SQL_SUCCESS_WITH_INFO):
- {
- szRetCode = STRSQL_SUCCESS_WITH_INFO;
- break;
- }
- case (SQL_INVALID_HANDLE):
- {
- szRetCode = STRSQL_INVALID_HANDLE;
- break;
- }
- case (SQL_NO_DATA):
- {
- szRetCode = STRSQL_NO_DATA;
- break;
- }
- case (SQL_NEED_DATA):
- {
- szRetCode = STRSQL_NEED_DATA;
- break;
- }
-
- default:
- {
- szRetCode = STRSQL_ERROR;
- }
- }
-
- if (m_eHandleType == SQL_HANDLE_STMT)
- {
- strHeader.Format(HEADERFMTSTMT, szRetCode, m_nErrors,
- m_iDynFunc, m_acDynFunc);
- }
- else
- {
- strHeader.Format(HEADERFMTDBC, szRetCode, m_nErrors);
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // FormatErr -- Use the error object's Format member function to set the
- // string value for the number of the error received.
- void CODBCErrList::FormatErr
- (
- CString& strError,
- UINT nErr = 1
- )
- {
- if ((SQLINTEGER) nErr <= m_nErrors)
- {
- ((CODBCErr*)
- m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr-1)))->Format(strError);
- }
- else
- {
- strError.Format(BADERRORRECNUM, nErr);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Log -- Write the header and any errors to the file received. Log creates
- // a new file if needed, appends to an existing file.
- void CODBCErrList::Log
- (
- LPCTSTR szLogFile
- )
- {
- CString str;
- UINT nErr;
- DWORD cbWritten;
- HANDLE hFile = CreateFile(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- return;
- }
-
- SetFilePointer(hFile, 0, NULL, FILE_END);
-
- FormatHeader(str);
- str += _T("\n");
- WriteFile(hFile, (LPCTSTR) str, str.GetLength(), &cbWritten, NULL);
-
- for (nErr = 0; nErr < (UINT) m_nErrors; nErr++)
- {
- FormatErr(str, nErr + 1);
- str += _T("\n");
- WriteFile(hFile, (LPCTSTR) str, str.GetLength(), &cbWritten, NULL);
- }
-
- CloseHandle(hFile);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // One and only destructor.
- CODBCErrList::~CODBCErrList()
- {
- SQLINTEGER nErr;
- CODBCErr* pODBCErr;
-
- if (m_nErrors)
- {
- for (nErr = 0; nErr < m_nErrors; nErr++)
- {
- pODBCErr =
- (CODBCErr*) (m_listErrors.GetAt(m_listErrors.FindIndex((int) nErr)));
- delete pODBCErr;
- }
- m_listErrors.RemoveAll();
- }
- }
-
- #ifdef _DEBUG
- // Dump the important parts of a column object
- void CODBCErrList::Dump(CDumpContext& dc) const
- {
- // call the base object
- CObject::Dump(dc);
- }
-
- // ASSERT that the first call to SQLGetDiagField succeeded
- void CODBCErrList::AssertValid() const
- {
- ASSERT(m_sRet != INVALID_OBJECT);
- }
- #endif
-