home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / database / dbfetch / bulkset.cpp next >
C/C++ Source or Header  |  1998-03-26  |  7KB  |  276 lines

  1. // bulkset.cpp : implementation file
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "dbfetch.h"
  15. #include "bulkset.h"
  16.  
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CBulkRecordsetMod
  25.  
  26. IMPLEMENT_DYNAMIC(CBulkRecordsetMod, CRecordset)
  27.  
  28. CBulkRecordsetMod::CBulkRecordsetMod(CDatabase* pdb)
  29.     : CRecordset(pdb)
  30. {
  31.     //{{AFX_FIELD_INIT(CBulkRecordsetMod)
  32.     //}}AFX_FIELD_INIT
  33.     m_nDefaultType = dynaset;
  34. }
  35.  
  36.  
  37. BOOL CBulkRecordsetMod::Open(UINT nOpenType,
  38.     LPCTSTR lpszSQL, DWORD dwOptions)
  39. {
  40.     ASSERT(dwOptions & useMultiRowFetch);
  41.     return CRecordset::Open(nOpenType, lpszSQL, dwOptions);
  42. }
  43.  
  44. BOOL CBulkRecordsetMod::RowsetUpdate(WORD wRow, WORD wLockType)
  45. {
  46.     ASSERT(wRow >= 0 && wRow <= GetRowsetSize());
  47.  
  48.     RETCODE nRetCode;
  49.     AFX_ODBC_CALL(::SQLSetPos(m_hstmt, wRow, SQL_UPDATE, wLockType));
  50.  
  51.     return ValidateMod(wRow, SQL_ROW_UPDATED);
  52. }
  53.  
  54. BOOL CBulkRecordsetMod::RowsetAdd(WORD wRow, WORD wLockType)
  55. {
  56.     // User may allocate an extra row buffer for the Add
  57.     // (if user adds more than 1, must override)
  58.     ASSERT(wRow >= 0 && wRow <= GetRowsetSize() + 1);
  59.  
  60.     RETCODE nRetCode;
  61.     AFX_ODBC_CALL(::SQLSetPos(m_hstmt, wRow, SQL_ADD, wLockType));
  62.  
  63.     return ValidateMod(wRow, SQL_ROW_ADDED);
  64. }
  65.  
  66. BOOL CBulkRecordsetMod::RowsetDelete(WORD wRow, WORD wLockType)
  67. {
  68.     ASSERT(wRow >= 0 && wRow <= GetRowsetSize());
  69.  
  70.     RETCODE nRetCode;
  71.     AFX_ODBC_CALL(::SQLSetPos(m_hstmt, wRow, SQL_DELETE, wLockType));
  72.  
  73.     return ValidateMod(wRow, SQL_ROW_DELETED);
  74. }
  75.  
  76. BOOL CBulkRecordsetMod::ValidateMod(WORD wRow, WORD wExpectedStatus)
  77. {
  78.     BOOL bReturn = TRUE;
  79.  
  80.     if (wRow != 0)
  81.         bReturn = GetRowStatus(wRow) == wExpectedStatus;
  82.     else
  83.     {
  84.         for (WORD wNum = 1; wNum <= GetRowsetSize(); wNum++)
  85.         {
  86.             // If any row status not expected, then validate fails
  87.             if (GetRowStatus(wNum) != wExpectedStatus)
  88.                 bReturn = FALSE;
  89.         }
  90.     }
  91.  
  92.     return bReturn;
  93. }
  94.  
  95. /////////////////////////////////////////////////////////////////////////////
  96. // CDynamicBulkSet
  97.  
  98. IMPLEMENT_DYNAMIC(CDynamicBulkSet, CBulkRecordsetMod)
  99.  
  100. CDynamicBulkSet::CDynamicBulkSet(CDatabase* pdb)
  101.     : CBulkRecordsetMod(pdb)
  102. {
  103.     m_nDefaultType = dynaset;
  104.     m_nAllocatedFields = 0;
  105.  
  106.     m_ppvData = NULL;
  107.     m_ppvLengths = NULL;
  108. }
  109.  
  110. void CDynamicBulkSet::Close()
  111. {
  112.     CRecordset::Close();
  113.  
  114.     delete [] m_ppvData;
  115.     delete [] m_ppvLengths;
  116. }
  117.  
  118. void CDynamicBulkSet::DoBulkFieldExchange(CFieldExchange* pFX)
  119. {
  120.     // Allocate the buffer
  121.     if (pFX->m_nOperation == CFieldExchange::AllocMultiRowBuffer &&
  122.         m_nAllocatedFields == 0)
  123.     {
  124.         // get the field count
  125.         m_ppvData = new void*[GetODBCFieldCount()];
  126.         memset(m_ppvData, 0, sizeof(void*) * GetODBCFieldCount());
  127.         m_ppvLengths = new void*[GetODBCFieldCount()];
  128.         memset(m_ppvLengths, 0, sizeof(void*) * GetODBCFieldCount());
  129.  
  130.         m_nAllocatedFields = GetODBCFieldCount();
  131.         m_nFields = m_nAllocatedFields;
  132.     }
  133.  
  134.     // Should never get to here without field buffer allocation
  135.     ASSERT(m_nAllocatedFields != 0);
  136.  
  137.     pFX->SetFieldType(CFieldExchange::outputColumn);
  138.     for (int nNum = 0; nNum < GetODBCFieldCount(); nNum++)
  139.     {
  140.         RFX_Text_Bulk(pFX, _T("Dummy"), (LPSTR*)&m_ppvData[nNum],
  141.             (long**)&m_ppvLengths[nNum], MAX_TEXT_LEN);
  142.     }
  143. }
  144.  
  145. void CDynamicBulkSet::CheckRowsetError(RETCODE nRetCode)
  146. {
  147.     // Always IGNORE data truncated warnings, as the code
  148.     // purposely truncates text to 40 chars...
  149.  
  150.     if (nRetCode == SQL_SUCCESS_WITH_INFO)
  151.     {
  152.         CDBException e(nRetCode);
  153.         // Build the error string but don't send nuisance output to TRACE window
  154.         e.BuildErrorString(m_pDatabase, m_hstmt, FALSE);
  155.  
  156.         if (e.m_strStateNativeOrigin.Find(_T("State:01004")) >= 0)
  157.         {
  158.             // Do nothing here for this app
  159.         }
  160.         else if (e.m_strStateNativeOrigin.Find(_T("State:01S01")) >= 0)
  161.         {
  162.             e.Empty();
  163.             TRACE0("Error: fetching row from server.\n");
  164.             ThrowDBException(AFX_SQL_ERROR_ROW_FETCH);
  165.         }
  166.         else
  167.         {
  168. #ifdef _DEBUG
  169.             // Not a truncation or row fetch warning so send debug output
  170.             if (afxTraceFlags & traceDatabase)
  171.             {
  172.                 TRACE0("Warning: ODBC Success With Info, ");
  173.                 e.TraceErrorMessage(e.m_strError);
  174.                 e.TraceErrorMessage(e.m_strStateNativeOrigin);
  175.             }
  176. #endif // _DEBUG
  177.         }
  178.     }
  179.     else if (!Check(nRetCode))
  180.         ThrowDBException(nRetCode);
  181. }
  182.  
  183. /////////////////////////////////////////////////////////////////////////////
  184. // CTables - borrowed from Catalog2
  185.  
  186. CTables::CTables(CDatabase* pDatabase)
  187.     : CRecordset(pDatabase)
  188. {
  189.     m_strTableQualifier = _T("");
  190.     m_strTableOwner     = _T("");
  191.     m_strTableName      = _T("");
  192.     m_strTableType      = _T("");
  193.     m_strRemarks        = _T("");
  194.     m_nFields = 5;
  195. }
  196.  
  197. BOOL CTables::Open(LPCSTR pszTableQualifier,
  198.     LPCSTR pszTableOwner,LPCSTR pszTableName,LPCSTR pszTableType,
  199.     UINT nOpenType)
  200. {
  201.     ASSERT(m_pDatabase != NULL);
  202.     ASSERT(m_pDatabase->IsOpen());
  203.  
  204.     RETCODE nRetCode;
  205.     UWORD   bFunctionExists;
  206.  
  207.     // make sure SQLTables exists
  208.     AFX_SQL_SYNC(::SQLGetFunctions(m_pDatabase->m_hdbc,
  209.         SQL_API_SQLTABLES,&bFunctionExists));
  210.     if (!Check(nRetCode) || !bFunctionExists)
  211.     {
  212.         if (!bFunctionExists)
  213.             TRACE(_T("SQLTables not supported\n"));
  214.         return FALSE;
  215.     }
  216.  
  217.     m_nOpenType = nOpenType;
  218.     m_bUpdatable = FALSE;
  219.  
  220.     // make sure hstmt is allocated
  221.     if (m_hstmt == SQL_NULL_HSTMT)
  222.     {
  223.         AFX_SQL_SYNC(::SQLAllocStmt(m_pDatabase->m_hdbc,&m_hstmt));
  224.         if (!Check(nRetCode))
  225.             ThrowDBException(nRetCode,m_hstmt);
  226.     }
  227.  
  228.     OnSetOptions(m_hstmt);
  229.  
  230.     TRY
  231.     {
  232.         // call the ODBC function
  233.         AFX_SQL_ASYNC(this,::SQLTables(m_hstmt,
  234.             (UCHAR FAR*)pszTableQualifier,SQL_NTS,
  235.             (UCHAR FAR*)pszTableOwner,SQL_NTS,
  236.             (UCHAR FAR*)pszTableName,SQL_NTS,
  237.             (UCHAR FAR*)pszTableType,SQL_NTS));
  238.  
  239.         if (!Check(nRetCode))
  240.             ThrowDBException(nRetCode,m_hstmt);
  241.  
  242.         // Allocate memory and cache info
  243.         AllocAndCacheFieldInfo();
  244.         AllocRowset();
  245.  
  246.         // Allocate the field info and status arrays if
  247.         // not done already in BuildSelectSQL
  248.         if ((m_nFields != 0 || m_nParams != 0) &&
  249.             m_rgFieldInfos == NULL)
  250.         {
  251.             AllocStatusArrays();
  252.         }
  253.  
  254.         MoveNext();
  255.     }
  256.  
  257.     CATCH_ALL(e)
  258.     {
  259.         Close();
  260.         THROW_LAST();
  261.     }
  262.     END_CATCH_ALL
  263.  
  264.     return TRUE;
  265. }
  266.  
  267. void CTables::DoFieldExchange(CFieldExchange* pFX)
  268. {
  269.     pFX->SetFieldType(CFieldExchange::outputColumn);
  270.     RFX_Text(pFX,_T("TABLE_QUALIFIER"),m_strTableQualifier);
  271.     RFX_Text(pFX,_T("TABLE_OWNER"),m_strTableOwner);
  272.     RFX_Text(pFX,_T("TABLE_NAME"),m_strTableName);
  273.     RFX_Text(pFX,_T("TABLE_TYPE"),m_strTableType);
  274.     RFX_Text(pFX,_T("REMARKS"),m_strRemarks);
  275. }
  276.