⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbcore.cpp

📁 c语言编程软件vc6.0中文绿色版_vc6.0官方下载
💻 CPP
📖 第 1 页 / 共 5 页
字号:

	// BeginTrans must be called first
#ifdef _DEBUG
	ASSERT(m_bTransactionPending);
#endif

	_AFX_DB_STATE* pDbState = _afxDbState;
	RETCODE nRetCode;
	AFX_SQL_SYNC(::SQLTransact(pDbState->m_henvAllConnections, m_hdbc, SQL_ROLLBACK));
	BOOL bSuccess = Check(nRetCode);

	// Turn back on auto commit
	AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc, SQL_AUTOCOMMIT,
		SQL_AUTOCOMMIT_ON));
	DEBUG_ONLY(m_bTransactionPending = FALSE);

	return bSuccess;
}

// Screen for errors.
BOOL CDatabase::Check(RETCODE nRetCode) const
{
	return CheckHstmt(nRetCode, SQL_NULL_HSTMT);
}

BOOL CDatabase::CheckHstmt(RETCODE nRetCode, HSTMT hstmt) const
{
	ASSERT_VALID(this);
	UNUSED(hstmt);

	switch (nRetCode)
	{
	case SQL_SUCCESS_WITH_INFO:
#ifdef _DEBUG
		if (afxTraceFlags & traceDatabase)
		{
			CDBException e(nRetCode);
			TRACE0("Warning: ODBC Success With Info, ");
			e.BuildErrorString((CDatabase*)this, hstmt);
		}
#endif // _DEBUG

		// Fall through

	case SQL_SUCCESS:
	case SQL_NO_DATA_FOUND:
		return TRUE;
	}

	return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
// CDatabase internal functions

//Replace brackets in SQL string with SQL_IDENTIFIER_QUOTE_CHAR
void CDatabase::ReplaceBrackets(LPTSTR lpchSQL)
{
	BOOL bInLiteral = FALSE;
	LPTSTR lpchNewSQL = lpchSQL;

	while (*lpchSQL != '\0')
	{
		if (*lpchSQL == _afxLiteralSeparator)
			{
				// Handle escaped literal
				if (*_tcsinc(lpchSQL) == _afxLiteralSeparator)
				{
					*lpchNewSQL = *lpchSQL;
					lpchSQL = _tcsinc(lpchSQL);
					lpchNewSQL = _tcsinc(lpchNewSQL);
				}
				else
					bInLiteral = !bInLiteral;

				*lpchNewSQL = *lpchSQL;
			}
		else if (!bInLiteral && (*lpchSQL == '['))
		{
			if (*_tcsinc(lpchSQL) == '[')
			{
				// Handle escaped left bracket by inserting one '['
				*lpchNewSQL = *lpchSQL;
				lpchSQL = _tcsinc(lpchSQL);
			}
			else
				*lpchNewSQL = m_chIDQuoteChar;
		}
		else if (!bInLiteral && (*lpchSQL == ']'))
		{
			if (*_tcsinc(lpchSQL) == ']')
			{
				// Handle escaped right bracket by inserting one ']'
				*lpchNewSQL = *lpchSQL;
				lpchSQL = _tcsinc(lpchSQL);
			}
			else
				*lpchNewSQL = m_chIDQuoteChar;
		}
		else
			*lpchNewSQL = *lpchSQL;

		lpchSQL = _tcsinc(lpchSQL);
		lpchNewSQL = _tcsinc(lpchNewSQL);
	}
}

// Allocate an henv (first time called) and hdbc
void CDatabase::AllocConnect(DWORD dwOptions)
{
	ASSERT_VALID(this);

	if (m_hdbc != SQL_NULL_HDBC)
		return;

	_AFX_DB_STATE* pDbState = _afxDbState;

	RETCODE nRetCode;

	AfxLockGlobals(CRIT_ODBC);
	if (pDbState->m_henvAllConnections == SQL_NULL_HENV)
	{
		ASSERT(pDbState->m_nAllocatedConnections == 0);

		// need to allocate an environment for first connection
		AFX_SQL_SYNC(::SQLAllocEnv(&pDbState->m_henvAllConnections));
		if (!Check(nRetCode))
		{
			AfxUnlockGlobals(CRIT_ODBC);
			AfxThrowMemoryException();  // fatal
		}
	}

	ASSERT(pDbState->m_henvAllConnections != SQL_NULL_HENV);
	AFX_SQL_SYNC(::SQLAllocConnect(pDbState->m_henvAllConnections, &m_hdbc));
	if (!Check(nRetCode))
	{
		AfxUnlockGlobals(CRIT_ODBC);
		ThrowDBException(nRetCode); // fatal
	}
	pDbState->m_nAllocatedConnections++;    // allocated at least
	AfxUnlockGlobals(CRIT_ODBC);

#ifdef _DEBUG
	if (bTraceSql)
	{
		::SQLSetConnectOption(m_hdbc, SQL_OPT_TRACEFILE,
			(DWORD)"odbccall.txt");
		::SQLSetConnectOption(m_hdbc, SQL_OPT_TRACE, 1);
	}
#endif // _DEBUG

	AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT,
		m_dwLoginTimeout));
#ifdef _DEBUG
	if (nRetCode != SQL_SUCCESS && nRetCode != SQL_SUCCESS_WITH_INFO &&
		(afxTraceFlags & traceDatabase))
		TRACE0("Warning: Failure setting login timeout.\n");
#endif

	if (!m_bUpdatable)
	{
		AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
			SQL_MODE_READ_ONLY));
#ifdef _DEBUG
		if (nRetCode != SQL_SUCCESS && nRetCode != SQL_SUCCESS_WITH_INFO &&
			(afxTraceFlags & traceDatabase))
			TRACE0("Warning: Failure setting read only access mode.\n");
#endif
	}

	// Turn on cursor lib support
	if (dwOptions & useCursorLib)
	{
		AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc,
			SQL_ODBC_CURSORS, SQL_CUR_USE_ODBC));
		// With cursor library added records immediately in result set
		m_bIncRecordCountOnAdd = TRUE;
	}
}

BOOL CDatabase::Connect(DWORD dwOptions)
{
	USES_CONVERSION;

	HWND hWndTop;
	HWND hWnd = CWnd::GetSafeOwner_(NULL, &hWndTop);
	if (hWnd == NULL)
		hWnd = ::GetDesktopWindow();

	UCHAR szConnectOutput[MAX_CONNECT_LEN];
	RETCODE nRetCode;
	SWORD nResult;
	UWORD wConnectOption = SQL_DRIVER_COMPLETE;
	if (dwOptions & noOdbcDialog)
		wConnectOption = SQL_DRIVER_NOPROMPT;
	else if (dwOptions & forceOdbcDialog)
		wConnectOption = SQL_DRIVER_PROMPT;
	AFX_SQL_SYNC(::SQLDriverConnect(m_hdbc, hWnd,
		(UCHAR*)T2A((LPTSTR)(LPCTSTR)m_strConnect), SQL_NTS,
		szConnectOutput, _countof(szConnectOutput),
		&nResult, wConnectOption));
	if (hWndTop != NULL)
		::EnableWindow(hWndTop, TRUE);

	// If user hit 'Cancel'
	if (nRetCode == SQL_NO_DATA_FOUND)
	{
		Free();
		return FALSE;
	}

	if (!Check(nRetCode))
	{
#ifdef _DEBUG
		if (hWnd == NULL)
			TRACE0("Error: No default window (AfxGetApp()->m_pMainWnd) for SQLDriverConnect.\n");
#endif
		ThrowDBException(nRetCode);
	}

	// Connect strings must have "ODBC;"
	m_strConnect = _afxODBCTrail;
	// Save connect string returned from ODBC
	m_strConnect += (char*)szConnectOutput;

	return TRUE;
}

void CDatabase::VerifyConnect()
{
	RETCODE nRetCode;
	SWORD nResult;

	SWORD nAPIConformance;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_ODBC_API_CONFORMANCE,
		&nAPIConformance, sizeof(nAPIConformance), &nResult));
	if (!Check(nRetCode))
		ThrowDBException(nRetCode);

	if (nAPIConformance < SQL_OAC_LEVEL1)
		ThrowDBException(AFX_SQL_ERROR_API_CONFORMANCE);

	SWORD nSQLConformance;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_ODBC_SQL_CONFORMANCE,
		&nSQLConformance, sizeof(nSQLConformance), &nResult));
	if (!Check(nRetCode))
		ThrowDBException(nRetCode);

	if (nSQLConformance < SQL_OSC_MINIMUM)
		ThrowDBException(AFX_SQL_ERROR_SQL_CONFORMANCE);
}

void CDatabase::GetConnectInfo()
{
	RETCODE nRetCode;
	SWORD nResult;

	// Reset the database update options
	m_dwUpdateOptions = 0;

	// Check for SQLSetPos support
	UDWORD dwDriverPosOperations;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_POS_OPERATIONS,
		&dwDriverPosOperations, sizeof(dwDriverPosOperations), &nResult));
	if (Check(nRetCode) &&
		(dwDriverPosOperations & SQL_POS_UPDATE) &&
		(dwDriverPosOperations & SQL_POS_DELETE) &&
		(dwDriverPosOperations & SQL_POS_ADD))
		m_dwUpdateOptions |= AFX_SQL_SETPOSUPDATES;

	// Check for positioned update SQL support
	UDWORD dwPositionedStatements;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_POSITIONED_STATEMENTS,
		&dwPositionedStatements, sizeof(dwPositionedStatements),
		&nResult));
	if (Check(nRetCode) &&
		(dwPositionedStatements & SQL_PS_POSITIONED_DELETE) &&
		(dwPositionedStatements & SQL_PS_POSITIONED_UPDATE))
		m_dwUpdateOptions |= AFX_SQL_POSITIONEDSQL;

	// Check for transaction support
	SWORD nTxnCapable;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &nTxnCapable,
		sizeof(nTxnCapable), &nResult));
	if (Check(nRetCode) && nTxnCapable != SQL_TC_NONE)
		m_bTransactions = TRUE;

	// Cache the effect of transactions on cursors
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_CURSOR_COMMIT_BEHAVIOR,
		&m_nCursorCommitBehavior, sizeof(m_nCursorCommitBehavior),
		&nResult));
	if (!Check(nRetCode))
		m_nCursorCommitBehavior = SQL_ERROR;

	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR,
		&m_nCursorRollbackBehavior, sizeof(m_nCursorRollbackBehavior),
		&nResult));
	if (!Check(nRetCode))
		m_nCursorRollbackBehavior = SQL_ERROR;

	// Cache bookmark attributes
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_BOOKMARK_PERSISTENCE,
		&m_dwBookmarkAttributes, sizeof(m_dwBookmarkAttributes),
		&nResult));
	Check(nRetCode);

	// Check for SQLGetData support req'd by RFX_LongBinary
	UDWORD dwGetDataExtensions;
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_GETDATA_EXTENSIONS,
		&dwGetDataExtensions, sizeof(dwGetDataExtensions),
		&nResult));
	if (!Check(nRetCode))
		dwGetDataExtensions = 0;
	if (dwGetDataExtensions & SQL_GD_BOUND)
		m_dwUpdateOptions |= AFX_SQL_GDBOUND;

	if (m_bUpdatable)
	{
		// Make sure data source is Updatable
		char szReadOnly[10];
		AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_DATA_SOURCE_READ_ONLY,
			szReadOnly, _countof(szReadOnly), &nResult));
		if (Check(nRetCode) && nResult == 1)
			m_bUpdatable = !(lstrcmpA(szReadOnly, "Y") == 0);
		else
			m_bUpdatable = FALSE;
#ifdef _DEBUG
		if (!m_bUpdatable && (afxTraceFlags & traceDatabase))
			TRACE0("Warning: data source is readonly.\n");
#endif
	}
	else
	{
		// Make data source is !Updatable
		AFX_SQL_SYNC(::SQLSetConnectOption(m_hdbc,
			SQL_ACCESS_MODE, SQL_MODE_READ_ONLY));
	}

	// Cache the quote char to use when constructing SQL
	char szIDQuoteChar[2];
	AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
		szIDQuoteChar, _countof(szIDQuoteChar), &nResult));
	if (Check(nRetCode) && nResult == 1)
		m_chIDQuoteChar = szIDQuoteChar[0];
	else
		m_chIDQuoteChar = ' ';

#ifdef _DEBUG
	if (afxTraceFlags & traceDatabase)
	{
		char szInfo[64];
		AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_DBMS_NAME,
			szInfo, _countof(szInfo), &nResult));
		if (Check(nRetCode))
		{
			CString strInfo = szInfo;
			TRACE1("DBMS: %s\n", strInfo);
			AFX_SQL_SYNC(::SQLGetInfo(m_hdbc, SQL_DBMS_VER,
				szInfo, _countof(szInfo), &nResult));
			if (Check(nRetCode))
			{
				strInfo = szInfo;
				TRACE1(", Version: %s\n", strInfo);
			}
		}
	}
#endif // _DEBUG
}

void CDatabase::BindParameters(HSTMT /* hstmt */)
{
	// Must override and call SQLBindParameter directly
}

//////////////////////////////////////////////////////////////////////////////
// CDatabase diagnostics

#ifdef _DEBUG
void CDatabase::AssertValid() const
{
	CObject::AssertValid();
}

void CDatabase::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);

	dc << "m_hdbc = " << m_hdbc;
	dc << "\nm_strConnect = " << m_strConnect;
	dc << "\nm_bUpdatable = " << m_bUpdatable;
	dc << "\nm_bTransactions = " << m_bTransactions;
	dc << "\nm_bTransactionPending = " << m_bTransactionPending;
	dc << "\nm_dwLoginTimeout = " << m_dwLoginTimeout;
	dc << "\nm_dwQueryTimeout = " << m_dwQueryTimeout;

	if (dc.GetDepth() > 0)
	{
		_AFX_DB_STATE* pDbState = _afxDbState;
		dc << "\nwith env:";
		dc << "\n\tnAllocated = " << pDbState->m_nAllocatedConnections;
		dc << "\n\thenvAllConnections = " << pDbState->m_henvAllConnections;
	}

	dc << "\n";
}

#endif // _DEBUG


//////////////////////////////////////////////////////////////////////////////
// CRecordset helpers

void AFXAPI AfxSetCurrentRecord(long* plCurrentRecord, long nRows, RETCODE nRetCode);
void AFXAPI AfxSetRecordCount(long* plRecordCount, long lCurrentRecord,
	BOOL bEOFSeen, RETCODE nRetCode);

//////////////////////////////////////////////////////////////////////////////
// CRecordset

CRecordset::CRecordset(CDatabase* pDatabase)
{
	ASSERT(pDatabase == NULL || AfxIsValidAddress(pDatabase, sizeof(CDatabase)));
	m_pDatabase = pDatabase;

	m_nOpenType = snapshot;
	m_lOpen = AFX_RECORDSET_STATUS_UNKNOWN;
	m_nEditMode = noMode;
	m_nDefaultType = snapshot;
	m_dwOptions = none;

	m_bAppendable = FALSE;
	m_bUpdatable = FALSE;
	m_bScrollable = FALSE;
	m_bRecordsetDb = FALSE;
	m_bRebindParams = FALSE;
	m_bLongBinaryColumns = FALSE;
	m_nLockMode = optimistic;
	m_dwInitialGetDataLen = 0;
	m_rgODBCFieldInfos = NULL;
	m_rgFieldInfos = NULL;
	m_rgRowStatus = NULL;
	m_dwRowsetSize = 25;
	m_dwAllocatedRowsetSize = 0;

	m_nFields = 0;
	m_nParams = 0;
	m_nFieldsBound = 0;
	m_lCurrentRecord = AFX_CURRENT_RECORD_UNDEFINED;
	m_lRecordCount = 0;
	m_bUseUpdateSQL = FALSE;
	m_bUseODBCCursorLib = FALSE;
	m_nResultCols = -1;
	m_bCheckCacheForDirtyFields = TRUE;

	m_pbFieldFlags = NULL;
	m_pbParamFlags = NULL;
	m_plParamLength = NULL;
	m_pvFieldProxy = NULL;
	m_pvParamProxy = NULL;
	m_nProxyFields = 0;
	m_nProxyParams = 0;

	m_hstmtUpdate = SQL_NULL_HSTMT;
	m_hstmt = SQL_NULL_HSTMT;
	if (m_pDatabase != NULL && m_pDatabase->IsOpen())
	{
		ASSERT_VALID(m_pDatabase);
		TRY
		{
			RETCODE nRetCode;
			AFX_SQL_SYNC(::SQLAllocStmt(m_pDatabase->m_hdbc, &m_hstmt));
			if (!Check(nRetCode))
				ThrowDBException(SQL_INVALID_HANDLE);

			// Add to list of CRecordsets with alloced hstmts
			AfxLockGlobals(CRIT_ODBC);
			TRY
			{
				m_pDatabase->m_listRecordsets.AddHead(this);
			}
			CATCH_ALL(e)
			{
				AfxUnlockGlobals(CRIT_ODBC);
				THROW_LAST();
			}
			END_CATCH_ALL
			AfxUnlockGlobals(CRIT_ODBC);
		}
		CATCH_ALL(e)
		{
			ASSERT(m_hstmt == SQL_NULL_HSTMT);
			DELETE_EXCEPTION(e);
		}
		END_CATCH_ALL
	}
}

CRecordset::~CRecordset()
{
	ASSERT_VALID(this);

	TRY
	{
		if (m_hstmt != NULL)
		{
#ifdef _DEBUG
			if (m_dwOptions & useMultiRowFetch && afxTraceFlags & traceDatabase)
			{
				TRACE0("\nWARNING: Close called implicitly from destructor.");
				TRACE0("\nUse of multi row fetch requires explicit call");
				TRACE0("\nto Close or memory leaks will result.\n");
			}
#endif
			Close();
		}
		if (m_bRecordsetDb)
			delete m_pDatabase;
		m_pDatabase = NULL;
	}
	CATCH_ALL(e)
	{
		// Nothing we can do
		TRACE0("Error: Exception ignored in ~CRecordset().\n");
		DELETE_EXCEPTION(e);
	}
	END_CATCH_ALL
}

BOOL CRecordset::Open(UINT nOpenType, LPCTSTR lpszSQL, DWORD dwOptions)
{
	ASSERT(!IsOpen());
	ASSERT_VALID(this);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -